# client/scripts/theme/build_game_theme.gd @tool extends SceneTree ## One-shot Theme builder. Run headless: ## godot --headless -s res://scripts/theme/build_game_theme.gd ## Constructs game_theme.tres from Palette + the bundled fonts and saves it. ## The builder is the source of truth; the .tres is a committed artifact. ## ยง2: presentation. const Palette = preload("res://scripts/theme/palette.gd") const ThemeKeys = preload("res://scripts/theme/theme_keys.gd") const OUT := "res://assets/theme/game_theme.tres" const SERIF := "res://assets/theme/fonts/EBGaramond-VariableFont_wght.ttf" const ACCENT := "res://assets/theme/fonts/ArchitectsDaughter-Regular.ttf" const MONO := "res://assets/theme/fonts/JetBrainsMono-VariableFont_wght.ttf" func _init() -> void: var theme := Theme.new() _fonts(theme) _primary_cta(theme) _tabs(theme) _chip(theme) _tiles(theme) _cards_and_panels(theme) var err := ResourceSaver.save(theme, OUT) if err != OK: push_error("theme save failed: %d" % err) else: print("wrote ", OUT) quit() func _flat(bg: Color, border: Color, width := 1, radius := 4) -> StyleBoxFlat: var s := StyleBoxFlat.new() s.bg_color = bg s.border_color = border s.set_border_width_all(width) s.set_corner_radius_all(radius) s.content_margin_left = 12 s.content_margin_right = 12 s.content_margin_top = 6 s.content_margin_bottom = 6 return s func _fonts(theme: Theme) -> void: var serif: FontFile = load(SERIF) # Global defaults: prose serif at body size. theme.default_font = serif theme.default_font_size = 18 # Heading role via the Label "Heading" variation. theme.set_type_variation(&"Heading", "Label") theme.set_font(&"font", &"Heading", serif) theme.set_font_size(&"font_size", &"Heading", 34) theme.set_color(&"font_color", &"Heading", Palette.INK_HEADING) # Accent (hand-inked) role. theme.set_type_variation(&"Accent", "Label") theme.set_font(&"font", &"Accent", load(ACCENT)) theme.set_font_size(&"font_size", &"Accent", 24) theme.set_color(&"font_color", &"Accent", Palette.INK_GOLD) # Mono chrome role. theme.set_type_variation(&"Mono", "Label") theme.set_font(&"font", &"Mono", load(MONO)) theme.set_font_size(&"font_size", &"Mono", 13) theme.set_color(&"font_color", &"Mono", Palette.MUTED_MONO) func _primary_cta(theme: Theme) -> void: var k := ThemeKeys.PRIMARY_CTA theme.set_type_variation(k, "Button") theme.set_stylebox(&"normal", k, _flat(Palette.BLOOD, Palette.BLOOD, 1, 4)) theme.set_stylebox(&"hover", k, _flat(Palette.BLOOD_BRIGHT, Palette.BLOOD, 1, 4)) theme.set_stylebox(&"pressed", k, _flat(Palette.BLOOD_DARK, Palette.BLOOD, 1, 4)) theme.set_color(&"font_color", k, Palette.CREAM_BRIGHT) func _tabs(theme: Theme) -> void: theme.set_type_variation(ThemeKeys.TAB, "Button") theme.set_stylebox(&"normal", ThemeKeys.TAB, _flat(Palette.TAB_INACTIVE_BG, Palette.PARCHMENT_BORDER_2, 1, 14)) theme.set_color(&"font_color", ThemeKeys.TAB, Palette.INK_MUTED) theme.set_type_variation(ThemeKeys.TAB_ACTIVE, "Button") theme.set_stylebox(&"normal", ThemeKeys.TAB_ACTIVE, _flat(Palette.BLOOD, Palette.BLOOD, 1, 14)) theme.set_color(&"font_color", ThemeKeys.TAB_ACTIVE, Palette.CREAM_BRIGHT) func _chip(theme: Theme) -> void: # Base chip; the semantic colour (red/gold/grey) is applied per-use by script. var k := ThemeKeys.CHIP theme.set_type_variation(k, "Button") var s := _flat(Color(Palette.MUTED_MONO, 0.12), Palette.MUTED_MONO, 1, 3) theme.set_stylebox(&"normal", k, s) theme.set_font(&"font", k, load(MONO)) theme.set_font_size(&"font_size", k, 11) theme.set_color(&"font_color", k, Palette.MUTED_MONO) func _tiles(theme: Theme) -> void: var filled := _flat(Palette.PARCHMENT_INSET, Palette.PARCHMENT_BORDER, 2, 6) theme.set_type_variation(ThemeKeys.ITEM_TILE, "PanelContainer") theme.set_stylebox(&"panel", ThemeKeys.ITEM_TILE, filled) var empty := _flat(Palette.PARCHMENT_INSET_2, Palette.PARCHMENT_BORDER_3, 1, 6) empty.draw_center = false theme.set_type_variation(ThemeKeys.ITEM_TILE_EMPTY, "PanelContainer") theme.set_stylebox(&"panel", ThemeKeys.ITEM_TILE_EMPTY, empty) func _cards_and_panels(theme: Theme) -> void: theme.set_type_variation(ThemeKeys.PARCHMENT_CARD, "PanelContainer") theme.set_stylebox(&"panel", ThemeKeys.PARCHMENT_CARD, _flat(Palette.PARCHMENT_CARD, Palette.PARCHMENT_BORDER, 1, 6)) theme.set_type_variation(ThemeKeys.PARCHMENT_INSET, "PanelContainer") theme.set_stylebox(&"panel", ThemeKeys.PARCHMENT_INSET, _flat(Palette.PARCHMENT_INSET, Palette.PARCHMENT_BORDER_3, 1, 4)) theme.set_type_variation(ThemeKeys.DARK_PANEL, "PanelContainer") theme.set_stylebox(&"panel", ThemeKeys.DARK_PANEL, _flat(Palette.DARK_PANEL_70, Palette.BORDER_4, 1, 4))