ui(menus): 💄 Refactor menu screens with consistent theming, animations, and standardized vocabulary

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
autocommit 2026-06-04 20:30:32 -07:00
parent 416316a2e8
commit 0d5f2ff00b
8 changed files with 45 additions and 39 deletions

View file

@ -28,7 +28,7 @@ func _populate() -> void:
if sections.is_empty():
var missing: Label = Label.new()
missing.text = ThemeVocabulary.lookup("credits_missing")
missing.add_theme_color_override("font_color", Color(0.7, 0.45, 0.2))
missing.add_theme_color_override("font_color", ThemeAssets.color("semantic.warning"))
_content_vbox.add_child(missing)
return
for section_variant: Variant in sections:
@ -169,11 +169,11 @@ func _build_section(section: Dictionary) -> Control:
var heading: Label = Label.new()
heading.text = str(section.get("heading", "")).to_upper()
heading.add_theme_font_size_override("font_size", 16)
heading.add_theme_color_override("font_color", Color(0.85, 0.75, 0.45))
heading.add_theme_color_override("font_color", ThemeAssets.color("text.title"))
box.add_child(heading)
var rule: ColorRect = ColorRect.new()
rule.custom_minimum_size = Vector2(0, 1)
rule.color = Color(0.6, 0.45, 0.12, 0.35)
rule.color = ThemeAssets.color("border.divider")
box.add_child(rule)
var entries: Array = section.get("entries", []) as Array
for entry_variant: Variant in entries:
@ -200,14 +200,14 @@ func _build_entry_row(entry: Dictionary) -> Control:
var lbl: Label = Label.new()
lbl.text = line
lbl.add_theme_font_size_override("font_size", 13)
lbl.add_theme_color_override("font_color", Color(0.85, 0.82, 0.72))
lbl.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
return lbl
var rich: RichTextLabel = RichTextLabel.new()
rich.bbcode_enabled = true
rich.fit_content = true
rich.scroll_active = false
rich.add_theme_font_size_override("normal_font_size", 13)
rich.add_theme_color_override("default_color", Color(0.85, 0.82, 0.72))
rich.add_theme_color_override("default_color", ThemeAssets.color("text.primary"))
# Escape-friendly: `line` is author-controlled JSON / CSV, not BBCode.
rich.text = "%s [color=#9bbfe0][url=%s]%s[/url][/color]" % [line, url, url]
rich.meta_clicked.connect(func(meta: Variant) -> void: OS.shell_open(str(meta)))

View file

@ -114,7 +114,10 @@ func _build_stats_grid(defeated_index: int) -> void:
var bdata: Dictionary = DataLoader.get_building(building_id)
if bdata.get("wonder_type") != null:
wonders += 1
var row_color: Color = Color(0.75, 0.35, 0.35) if is_defeated else Color(0.88, 0.88, 0.88)
var row_color: Color = (
ThemeAssets.color("semantic.negative") if is_defeated
else ThemeAssets.color("text.primary")
)
var prefix: String = "x " if is_defeated else " "
_stats_grid.add_child(_make_cell(prefix + _player_display(p), row_color, true))
_stats_grid.add_child(_make_cell(str(pop), row_color))
@ -130,7 +133,7 @@ func _make_header(text: String, is_name_col: bool = false) -> Label:
var lbl: Label = Label.new()
lbl.text = text
lbl.add_theme_font_size_override("font_size", 13)
lbl.add_theme_color_override("font_color", Color(0.6, 0.55, 0.35))
lbl.add_theme_color_override("font_color", ThemeAssets.color("text.muted"))
if not is_name_col:
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
return lbl

View file

