diff --git a/src/client/app/common/scripts/theme.ts b/src/client/app/common/scripts/theme.ts
index a08028ff9a..db1cd7c394 100644
--- a/src/client/app/common/scripts/theme.ts
+++ b/src/client/app/common/scripts/theme.ts
@@ -7,6 +7,7 @@ type Theme = {
 		id: string;
 		name: string;
 		inherit: string;
+		vars: any;
 	};
 } & {
 	[key: string]: string;
@@ -34,6 +35,22 @@ function compile(theme: Theme): { [key: string]: string } {
 		if (code[0] == '@') {
 			return getColor(theme[code.substr(1)]);
 		}
+		if (code[0] == '$') {
+			return getColor(theme.meta.vars[code.substr(1)]);
+		}
+
+		// func
+		if (code[0] == ':') {
+			const parts = code.split('<');
+			const func = parts.shift().substr(1);
+			const arg = parseInt(parts.shift(), 10);
+			const color = getColor(parts.join('<'));
+
+			switch (func) {
+				case 'darken': return color.darken(arg);
+				case 'lighten': return color.lighten(arg);
+			}
+		}
 
 		return tinycolor(code);
 	}
diff --git a/src/client/app/common/views/widgets/broadcast.vue b/src/client/app/common/views/widgets/broadcast.vue
index c471229f15..65e37bfc69 100644
--- a/src/client/app/common/views/widgets/broadcast.vue
+++ b/src/client/app/common/views/widgets/broadcast.vue
@@ -71,9 +71,9 @@ export default define({
 </script>
 
 <style lang="stylus" scoped>
-root(isDark)
+.anltbovirfeutcigvwgmgxipejaeozxi-body
 	padding 10px
-	background isDark ? #253a50 : #f3f9ff
+	background var(--announcementsBg)
 
 	&[data-melt]
 		background transparent
@@ -130,14 +130,14 @@ root(isDark)
 		margin 0
 		font-size 0.95em
 		font-weight normal
-		color isDark ? #539eff : #4078c0
+		color var(--announcementsTitle)
 
 	> p
 		display block
 		z-index 1
 		margin 0
 		font-size 0.7em
-		color isDark ? #fff : #57616f
+		color var(--announcementsText)
 
 		&.fetching
 			text-align center
@@ -150,10 +150,4 @@ root(isDark)
 		> p
 			color #fff
 
-.anltbovirfeutcigvwgmgxipejaeozxi-body[data-darkmode]
-	root(true)
-
-.anltbovirfeutcigvwgmgxipejaeozxi-body:not([data-darkmode])
-	root(false)
-
 </style>
diff --git a/src/client/theme/dark.json b/src/client/theme/dark.json
index 7e0df42365..c4d1fa9d62 100644
--- a/src/client/theme/dark.json
+++ b/src/client/theme/dark.json
@@ -2,17 +2,21 @@
 	"meta": {
 		"id": "9978f7f9-5616-44fd-a704-cc5985efdd63",
 		"name": "Dark",
-		"author": "syuilo"
+		"author": "syuilo",
+		"vars": {
+			"primary": "#fb4e4e",
+			"secondary": "#282C37"
+		}
 	},
-	"primary": "#fb4e4e",
+	"primary": "$primary",
 	"primaryForeground": "#fff",
-	"bg": "#191b22",
+	"bg": ":darken<8<$secondary",
 	"scrollbarTrack": "#282c37",
 	"scrollbarHandle": "#454954",
 	"scrollbarHandleHover": "#535660",
-	"face": "#282c37",
+	"face": "$secondary",
 	"faceText": "#fff",
-	"faceHeader": "#313543",
+	"faceHeader": ":lighten<5<$secondary",
 	"faceHeaderText": "#e3e5e8",
 	"faceDivider": "rgba(0, 0, 0, 0.3)",
 	"faceTextButton": "#9baec8",
@@ -20,7 +24,7 @@
 	"faceTextButtonActive": "#b2c1d5",
 	"faceClearButtonHover": "rgba(0, 0, 0, 0.1)",
 	"faceClearButtonActive": "rgba(0, 0, 0, 0.2)",
-	"popupBg": "#2c303c",
+	"popupBg": ":lighten<5<$secondary",
 	"popupFg": "#d6dce2",
 	"subNoteBg": "rgba(0, 0, 0, 0.18)",
 	"renoteGradient": "#314027",
@@ -54,6 +58,9 @@
 	"calendarWeek": "#43d5dc",
 	"calendarSaturdayOrSunday": "#ff6679",
 	"calendarDay": "#c5ced6",
+	"announcementsBg": "#253a50",
+	"announcementsTitle": "#539eff",
+	"announcementsText": "#fff",
 	"desktopHeaderBg": "#313543",
 	"desktopHeaderFg": "#b8c5ca",
 	"desktopHeaderHoverFg": "#fff",
diff --git a/src/client/theme/halloween.json b/src/client/theme/halloween.json
index 154755fe90..81c773f574 100644
--- a/src/client/theme/halloween.json
+++ b/src/client/theme/halloween.json
@@ -3,18 +3,16 @@
 		"id": "42e4f09b-67d5-498c-af7d-29faa54745b0",
 		"name": "Halloween",
 		"author": "syuilo",
-		"inherit": "9978f7f9-5616-44fd-a704-cc5985efdd63"
+		"inherit": "9978f7f9-5616-44fd-a704-cc5985efdd63",
+		"vars": {
+			"primary": "#d67036",
+			"primaryForeground": "#fff",
+			"secondary": "#1f1d30",
+			"text": "#b1bee3"
+		}
 	},
-	"primary": "#d67036",
-	"primaryForeground": "#fff",
 	"bg": "#1b1a35",
-	"face": "#322e44",
-	"faceHeader": "#36314e",
-	"dateDividerBg": "#26253c",
-	"popupBg": "@face",
-	"popupFg": "#d6dce2",
 	"renoteGradient": "#5d2d1a",
 	"renoteText": "#ff6c00",
-	"reactionPickerButtonHoverBg": "rgba(0, 0, 0, 0.18)",
 	"desktopHeaderBg": "#36314e"
 }
diff --git a/src/client/theme/light.json b/src/client/theme/light.json
index 482276f638..a7037b8e54 100644
--- a/src/client/theme/light.json
+++ b/src/client/theme/light.json
@@ -2,17 +2,21 @@
 	"meta": {
 		"id": "406cfea3-a4e7-486c-9057-30ede1353c3f",
 		"name": "Light",
-		"author": "syuilo"
+		"author": "syuilo",
+		"vars": {
+			"primary": "#fb4e4e",
+			"secondary": "#fff"
+		}
 	},
-	"primary": "#fb4e4e",
+	"primary": "$primary",
 	"primaryForeground": "#fff",
-	"bg": "#f7f7f7",
+	"bg": ":darken<8<$secondary",
 	"scrollbarTrack": "#fff",
 	"scrollbarHandle": "#00000033",
 	"scrollbarHandleHover": "#00000066",
-	"face": "#fff",
+	"face": "$secondary",
 	"faceText": "#444",
-	"faceHeader": "#fff",
+	"faceHeader": ":lighten<5<$secondary",
 	"faceHeaderText": "#888",
 	"faceDivider": "rgba(0, 0, 0, 0.082)",
 	"faceTextButton": "#ccc",
@@ -20,7 +24,7 @@
 	"faceTextButtonActive": "#999",
 	"faceClearButtonHover": "rgba(0, 0, 0, 0.025)",
 	"faceClearButtonActive": "rgba(0, 0, 0, 0.05)",
-	"popupBg": "#fff",
+	"popupBg": ":lighten<5<$secondary",
 	"popupFg": "#586069",
 	"subNoteBg": "rgba(0, 0, 0, 0.01)",
 	"renoteGradient": "#edfde2",
@@ -54,6 +58,9 @@
 	"calendarWeek": "#19a2a9",
 	"calendarSaturdayOrSunday": "#ef95a0",
 	"calendarDay": "#777",
+	"announcementsBg": "#f3f9ff",
+	"announcementsTitle": "#4078c0",
+	"announcementsText": "#57616f",
 	"desktopHeaderBg": "#f7f7f7",
 	"desktopHeaderFg": "#9eaba8",
 	"desktopHeaderHoverFg": "#7b8c88",