diff --git a/package.json b/package.json
index b716e7c69224947957730eb69de2c275a8dcab6a..1149d200b8cc16ac649fbb9768ec4d12e17e9cee 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
   "dependencies": {
     "babel-plugin-add-module-exports": "^0.2.1",
     "babel-plugin-lodash": "^3.2.11",
+    "chromatism": "^3.0.0",
     "diff": "^3.0.1",
     "karma-mocha-reporter": "^2.2.1",
     "localforage": "^1.5.0",
diff --git a/src/App.scss b/src/App.scss
index 056a235ef1916e3584ccb0733c554112171e2e98..1119caf27accbcc8857cec42903e82cdb3a13287 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -51,7 +51,7 @@ a {
 button {
   user-select: none;
   color: $fallback--fg;
-  color: var(--fg, $fallback--fg);
+  color: var(--btnText, $fallback--fg);
   background-color: $fallback--btn;
   background-color: var(--btn, $fallback--btn);
   border: none;
@@ -254,7 +254,7 @@ nav {
       mask-position: center;
       mask-size: contain;
       background-color: $fallback--fg;
-      background-color: var(--fg, $fallback--fg);
+      background-color: var(--topBarText, $fallback--fg);
       position: absolute;
       top: 0;
       bottom: 0;
@@ -330,8 +330,9 @@ main-router {
   padding: .6em .6em;
   text-align: left;
   line-height: 28px;
+  color: var(--panelText);
   background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  background-color: var(--panel, $fallback--btn);
   align-items: baseline;
 
   .title {
@@ -387,8 +388,9 @@ main-router {
 
 nav {
   z-index: 1000;
+  color: var(--topBarText);
   background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  background-color: var(--topBar, $fallback--btn);
   color: $fallback--faint;
   color: var(--faint, $fallback--faint);
   box-shadow: 0px 0px 4px rgba(0,0,0,.6);
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index 42c660a3c33dcdcf078873cd3f3c8af24747f539..eebb2cb78f6c0fe7c02d83651129aa7aac7395d1 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -18,6 +18,7 @@
     </transition>
   </div>
   <div class="panel-body">
+<keep-alive>
     <tab-switcher>
       <div :label="$t('settings.general')" >
         <div class="setting-item">
@@ -146,6 +147,7 @@
       </div>
 
     </tab-switcher>
+</keep-alive>
   </div>
 </div>
 </template>
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 95c15b496baf67d63f2296cac856861582ead9da..5f76c038a1dfef0151e4e80e8ad9fcd5a014df8d 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,4 +1,7 @@
-import { rgbstr2hex } from '../../services/color_convert/color_convert.js'
+import { rgb2hex } from '../../services/color_convert/color_convert.js'
+import ColorInput from '../color_input/color_input.vue'
+import OpacityInput from '../opacity_input/opacity_input.vue'
+import StyleSetter from '../../services/style_setter/style_setter.js'
 
 export default {
   data () {
@@ -7,13 +10,23 @@ export default {
       selected: this.$store.state.config.theme,
       invalidThemeImported: false,
       bgColorLocal: '',
+      bgOpacityLocal: 0,
       btnColorLocal: '',
+      btnOpacityLocal: '',
+
       textColorLocal: '',
       linkColorLocal: '',
+
+      panelColorLocal: undefined,
+      panelOpacityLocal: undefined,
+      topBarColorLocal: undefined,
+      topBarOpacityLocal: undefined,
+
       redColorLocal: '',
       blueColorLocal: '',
       greenColorLocal: '',
       orangeColorLocal: '',
+
       btnRadiusLocal: '',
       inputRadiusLocal: '',
       panelRadiusLocal: '',
@@ -33,7 +46,48 @@ export default {
       })
   },
   mounted () {
-    this.normalizeLocalState(this.$store.state.config.colors, this.$store.state.config.radii)
+    this.normalizeLocalState(this.$store.state.config.customTheme)
+  },
+  computed: {
+    currentTheme () {
+      return {
+        colors: {
+          bg: this.bgColorLocal,
+          fg: this.textColorLocal,
+          panel: this.panelColorLocal,
+          topBar: this.topBarColorLocal,
+          btn: this.btnColorLocal,
+          link: this.linkColorLocal,
+          cRed: this.redColorLocal,
+          cBlue: this.blueColorLocal,
+          cGreen: this.greenColorLocal,
+          cOrange: this.orangeColorLocal
+        },
+        radii: {
+          btnRadius: this.btnRadiusLocal,
+          inputRadius: this.inputRadiusLocal,
+          panelRadius: this.panelRadiusLocal,
+          avatarRadius: this.avatarRadiusLocal,
+          avatarAltRadius: this.avatarAltRadiusLocal,
+          tooltipRadius: this.tooltipRadiusLocal,
+          attachmentRadius: this.attachmentRadiusLocal
+        }
+      }
+    },
+    previewRules () {
+      try {
+        const generated = StyleSetter.generatePreset(this.currentTheme.colors)
+        return [generated.colorRules, generated.radiiRules].join(';')
+      } catch (e) {
+        console.error('CATCH')
+        console.error(e)
+        return ''
+      }
+    }
+  },
+  components: {
+    ColorInput,
+    OpacityInput
   },
   methods: {
     exportCurrentTheme () {
@@ -101,57 +155,62 @@ export default {
           b: parseInt(result[3], 16)
         } : null
       }
-      const bgRgb = rgb(this.bgColorLocal)
-      const btnRgb = rgb(this.btnColorLocal)
-      const textRgb = rgb(this.textColorLocal)
-      const linkRgb = rgb(this.linkColorLocal)
-
-      const redRgb = rgb(this.redColorLocal)
-      const blueRgb = rgb(this.blueColorLocal)
-      const greenRgb = rgb(this.greenColorLocal)
-      const orangeRgb = rgb(this.orangeColorLocal)
-
-      if (bgRgb && btnRgb && linkRgb) {
-        this.$store.dispatch('setOption', {
-          name: 'customTheme',
-          value: {
-            fg: btnRgb,
-            bg: bgRgb,
-            text: textRgb,
-            link: linkRgb,
-            cRed: redRgb,
-            cBlue: blueRgb,
-            cGreen: greenRgb,
-            cOrange: orangeRgb,
-            btnRadius: this.btnRadiusLocal,
-            inputRadius: this.inputRadiusLocal,
-            panelRadius: this.panelRadiusLocal,
-            avatarRadius: this.avatarRadiusLocal,
-            avatarAltRadius: this.avatarAltRadiusLocal,
-            tooltipRadius: this.tooltipRadiusLocal,
-            attachmentRadius: this.attachmentRadiusLocal
-          }})
-      }
+
+      this.$store.dispatch('setOption', {
+        name: 'customTheme',
+        value: this.currentTheme
+      })
     },
 
-    normalizeLocalState (colors, radii) {
-      this.bgColorLocal = rgbstr2hex(colors.bg)
-      this.btnColorLocal = rgbstr2hex(colors.btn)
-      this.textColorLocal = rgbstr2hex(colors.fg)
-      this.linkColorLocal = rgbstr2hex(colors.link)
+    normalizeLocalState (input) {
+      const colors = input.colors || input
+      const radii = input.radii || input
+      let i = 0
+      console.log('BENIS')
+      console.log(colors)
+
+      console.log(i++)
+      this.bgColorLocal = rgb2hex(colors.bg)
+      console.log(i++)
+      this.btnColorLocal = rgb2hex(colors.btn)
+      console.log(i++)
+      this.textColorLocal = rgb2hex(colors.text || colors.fg)
+      console.log(i++)
+      this.linkColorLocal = rgb2hex(colors.link)
+      console.log(i++)
+
+      this.panelColorLocal = colors.panel ? rgb2hex(colors.panel) : undefined
+      console.log(i++)
+      this.topBarColorLocal = colors.topBad ? rgb2hex(colors.topBar) : undefined
+      console.log(i++)
 
-      this.redColorLocal = rgbstr2hex(colors.cRed)
-      this.blueColorLocal = rgbstr2hex(colors.cBlue)
-      this.greenColorLocal = rgbstr2hex(colors.cGreen)
-      this.orangeColorLocal = rgbstr2hex(colors.cOrange)
+      this.redColorLocal = rgb2hex(colors.cRed)
+      console.log(i++)
+      console.log('red')
+      console.log(colors.cRed)
+      console.log(this.redColorLocal)
+      this.blueColorLocal = rgb2hex(colors.cBlue)
+      console.log(i++)
+      console.log('blue', this.blueColorLocal, colors.cBlue)
+      this.greenColorLocal = rgb2hex(colors.cGreen)
+      console.log(i++)
+      this.orangeColorLocal = rgb2hex(colors.cOrange)
+      console.log(i++)
 
       this.btnRadiusLocal = radii.btnRadius || 4
+      console.log(i++)
       this.inputRadiusLocal = radii.inputRadius || 4
+      console.log(i++)
       this.panelRadiusLocal = radii.panelRadius || 10
+      console.log(i++)
       this.avatarRadiusLocal = radii.avatarRadius || 5
+      console.log(i++)
       this.avatarAltRadiusLocal = radii.avatarAltRadius || 50
+      console.log(i++)
       this.tooltipRadiusLocal = radii.tooltipRadius || 2
+      console.log(i++)
       this.attachmentRadiusLocal = radii.attachmentRadius || 5
+      console.log(i++)
     }
   },
   watch: {
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 72a338bdb9cc4c3eb2f84cbf3fd43fc5c803d366..339d7c3dbe0b06c874a9dc4089c2c58bb0bc8c98 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -24,80 +24,73 @@
     </div>
   </div>
 
-  <div class="preview-container">
-    <div :style="{
-                 '--btnRadius': btnRadiusLocal + 'px',
-                 '--inputRadius': inputRadiusLocal + 'px',
-                 '--panelRadius': panelRadiusLocal + 'px',
-                 '--avatarRadius': avatarRadiusLocal + 'px',
-                 '--avatarAltRadius': avatarAltRadiusLocal + 'px',
-                 '--tooltipRadius': tooltipRadiusLocal + 'px',
-                 '--attachmentRadius': attachmentRadiusLocal + 'px'
-                 }">
-      <div class="panel dummy">
-        <div class="panel-heading" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Preview</div>
-        <div class="panel-body theme-preview-content" :style="{ 'background-color': bgColorLocal, 'color': textColorLocal }">
-          <div class="avatar" :style="{
-                                      'border-radius': avatarRadiusLocal + 'px'
-                                      }">
-            ( 汀掳 蜏蕱 汀掳)
-          </div>
-          <h4>Content</h4>
-          <br>
-          A bunch of more content and
-          <a :style="{ color: linkColorLocal }">a nice lil' link</a>
-          <i :style="{ color: blueColorLocal }" class="icon-reply"/>
-          <i :style="{ color: greenColorLocal }" class="icon-retweet"/>
-          <i :style="{ color: redColorLocal }" class="icon-cancel"/>
-          <i :style="{ color: orangeColorLocal }" class="icon-star"/>
-          <br>
-          <button class="btn" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Button</button>
+  <div class="preview-container" :style="previewRules">
+    <div class="panel dummy">
+      <div class="panel-heading">Preview</div>
+      <div class="panel-body theme-preview-content">
+        <div class="avatar">
+          ( 汀掳 蜏蕱 汀掳)
         </div>
+        <h4>Content</h4>
+        <br>
+        A bunch of more content and
+        <a style="color: var(--link)">a nice lil' link</a>
+        <i style="color: var(--cBlue)" class="icon-reply"/>
+        <i style="color: var(--cGreen)" class="icon-retweet"/>
+        <i style="color: var(--cRed)" class="icon-cancel"/>
+        <i style="color: var(--cOrange)" class="icon-star"/>
+        <br>
+        <button class="btn">Button</button>
       </div>
     </div>
   </div>
 
   <div class="color-container">
     <p>{{$t('settings.theme_help')}}</p>
-    <div class="color-item">
-      <label for="bgcolor" class="theme-color-lb">{{$t('settings.background')}}</label>
-      <input id="bgcolor" class="theme-color-cl" type="color" v-model="bgColorLocal">
-      <input id="bgcolor-t" class="theme-color-in" type="text" v-model="bgColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="fgcolor" class="theme-color-lb">{{$t('settings.foreground')}}</label>
-      <input id="fgcolor" class="theme-color-cl" type="color" v-model="btnColorLocal">
-      <input id="fgcolor-t" class="theme-color-in" type="text" v-model="btnColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="textcolor" class="theme-color-lb">{{$t('settings.text')}}</label>
-      <input id="textcolor" class="theme-color-cl" type="color" v-model="textColorLocal">
-      <input id="textcolor-t" class="theme-color-in" type="text" v-model="textColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="linkcolor" class="theme-color-lb">{{$t('settings.links')}}</label>
-      <input id="linkcolor" class="theme-color-cl" type="color" v-model="linkColorLocal">
-      <input id="linkcolor-t" class="theme-color-in" type="text" v-model="linkColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="redcolor" class="theme-color-lb">{{$t('settings.cRed')}}</label>
-      <input id="redcolor" class="theme-color-cl" type="color" v-model="redColorLocal">
-      <input id="redcolor-t" class="theme-color-in" type="text" v-model="redColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="bluecolor" class="theme-color-lb">{{$t('settings.cBlue')}}</label>
-      <input id="bluecolor" class="theme-color-cl" type="color" v-model="blueColorLocal">
-      <input id="bluecolor-t" class="theme-color-in" type="text" v-model="blueColorLocal">
+    <h3>Basic colors!!</h3>
+    <div>
+      <div class="color-item">
+        <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/>
+        <OpacityInput name="bgOpacity" v-model="bgOpacityLocal" fallback="1"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="fgColor" v-model="btnColorLocal" :label="$t('settings.foreground')"/>
+        <OpacityInput name="fgOpacity" v-model="btnOpacityLocal" fallback="1"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="textColor" v-model="textColorLocal" :label="$t('settings.text')"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="linkColor" v-model="linkColorLocal" :label="$t('settings.links')"/>
+      </div>
     </div>
-    <div class="color-item">
-      <label for="greencolor" class="theme-color-lb">{{$t('settings.cGreen')}}</label>
-      <input id="greencolor" class="theme-color-cl" type="color" v-model="greenColorLocal">
-      <input id="greencolor-t" class="theme-color-in" type="green" v-model="greenColorLocal">
+
+    <h3>More customs!</h3>
+    <div>
+      <div class="color-item">
+        <ColorInput name="panelColor" v-model="panelColorLocal" :fallback="btnColorLocal" label="Panel header"/>
+        <OpacityInput name="panelOpacity" v-model="panelOpacityLocal" fallback="1"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="topBarColor" v-model="topBarColorLocal" :fallback="btnColorLocal" label="Top bar"/>
+        <OpacityInput name="topBarOpacity" v-model="topBarOpacityLocal" fallback="1"/>
+      </div>
     </div>
-    <div class="color-item">
-      <label for="orangecolor" class="theme-color-lb">{{$t('settings.cOrange')}}</label>
-      <input id="orangecolor" class="theme-color-cl" type="color" v-model="orangeColorLocal">
-      <input id="orangecolor-t" class="theme-color-in" type="text" v-model="orangeColorLocal">
+
+    <h3>Rainbows!!!</h3>
+    <div>
+      <div class="color-item">
+        <ColorInput name="cRedColor" v-model="redColorLocal" :label="$t('settings.cRed')"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="cBlueColor" v-model="blueColorLocal" :label="$t('settings.cBlue')"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="cGreenColor" v-model="greenColorLocal" :label="$t('settings.cGreen')"/>
+      </div>
+      <div class="color-item">
+        <ColorInput name="cOrangeColor" v-model="orangeColorLocal" :label="$t('settings.cOrange')"/>
+      </div>
     </div>
   </div>
 
@@ -161,7 +154,7 @@
 
 .apply-container,
 .radius-container,
-.color-container,
+.color-container > div,
 .presets-container {
   display: flex;
 
@@ -176,7 +169,7 @@
   flex-direction: column;
 }
 
-.color-container {
+.color-container > div{
   flex-wrap: wrap;
   justify-content: space-between;
 }
@@ -214,14 +207,30 @@
 .radius-item,
 .color-item {
   min-width: 20em;
+  margin: 5px 6px 0 0;
   display:flex;
+  flex-direction: column;
   flex: 1 1 0;
-  align-items: baseline;
-  margin: 5px 6px 5px 0;
+
+  &:nth-child(2n+1) {
+    margin-right: 7px;
+
+  }
+
+  .color, .opacity {
+    display:flex;
+    align-items: baseline;
+  }
 
   label {
     color: var(--faint, $fallback--faint);
   }
+  .opacity-control {
+    margin-top: 5px;
+    height: 12px;
+    line-height: 12px;
+    font-size: 12px;
+  }
 }
 
 .radius-item {
@@ -243,44 +252,19 @@
   margin-left: 4px;
 }
 
-.theme-color-in {
-  min-width: 4em;
-}
-
 .theme-radius-in {
   min-width: 1em;
 }
 
-.theme-radius-in,
-.theme-color-in {
+.theme-radius-in {
   max-width: 7em;
   flex: 1;
 }
 
-.theme-radius-lb,
-.theme-color-lb {
-  flex: 2;
-  min-width: 7em;
-}
-
 .theme-radius-lb{
   max-width: 50em;
 }
 
-.theme-color-lb {
-  max-width: 10em;
-}
-
-.theme-color-cl {
-  padding: 1px;
-  max-width: 8em;
-  height: 100%;
-  flex: 0;
-  min-width: 2em;
-  cursor: pointer;
-  max-height: 29px;
-}
-
 .theme-preview-content {
   padding: 20px;
 }
diff --git a/src/lib/persisted_state.js b/src/lib/persisted_state.js
index 006107e207ac7f6d8875b70590406e3dd4e3e0ea..e55b3b79e53f875236d238dab0aa81a833bf52a4 100644
--- a/src/lib/persisted_state.js
+++ b/src/lib/persisted_state.js
@@ -73,6 +73,7 @@ export default function createPersistedState ({
         loaded = true
       } catch (e) {
         console.log("Couldn't load state")
+        console.error(e)
         loaded = true
       }
     })
diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js
index 13dd897975fe19f5eba7572cd37255567c9cc5a3..efb433276b2ec6daad7c073342a114321280e5a3 100644
--- a/src/services/color_convert/color_convert.js
+++ b/src/services/color_convert/color_convert.js
@@ -1,6 +1,10 @@
 import { map } from 'lodash'
 
 const rgb2hex = (r, g, b) => {
+  console.log(r)
+  if (typeof r === 'object') {
+    ({ r, g, b } = r)
+  }
   [r, g, b] = map([r, g, b], (val) => {
     val = Math.ceil(val)
     val = val < 0 ? 0 : val
@@ -27,8 +31,16 @@ const rgbstr2hex = (rgb) => {
   return `#${((Number(rgb[0]) << 16) + (Number(rgb[1]) << 8) + Number(rgb[2])).toString(16)}`
 }
 
+const mixrgb = (a, b) => {
+  return Object.keys(a).reduce((acc, k) => {
+    acc[k] = (a[k] + b[k]) / 2
+    return acc
+  }, {})
+}
+
 export {
   rgb2hex,
   hex2rgb,
+  mixrgb,
   rgbstr2hex
 }
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 493d444eb144a024a27c5bdd307ec9229c64c96e..72782594156e2001abce42fe84f6c1c11e1cec7f 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,5 +1,6 @@
 import { times } from 'lodash'
-import { rgb2hex, hex2rgb } from '../color_convert/color_convert.js'
+import { brightness, invertLightness, convert } from 'chromatism'
+import { rgb2hex, hex2rgb, mixrgb } from '../color_convert/color_convert.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -53,7 +54,23 @@ const setStyle = (href, commit) => {
   cssEl.addEventListener('load', setDynamic)
 }
 
-const setColors = (col, commit) => {
+const rgb2rgba = function (rgba) {
+  return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`
+}
+
+const getTextColor = function (bg, text) {
+  const bgIsLight = convert(bg).hsl.l > 50
+  const textIsLight = convert(text).hsl.l > 50
+
+  if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) {
+    const base = typeof text.a !== 'undefined' ? { a: text.a } : {}
+    return Object.assign(base, invertLightness(text).rgb)
+  }
+  return text
+}
+
+const setColors = (input, commit) => {
+  const { colorRules, radiiRules, col } = generatePreset(input)
   const head = document.head
   const body = document.body
   body.style.display = 'none'
@@ -62,51 +79,83 @@ const setColors = (col, commit) => {
   head.appendChild(styleEl)
   const styleSheet = styleEl.sheet
 
-  const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b)
-  let colors = {}
-  let radii = {}
-
-  const mod = isDark ? -10 : 10
-
-  colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b)                         // background
-  colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg
-  colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b)                         // panels & buttons
-  colors.input = `rgba(${col.fg.r}, ${col.fg.g}, ${col.fg.b}, .5)`
-  colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod)       // borders
-  colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)`
-  colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b)                   // text
-  colors.lightFg = rgb2hex(col.text.r - mod * 5, col.text.g - mod * 5, col.text.b - mod * 5) // strong text
-
-  colors['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2)
-
-  colors.link = rgb2hex(col.link.r, col.link.g, col.link.b)                   // links
-  colors.icon = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons
-
-  colors.cBlue = col.cBlue && rgb2hex(col.cBlue.r, col.cBlue.g, col.cBlue.b)
-  colors.cRed = col.cRed && rgb2hex(col.cRed.r, col.cRed.g, col.cRed.b)
-  colors.cGreen = col.cGreen && rgb2hex(col.cGreen.r, col.cGreen.g, col.cGreen.b)
-  colors.cOrange = col.cOrange && rgb2hex(col.cOrange.r, col.cOrange.g, col.cOrange.b)
-
-  colors.cAlertRed = col.cRed && `rgba(${col.cRed.r}, ${col.cRed.g}, ${col.cRed.b}, .5)`
-
-  radii.btnRadius = col.btnRadius
-  radii.inputRadius = col.inputRadius
-  radii.panelRadius = col.panelRadius
-  radii.avatarRadius = col.avatarRadius
-  radii.avatarAltRadius = col.avatarAltRadius
-  radii.tooltipRadius = col.tooltipRadius
-  radii.attachmentRadius = col.attachmentRadius
-
   styleSheet.toString()
-  styleSheet.insertRule(`body { ${Object.entries(colors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max')
-  styleSheet.insertRule(`body { ${Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';')} }`, 'index-max')
+  styleSheet.insertRule(`body { ${colorRules} }`, 'index-max')
+  styleSheet.insertRule(`body { ${radiiRules} }`, 'index-max')
   body.style.display = 'initial'
 
-  commit('setOption', { name: 'colors', value: colors })
-  commit('setOption', { name: 'radii', value: radii })
+  // commit('setOption', { name: 'colors', value: htmlColors })
+  // commit('setOption', { name: 'radii', value: radii })
   commit('setOption', { name: 'customTheme', value: col })
 }
 
+const generatePreset = (input) => {
+  const radii = input.radii || {
+    btnRadius: input.btnRadius,
+    inputRadius: input.inputRadius,
+    panelRadius: input.panelRadius,
+    avatarRadius: input.avatarRadius,
+    avatarAltRadius: input.avatarAltRadius,
+    tooltipRadius: input.tooltipRadius,
+    attachmentRadius: input.attachmentRadius
+  }
+  const colors = {}
+
+  const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => {
+    if (typeof v === 'object') {
+      acc[k] = v
+    } else {
+      acc[k] = hex2rgb(v)
+    }
+    return acc
+  }, {})
+
+  colors.fg = col.fg || col.text                   // text
+  colors.text = col.fg || col.text                   // text
+  colors.lightFg = col.fg || col.text                   // text
+
+  colors.bg = col.bg                         // background
+  colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg
+  console.log(colors.bg)
+  console.log(colors.lightBg)
+
+  colors.btn = col.btn || { r: 0, g: 0, b: 0 }
+  colors.btnText = getTextColor(colors.btn, colors.text)
+
+  colors.panel = col.panel || col.btn
+  colors.panelText = getTextColor(colors.panel, colors.text)
+
+  colors.topBar = col.topBar || col.btn
+  colors.topBarText = getTextColor(colors.topBar, colors.text)
+
+  colors.input = col.input || Object.assign({ a: 0.5 }, col.btn)
+  colors.border = col.btn       // borders
+  colors.faint = col.faint || Object.assign({ a: 0.5 }, col.text)
+
+  colors.link = col.link                   // links
+  colors.icon = mixrgb(colors.bg, colors.text) // icons
+
+  colors.cBlue = col.cBlue
+  colors.cRed = col.cRed
+  colors.cGreen = col.cGreen
+  colors.cOrange = col.cOrange
+
+  colors.cAlertRed = col.cAlertRed || Object.assign({ a: 0.5 }, col.cRed)
+
+  const htmlColors = Object.entries(colors)
+        .reduce((acc, [k, v]) => {
+          if (!v) return acc
+          acc[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
+          return acc
+        }, {})
+
+  return {
+    colorRules: Object.entries(htmlColors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';'),
+    radiiRules: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';'),
+    col
+  }
+}
+
 const setPreset = (val, commit) => {
   window.fetch('/static/styles.json')
     .then((data) => data.json())
@@ -148,7 +197,8 @@ const setPreset = (val, commit) => {
 const StyleSetter = {
   setStyle,
   setPreset,
-  setColors
+  setColors,
+  generatePreset
 }
 
 export default StyleSetter
diff --git a/yarn.lock b/yarn.lock
index fdad8b498f0d99ea01e38d51b5497988cee99d74..0139c714c258d7258456fdbd835c91e06190616e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1205,6 +1205,10 @@ chokidar@^1.0.0, chokidar@^1.4.1:
   optionalDependencies:
     fsevents "^1.0.0"
 
+chromatism@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12"
+
 chromedriver@^2.21.2:
   version "2.35.0"
   resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.35.0.tgz#c103ba2fb3d1671f666058159f5cbaa816902e4d"