@ -116,16 +116,16 @@ func _populate_hero_strip() -> void:
if stalemate:
_banner_label.text = ThemeVocabulary.lookup("endgame_banner_gameover")
_banner_label.add_theme_color_override("font_color", Color(0.75, 0.75, 0.78))
_banner_label.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
else:
var human_idx: int = _find_human_player_index()
var player_is_winner: bool = _winner_index == human_idx
if player_is_winner:
_banner_label.text = ThemeVocabulary.lookup("endgame_banner_victory")
_banner_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.2))
_banner_label.add_theme_color_override("font_color", ThemeAssets.color("accent.gold"))
else:
_banner_label.text = ThemeVocabulary.lookup("endgame_banner_defeat")
_banner_label.add_theme_color_override("font_color", Color(0.8, 0.3, 0.3))
_banner_label.add_theme_color_override("font_color", ThemeAssets.color("semantic.negative"))
# Append per-reason flavour when the vocabulary key is mapped.
var reason_key: String = "endgame_reason_" + _reason
@ -166,7 +166,8 @@ func _populate_standings() -> void:
var rank_lbl: Label = _make_label(
"#%d" % rank, 16,
Color(0.3, 0.9, 0.4) if rank == 1 else Color(0.7, 0.7, 0.7))
ThemeAssets.color("semantic.positive") if rank == 1
else ThemeAssets.color("text.secondary"))
rank_lbl.custom_minimum_size.x = 50
rank_lbl.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(rank_lbl)
@ -181,20 +182,20 @@ func _populate_standings() -> void:
row.add_child(dot)
var name_lbl: Label = _make_label(
" " + _player_display(player), 15, Color(0.88, 0.88, 0.88))
" " + _player_display(player), 15, ThemeAssets.color("text.primary"))
name_lbl.size_flags_horizontal = Control.SIZE_EXPAND_FILL
name_lbl.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(name_lbl)
var outcome_key: String = "outcome_winner" if idx == _winner_index else "outcome_defeated"
var outcome_lbl: Label = _make_label(
ThemeVocabulary.lookup(outcome_key), 13, Color(0.7, 0.7, 0.5))
ThemeVocabulary.lookup(outcome_key), 13, ThemeAssets.color("text.muted"))
outcome_lbl.custom_minimum_size.x = 90
outcome_lbl.size_flags_vertical = Control.SIZE_SHRINK_CENTER
row.add_child(outcome_lbl)
var score_lbl: Label = _make_label(
"%.1f" % score, 15, Color(0.95, 0.82, 0.3))
"%.1f" % score, 15, ThemeAssets.color("accent.goldResource"))
score_lbl.custom_minimum_size.x = 80
score_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
score_lbl.size_flags_vertical = Control.SIZE_SHRINK_CENTER
@ -262,7 +263,7 @@ func _populate_awards() -> void:
if _awards.is_empty():
_awards_container.add_child(_make_label(
ThemeVocabulary.lookup("endgame_awards_pending"),
13, Color(0.55, 0.55, 0.55)))
13, ThemeAssets.color("text.muted")))
return
for entry: Dictionary in _awards:
@ -278,15 +279,15 @@ func _populate_awards() -> void:
var card: VBoxContainer = VBoxContainer.new()
card.custom_minimum_size = Vector2(120, 80)
var title_lbl: Label = _make_label(award_name, 12, Color(0.85, 0.76, 0.52))
var title_lbl: Label = _make_label(award_name, 12, ThemeAssets.color("text.secondary"))
title_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
card.add_child(title_lbl)
var winner_lbl: Label = _make_label(clan_name, 14, Color(0.95, 0.95, 0.95))
var winner_lbl: Label = _make_label(clan_name, 14, ThemeAssets.color("text.primary"))
winner_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
card.add_child(winner_lbl)
var value_lbl: Label = _make_label("%.0f" % value, 11, Color(0.65, 0.65, 0.65))
var value_lbl: Label = _make_label("%.0f" % value, 11, ThemeAssets.color("text.muted"))
value_lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
card.add_child(value_lbl)
@ -338,7 +339,7 @@ func _populate_timeline() -> void:
var start: int = maxi(0, events.size() - 30)
for i: int in range(start, events.size()):
_timeline_container.add_child(_make_label(events[i], 12, Color(0.65, 0.6, 0.5)))
_timeline_container.add_child(_make_label(events[i], 12, ThemeAssets.color("text.muted")))
# ── Footer wiring ─────────────────────────────────────────────────────────────

