# client/scripts/theme/theme_showcase.gd extends Control ## The eyeball proof for the shared Theme (spec §7). Builds every token, stylebox, ## font, surface, and bar on one scrollable screen. No AI, no state. §2: presentation. const Palette = preload("res://scripts/theme/palette.gd") const ThemeKeys = preload("res://scripts/theme/theme_keys.gd") const GAME_THEME := "res://assets/theme/game_theme.tres" const SERIF_ITALIC := "res://assets/theme/fonts/EBGaramond-Italic-VariableFont_wght.ttf" func _ready() -> void: theme = load(GAME_THEME) set_anchors_preset(Control.PRESET_FULL_RECT) var scroll := ScrollContainer.new() scroll.set_anchors_preset(Control.PRESET_FULL_RECT) add_child(scroll) var col := VBoxContainer.new() col.custom_minimum_size = Vector2(1900, 0) col.add_theme_constant_override("separation", 16) scroll.add_child(col) col.add_child(_heading("SHARED THEME — SHOWCASE")) col.add_child(_swatches()) col.add_child(_variations()) col.add_child(_fonts()) col.add_child(_prose()) col.add_child(_rarity()) col.add_child(_bars()) col.add_child(_surfaces()) func _heading(text: String) -> Label: var l := Label.new() l.text = text l.theme_type_variation = ThemeKeys.HEADING return l func _swatches() -> Control: var grid := GridContainer.new() grid.columns = 8 var tokens := [ ["STAGE_1", Palette.STAGE_1], ["BAY_STRIPE_A", Palette.BAY_STRIPE_A], ["DARK_PANEL_70", Palette.DARK_PANEL_70], ["SHEET_TOP", Palette.SHEET_TOP], ["PARCHMENT_CARD", Palette.PARCHMENT_CARD], ["BLOOD", Palette.BLOOD], ["GOLD", Palette.GOLD], ["STEEL", Palette.STEEL], ["GREEN", Palette.GREEN], ["INK_BODY", Palette.INK_BODY], ["CREAM", Palette.CREAM], ] for entry in tokens: var col := VBoxContainer.new() var r := ColorRect.new() r.color = entry[1] r.custom_minimum_size = Vector2(120, 60) col.add_child(r) var caption := Label.new() caption.text = entry[0] caption.theme_type_variation = ThemeKeys.MONO col.add_child(caption) grid.add_child(col) return grid func _variations() -> Control: var row := HBoxContainer.new() row.add_theme_constant_override("separation", 12) var cta := Button.new(); cta.text = "ENTER THE WORLD"; cta.theme_type_variation = ThemeKeys.PRIMARY_CTA var tab := Button.new(); tab.text = "INACTIVE"; tab.theme_type_variation = ThemeKeys.TAB var tab_a := Button.new(); tab_a.text = "ACTIVE"; tab_a.theme_type_variation = ThemeKeys.TAB_ACTIVE # Neutral chip (grey) plus the semantic colours a script applies per-use # (spec §5.3): red for aggressive/combat actions, gold for pay/faith. var chip := Button.new(); chip.text = "STEALTH · DEX"; chip.theme_type_variation = ThemeKeys.CHIP var chip_red := _semantic_chip("INTIMIDATE · STR", Palette.BLOOD) var chip_gold := _semantic_chip("PAY ◈40", Palette.GOLD) for b in [cta, tab, tab_a, chip, chip_red, chip_gold]: row.add_child(b) var card := PanelContainer.new(); card.theme_type_variation = ThemeKeys.PARCHMENT_CARD card.custom_minimum_size = Vector2(160, 80) row.add_child(card) # Filled vs empty item tile, side by side for comparison. var tile_filled := PanelContainer.new() tile_filled.theme_type_variation = ThemeKeys.ITEM_TILE tile_filled.custom_minimum_size = Vector2(64, 64) row.add_child(tile_filled) var tile_empty := PanelContainer.new() tile_empty.theme_type_variation = ThemeKeys.ITEM_TILE_EMPTY tile_empty.custom_minimum_size = Vector2(64, 64) row.add_child(tile_empty) var inset := PanelContainer.new() inset.theme_type_variation = ThemeKeys.PARCHMENT_INSET inset.custom_minimum_size = Vector2(160, 80) row.add_child(inset) var dark := PanelContainer.new() dark.theme_type_variation = ThemeKeys.DARK_PANEL dark.custom_minimum_size = Vector2(160, 80) row.add_child(dark) return row func _semantic_chip(text: String, color: Color) -> Button: # Chip base is neutral (ThemeKeys.CHIP); the semantic colour (§5.3) is set # by the consuming script, here via font-colour + border overrides. var chip := Button.new() chip.text = text chip.theme_type_variation = ThemeKeys.CHIP chip.add_theme_color_override("font_color", color) var tinted := StyleBoxFlat.new() tinted.bg_color = Color(color, 0.15) tinted.border_color = color tinted.set_border_width_all(1) tinted.set_corner_radius_all(3) tinted.content_margin_left = 12 tinted.content_margin_right = 12 tinted.content_margin_top = 6 tinted.content_margin_bottom = 6 chip.add_theme_stylebox_override("normal", tinted) return chip func _prose() -> Control: # Narrative italic (spec §6) — the bundled EB Garamond italic face, shown # nowhere else on this screen. RichTextLabel is required for bbcode italics; # a plain Label cannot render [i]. var rtl := RichTextLabel.new() rtl.bbcode_enabled = true rtl.fit_content = true rtl.custom_minimum_size = Vector2(900, 0) rtl.add_theme_font_override("normal_font", load(GAME_THEME).default_font) rtl.add_theme_font_override("italics_font", load(SERIF_ITALIC)) rtl.text = "[i]The chamber is cold. Something waits in the dark.[/i]" return rtl func _fonts() -> Control: # All three bundled font families, at their real Theme sizes, plus the # default serif body face (not otherwise shown elsewhere on this screen). var col := VBoxContainer.new() col.add_theme_constant_override("separation", 6) var body := Label.new() body.text = "The road to the Ashmarch is longer than the maps admit." col.add_child(body) var accent := Label.new() accent.text = "Vexcca of the Ashmarch" accent.theme_type_variation = ThemeKeys.ACCENT col.add_child(accent) var mono := Label.new() mono.text = "STR 14 · INITIATIVE +2 · AC 16" mono.theme_type_variation = ThemeKeys.MONO col.add_child(mono) return col func _rarity() -> Control: var row := HBoxContainer.new() for i in range(5): var tile := PanelContainer.new() tile.theme_type_variation = ThemeKeys.ITEM_TILE tile.custom_minimum_size = Vector2(72, 72) var bar := ColorRect.new() bar.color = Palette.rarity_color(i) bar.custom_minimum_size = Vector2(60, 4) tile.add_child(bar) row.add_child(tile) return row func _bars() -> Control: var row := HBoxContainer.new() for kind in [&"hp", &"mp", &"stamina"]: var pair = Palette.stat_bar(kind) var bar := ColorRect.new() bar.color = pair[0] bar.custom_minimum_size = Vector2(200, 18) row.add_child(bar) return row func _surfaces() -> Control: var row := HBoxContainer.new() row.custom_minimum_size = Vector2(0, 240) for path in ["res://scenes/theme/surfaces/ParchmentPanel.tscn", "res://scenes/theme/surfaces/DarkBay.tscn"]: var s = load(path).instantiate() s.custom_minimum_size = Vector2(600, 220) row.add_child(s) # VignetteOverlay draws a black-with-alpha dim; give it a mid-tone backing # so the dim is visibly rendering rather than reading as empty space. var vignette_slot := Control.new() vignette_slot.custom_minimum_size = Vector2(600, 220) var backing := ColorRect.new() backing.color = Palette.STEEL backing.set_anchors_preset(Control.PRESET_FULL_RECT) vignette_slot.add_child(backing) var vignette = load("res://scenes/theme/surfaces/VignetteOverlay.tscn").instantiate() vignette.set_anchors_preset(Control.PRESET_FULL_RECT) vignette_slot.add_child(vignette) row.add_child(vignette_slot) return row