Skip to content

Commit 02d8da7

Browse files
committed
fix(slides): accurate Google brand colors, light theme as default
Theme changes: - Add 'light' theme (default): near-black #202124 headers, Google Blue 600 #1A73E8 accent, Arial, white background. Safe cross-platform — no Google-specific fonts required. - Fix 'google' theme to match official Google brand palette: primary: #1A73E8 (Google Blue 600, was #1C549E — wrong) secondary: #34A853 (Google Green, was #198A3D — wrong) surface: #E8F0FE (Blue 50) surfaceAlt:#E6F4EA (Green 50) text: #1F1F1F (gm3-sys-color-on-surface) textMuted: #444746 (gm3-sys-color-on-surface-variant) font: Google Sans (unchanged) - Fix 'dark' theme primary to #0B57D0 (Material 3 gm3-sys-color-primary) - 'light' is now the default when no theme param is provided, giving new users sensible font and color defaults out of the box. Backward compat: existing blueprints with explicit RGB values get theme.text as text color default (was hardcoded black).
1 parent ebb6a10 commit 02d8da7

2 files changed

Lines changed: 43 additions & 42 deletions

File tree

workspace-server/src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -609,10 +609,10 @@ async function main() {
609609
'JSON string of the slide blueprint. Use {"slides":[{"elements":[...]},...]} for multiple slides or {"elements":[...]} for one slide. Will be parsed server-side.',
610610
),
611611
theme: z
612-
.enum(['google', 'minimal', 'dark'])
612+
.enum(['light', 'google', 'dark'])
613613
.optional()
614614
.describe(
615-
'Named colour palette and font defaults. "google" = Google Blue/Green + Google Sans. "minimal" = dark grey + Arial. "dark" = dark background + blue accent + Arial. When set, color aliases ("primary", "surface", etc.) resolve to theme colours and font_family defaults to the theme font.',
615+
'Named colour palette and font defaults. Defaults to "light" when omitted. "light" = clean neutral (near-black headers, Google Blue 600 accent, Arial — works on any machine). "google" = official Google brand palette (Blue #1A73E8, Green #34A853, Google Sans font). "dark" = dark background, blue accent, Arial. Color aliases in style fields ("primary", "primary_text", "secondary", "secondary_text", "surface", "surface_alt", "text", "text_muted", "background") resolve to the active theme. font_family defaults to the theme font; pass "theme" to opt in explicitly.',
616616
),
617617
},
618618
},

workspace-server/src/services/SlidesService.ts

Lines changed: 41 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -32,40 +32,44 @@ interface Theme {
3232
}
3333