View file

@ -276,7 +276,7 @@ func _make_controller_row(slot_idx: int) -> Control:
var label: Label = Label.new()
label.text = "AI Slot %d" % slot_idx
label.add_theme_font_size_override("font_size", 11)
label.add_theme_color_override("font_color", Color(0.75, 0.68, 0.52, 1))
label.add_theme_color_override("font_color", ThemeAssets.color("text.secondary"))
label.custom_minimum_size = Vector2(80, 0)
row.add_child(label)
var picker: OptionButton = OptionButton.new()
@ -354,13 +354,13 @@ func _make_clan_row(slot_idx: int, clan: Dictionary) -> Control:
var header: Label = Label.new()
header.text = ThemeVocabulary.lookup("fmt_ai_slot") % [slot_idx, clan.get("name", "?")]
header.add_theme_font_size_override("font_size", 14)
header.add_theme_color_override("font_color", Color(0.95, 0.82, 0.3, 1))
header.add_theme_color_override("font_color", ThemeAssets.color("accent.goldResource"))
vbox.add_child(header)
var desc: Label = Label.new()
desc.text = str(clan.get("description", ""))
desc.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
desc.add_theme_font_size_override("font_size", 11)
desc.add_theme_color_override("font_color", Color(0.75, 0.68, 0.52, 1))
desc.add_theme_color_override("font_color", ThemeAssets.color("text.secondary"))
vbox.add_child(desc)
vbox.add_child(_build_axes_row(clan.get("strategic_axes", {})))
return panel
@ -375,13 +375,13 @@ func _build_axes_row(axes: Dictionary) -> HBoxContainer:
var label: Label = Label.new()
label.text = ThemeVocabulary.lookup("axis_%s" % key)
label.add_theme_font_size_override("font_size", 10)
label.add_theme_color_override("font_color", Color(0.6, 0.55, 0.42, 1))
label.add_theme_color_override("font_color", ThemeAssets.color("text.muted"))
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
cell.add_child(label)
var value: Label = Label.new()
value.text = str(int(axes.get(key, 0)))
value.add_theme_font_size_override("font_size", 15)
value.add_theme_color_override("font_color", Color(0.9, 0.85, 0.65, 1))
value.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
value.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
cell.add_child(value)
row.add_child(cell)

View file

@ -46,13 +46,13 @@ func _populate_clans() -> void:
var name_label: Label = Label.new()
name_label.text = clan.get("name", clan_id)
name_label.add_theme_font_size_override("font_size", 16)
name_label.add_theme_color_override("font_color", Color(0.95, 0.82, 0.3))
name_label.add_theme_color_override("font_color", ThemeAssets.color("accent.goldResource"))
row.add_child(name_label)
var desc_label: Label = Label.new()
desc_label.text = clan.get("description", "")
desc_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
desc_label.add_theme_font_size_override("font_size", 13)
desc_label.add_theme_color_override("font_color", Color(0.85, 0.8, 0.7))
desc_label.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
row.add_child(desc_label)
_clans_container.add_child(row)

View file

@ -12,10 +12,6 @@ const PersonalityAssignerScript: GDScript = preload(
)
const TICK_DELAY: float = 0.04
const TIP_ROTATE_SEC: float = 3.5
const PLAYER_COLORS: Array[Color] = [
Color(0.85, 0.65, 0.20), Color(0.80, 0.20, 0.20),
Color(0.20, 0.60, 0.80), Color(0.20, 0.75, 0.30),
]
var _tips: Array = []
var _tip_index: int = 0
@ -119,7 +115,10 @@ func _create_players() -> void:
var base: String = "Player %d" % (i + 1)
p.player_name = EnvConfig.get_var("AI_ARENA_P%d_NAME" % (i + 1), base) if arena_mode else base
p.race_id = default_race
p.color = PLAYER_COLORS[i] if i < PLAYER_COLORS.size() else Color(0.5, 0.5, 0.5)
p.color = (
ThemeAssets.get_player_color(i) if ThemeAssets.has_palette_color(i)
else ThemeAssets.color("player.gray")
)
GameState.players.append(p)
PersonalityAssignerScript.assign(p, GameState.game_rng)
# Stamp the controller id onto the Rust simulation state. The

View file

@ -36,7 +36,7 @@ func _populate(ids: Array[String]) -> void:
row.theme_override_constants_separation = 12
var icon: Label = Label.new()
icon.text = ""
icon.add_theme_color_override("font_color", Color(0.95, 0.82, 0.3, 1))
icon.add_theme_color_override("font_color", ThemeAssets.color("accent.goldResource"))
icon.add_theme_font_size_override("font_size", 16)
icon.custom_minimum_size = Vector2(24, 0)
row.add_child(icon)
@ -46,12 +46,12 @@ func _populate(ids: Array[String]) -> void:
var name_label: Label = Label.new()
name_label.text = dec.get("name", id)
name_label.add_theme_font_size_override("font_size", 15)
name_label.add_theme_color_override("font_color", Color(0.92, 0.86, 0.70, 1))
name_label.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
text_col.add_child(name_label)
var desc_label: Label = Label.new()
desc_label.text = dec.get("description", "")
desc_label.add_theme_font_size_override("font_size", 11)
desc_label.add_theme_color_override("font_color", Color(0.68, 0.62, 0.50, 1))
desc_label.add_theme_color_override("font_color", ThemeAssets.color("text.muted"))
desc_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
text_col.add_child(desc_label)
_spoils_list.add_child(row)

View file

@ -42,15 +42,15 @@ func _on_victory_achieved(player_index: int, victory_type: String) -> void:
if stalemate:
_result_label.text = ThemeVocabulary.lookup("stalemate").to_upper()
_result_label.add_theme_color_override("font_color", Color(0.75, 0.75, 0.78))
_result_label.add_theme_color_override("font_color", ThemeAssets.color("text.primary"))
_player_label.text = ThemeVocabulary.lookup("turn_limit_reached")
elif player != null and player.is_human:
_result_label.text = ThemeVocabulary.lookup("victory").to_upper()
_result_label.add_theme_color_override("font_color", Color(1.0, 0.85, 0.2))
_result_label.add_theme_color_override("font_color", ThemeAssets.color("accent.gold"))
_player_label.text = "%s %s" % [_player_display(player), ThemeVocabulary.lookup("wins")]
else:
_result_label.text = ThemeVocabulary.lookup("defeat").to_upper()
_result_label.add_theme_color_override("font_color", Color(0.8, 0.3, 0.3))
_result_label.add_theme_color_override("font_color", ThemeAssets.color("semantic.negative"))
_player_label.text = "%s %s" % [_player_display(player), ThemeVocabulary.lookup("wins")]
_condition_label.text = _victory_banner(victory_type, stalemate)
@ -133,7 +133,10 @@ func _build_stats_grid(winner_index: int) -> void:
var bdata: Dictionary = DataLoader.get_building(building_id)
if bdata.get("wonder_type") != null:
wonders += 1
var row_color: Color = Color(1.0, 0.9, 0.35) if is_winner else Color(0.88, 0.88, 0.88)
var row_color: Color = (
ThemeAssets.color("accent.goldResource") if is_winner
else ThemeAssets.color("text.primary")
)
var prefix: String = "* " if is_winner else " "
_stats_grid.add_child(_make_cell(prefix + _player_display(p), row_color, true))
_stats_grid.add_child(_make_cell(str(pop), row_color))
@ -149,7 +152,7 @@ func _make_header(text: String, is_name_col: bool = false) -> Label:
var lbl: Label = Label.new()
lbl.text = text
lbl.add_theme_font_size_override("font_size", 13)
lbl.add_theme_color_override("font_color", Color(0.6, 0.55, 0.35))
lbl.add_theme_color_override("font_color", ThemeAssets.color("text.muted"))
if not is_name_col:
lbl.horizontal_alignment = HORIZONTAL_ALIGNMENT_RIGHT
return lbl