3434
const THEMES: Record<string, Theme> = {
35+
// Clean neutral default — works without Google-specific fonts.
36+
// primary = near-black (#202124), secondary = Google Blue 600 (#1A73E8)
37+
light: {
38+
primary: { red: 0.125, green: 0.129, blue: 0.141 }, // #202124
39+
primaryText: { red: 1.000, green: 1.000, blue: 1.000 },
40+
secondary: { red: 0.102, green: 0.451, blue: 0.910 }, // #1A73E8 Google Blue 600
41+
secondaryText: { red: 1.000, green: 1.000, blue: 1.000 },
42+
surface: { red: 0.973, green: 0.976, blue: 0.980 }, // #F8F9FA Google Grey 50
43+
surfaceAlt: { red: 0.914, green: 0.933, blue: 0.965 }, // #E9EEF6
44+
text: { red: 0.125, green: 0.129, blue: 0.141 }, // #202124
45+
textMuted: { red: 0.373, green: 0.388, blue: 0.408 }, // #5F6368 Google Grey 700
46+
background: { red: 1.000, green: 1.000, blue: 1.000 },
47+
fontFamily: 'Arial',
48+
},
49+
// Google brand palette — matches official Google design system.
50+
// Blue #1A73E8, Green #34A853, font Google Sans.
3551
google: {
36-
primary: { red: 0.11, green: 0.33, blue: 0.68 },
37-
primaryText: { red: 1.00, green: 1.00, blue: 1.00 },
38-
secondary: { red: 0.10, green: 0.53, blue: 0.24 },
39-
secondaryText: { red: 1.00, green: 1.00, blue: 1.00 },
40-
surface: { red: 0.86, green: 0.93, blue: 1.00 },
41-
surfaceAlt: { red: 0.84, green: 0.96, blue: 0.87 },
42-
text: { red: 0.15, green: 0.15, blue: 0.15 },
43-
textMuted: { red: 0.50, green: 0.50, blue: 0.50 },
44-
background: { red: 1.00, green: 1.00, blue: 1.00 },
52+
primary: { red: 0.102, green: 0.451, blue: 0.910 }, // #1A73E8 Google Blue 600
53+
primaryText: { red: 1.000, green: 1.000, blue: 1.000 },
54+
secondary: { red: 0.204, green: 0.659, blue: 0.325 }, // #34A853 Google Green
55+
secondaryText: { red: 1.000, green: 1.000, blue: 1.000 },
56+
surface: { red: 0.910, green: 0.941, blue: 0.996 }, // #E8F0FE Blue 50
57+
surfaceAlt: { red: 0.902, green: 0.957, blue: 0.918 }, // #E6F4EA Green 50
58+
text: { red: 0.122, green: 0.122, blue: 0.122 }, // #1F1F1F
59+
textMuted: { red: 0.267, green: 0.278, blue: 0.275 }, // #444746
60+
background: { red: 1.000, green: 1.000, blue: 1.000 },
4561
fontFamily: 'Google Sans',
4662
},
47-
minimal: {
48-
primary: { red: 0.13, green: 0.13, blue: 0.13 },
49-
primaryText: { red: 1.00, green: 1.00, blue: 1.00 },
50-
secondary: { red: 0.30, green: 0.30, blue: 0.30 },
51-
secondaryText: { red: 1.00, green: 1.00, blue: 1.00 },
52-
surface: { red: 0.96, green: 0.96, blue: 0.96 },
53-
surfaceAlt: { red: 0.90, green: 0.90, blue: 0.90 },
54-
text: { red: 0.13, green: 0.13, blue: 0.13 },
55-
textMuted: { red: 0.50, green: 0.50, blue: 0.50 },
56-
background: { red: 1.00, green: 1.00, blue: 1.00 },
57-
fontFamily: 'Arial',
58-
},
5963
dark: {
60-
primary: { red: 0.07, green: 0.07, blue: 0.10 },
61-
primaryText: { red: 1.00, green: 1.00, blue: 1.00 },
62-
secondary: { red: 0.20, green: 0.60, blue: 1.00 },
63-
secondaryText: { red: 1.00, green: 1.00, blue: 1.00 },
64-
surface: { red: 0.12, green: 0.12, blue: 0.16 },
65-
surfaceAlt: { red: 0.18, green: 0.18, blue: 0.22 },
66-
text: { red: 0.90, green: 0.90, blue: 0.90 },
67-
textMuted: { red: 0.55, green: 0.55, blue: 0.60 },
68-
background: { red: 0.07, green: 0.07, blue: 0.10 },
64+
primary: { red: 0.043, green: 0.341, blue: 0.816 }, // #0B57D0 Material 3 primary
65+
primaryText: { red: 1.000, green: 1.000, blue: 1.000 },
66+
secondary: { red: 0.255, green: 0.671, blue: 0.996 }, // #41ABF9
67+
secondaryText: { red: 0.071, green: 0.071, blue: 0.098 },
68+
surface: { red: 0.118, green: 0.118, blue: 0.157 }, // #1E1E28
69+
surfaceAlt: { red: 0.176, green: 0.176, blue: 0.220 }, // #2D2D38
70+
text: { red: 0.898, green: 0.898, blue: 0.898 }, // #E5E5E5
71+
textMuted: { red: 0.553, green: 0.557, blue: 0.588 }, // #8D8E96
72+
background: { red: 0.071, green: 0.071, blue: 0.098 }, // #121219
6973
fontFamily: 'Arial',
7074
},
7175
};
@@ -86,10 +90,9 @@ const COLOR_ALIASES: Record<string, keyof Theme> = {
8690
* Resolve a color value: pass-through RGB objects, resolve string aliases via theme.
8791
* Returns undefined if alias unknown or no theme active.
8892
*/
89-
function resolveColor(color: ColorValue | undefined, theme: Theme | null): RGB | undefined {
93+
function resolveColor(color: ColorValue | undefined, theme: Theme): RGB | undefined {
9094
if (!color) return undefined;
9195
if (typeof color !== 'string') return color as RGB;
92-
if (!theme) return undefined;
9396
const key = COLOR_ALIASES[color.toLowerCase()];
9497
return key ? (theme[key] as RGB) : undefined;
9598
}
@@ -480,7 +483,7 @@ export class SlidesService {
480483
};
481484
}>,
482485
objCounter: { value: number },
483-
theme: Theme | null = null,
486+
theme: Theme,
484487
): slides_v1.Schema$Request[] {
485488
const requests: slides_v1.Schema$Request[] = [];
486489

@@ -645,13 +648,12 @@ export class SlidesService {
645648
italic: style.italic ?? false,
646649
foregroundColor: {
647650
opaqueColor: {
648-
rgbColor: resolveColor(style.color, theme) ??
649-
theme?.text ?? { red: 0, green: 0, blue: 0 },
651+
rgbColor: resolveColor(style.color, theme) ?? theme.text,
650652
},
651653
},
652654
fontFamily: style.font_family === 'theme'
653-
? (theme?.fontFamily ?? 'Arial')
654-
: (style.font_family ?? theme?.fontFamily ?? 'Arial'),
655+
? theme.fontFamily
656+
: (style.font_family ?? theme.fontFamily),
655657
underline: style.underline ?? false,
656658
strikethrough: style.strikethrough ?? false,
657659
},
@@ -775,9 +777,8 @@ export class SlidesService {
775777
? JSON.parse(rawSlideJson)
776778
: rawSlideJson;
777779

778-
const theme: Theme | null = themeName
779-
? (THEMES[themeName.toLowerCase()] ?? null)
780-
: null;
780+
// Default to 'light' when no theme specified
781+
const theme: Theme = THEMES[(themeName ?? 'light').toLowerCase()] ?? THEMES['light'];
781782

782783
// Normalize: accept either slides[] or top-level elements[] (backward compat)
783784
const slideDefs = (slideJson as any).slides

0 commit comments

Comments
 (0)