UI Style Guide · Introduction

Kosmograd (aka Project Moon) is a real-time survival colony sim set on the lunar surface. You manage three colonists — keeping them fed, oxygenated, and alive — while a quest chain gates new systems and escalates threats. The win condition: assemble all three Signal Components to complete the Comms Center.

The UI reflects the world: a Soviet-era space programme aesthetic — utilitarian, worn, purposeful. Panels borrow the structured information density of XCOM's squad management while staying calm enough for a game about quiet survival rather than action. Every design decision returns to two principles: legible at a glance and thematically honest to the setting. Dark backgrounds, muted regolith tones, and ARC Cyan highlights keep the interface feeling like cold vacuum glass over mission-critical readouts.

This design system is split across three sections: Foundations covers colour tokens, typography scale, and spacing rules; Components documents individual widgets and controls; Panel Examples (below) collects full rendered examples of every in-game panel.

UI Style Guide · Panel Examples

Example — Bottom Tab Bar

Centered pill bar anchored to the bottom of the game viewport. Two toggle buttons: Build (crank icon) and Colonists (user icon). Active tab = ARC Cyan --interactive (#4AC1F2), matching the tab component system. Inactive = Gray #999. Clicking an active tab again deselects it and hides the panel. Click the buttons below to interact.

game viewport
Build
Refiner
80 Al
🔋
Battery
60 Al
🏠
Hab
50 Al
Colonists
👤
Boris
Working · Refiner Alpha
● Active
👤
Katya
Sleeping · Hab Module
● Sleeping
👤
Chen
Idle
● Idle

Anatomy

PropertyValueNotes
Bar background#151618 @ 95%Slightly transparent to sit on game world without fully obscuring it
Bar border#474747 1pxSubtle separation from game world. Radius 4px.
Button size80–90 px wide × 32 px tallBuild 80px, Colonists 90px. Both min-width, content-driven.
Active color--interactive (#4AC1F2)Applied to both text and icon simultaneously. Matches tab component system.
Inactive color#999999 (Gray)Clear enough to read, dim enough to recede
Toggle behaviorClick active tab = deselectHides panel. Player gets unobstructed view of game world.
Themepanel_button_primary.tresConsistent with all other in-panel actions
Icon size14 px max-widthLeft-aligned within button. 5px gap to label.
Panels attach to the bar, not the viewport. The panel that opens floats directly above the tab bar, with its bottom edge flush against the top of the bar. It is not a modal — the game world remains interactive behind it. Panel corners are rounded at the top only (top-left + top-right), meeting flush with the flat top edge of the tab bar.

Example — Pause Menu

Modal context: full-attention, single-column, uniform button height. All pause menu buttons use btn-md (40 px). Primary action (Resume) gets visual priority through the primary colour variant only — never through size. A taller Resume button would look like a layout error, not intentional hierarchy.

GAME PAUSED
Annotations
Title: 14px · PIXEARG_ FIX → Onest 16px
All buttons: btn-md · 40 px tall · full width. Uniform height — hierarchy via colour only.
Secondary: btn-md btn-secondary · Slate bg, Cream text.
Danger: btn-md btn-danger · below divider · never mixed with other actions.
Panel padding: 20 px · Section gap: 12 px

Example — Settings Panel

Settings is a sub-panel inside the pause overlay — same panel chrome as the pause menu, narrower content. Controls are grouped into labelled sections (Display, Audio). Toggles use arc-cyan when on; sliders share the same cyan accent. All rows are equal-height with a hairline separator. Buttons live below a divider, secondary weight only — Back is the primary escape action here, never a primary-coloured button.

SETTINGS
Fullscreen
Run game in fullscreen mode
Fog of War
Hide unexplored terrain
Master Volume
80%
Music
50%
SFX
30%
Annotations
Title: 16px Onest-Bold · --cream · centered.
Section labels: 9px Onest-Bold · --dust-shadow · uppercase · 0.1em tracking. Groups related controls without adding heavy visual weight.
Row separator: rgba(white, 0.05) hairline. Barely-there — structure without contrast noise.
Toggle ON state: --arc-cyan thumb, low-opacity cyan pill bg. OFF: slate pill, dust-shadow thumb. Never use checkboxes in-game.
Volume sliders: cyan thumb + value readout in --arc-cyan monospace. Label left, live % right — no separate label rows.
Both buttons are btn-md btn-secondary. Back is not a primary button — returning to the pause menu is low-stakes.

Example — Building Details Panel

Compact in-game panel showing a damaged building. Demonstrates full-width panel_button_primary.tres (repair action), btn-xs secondary controls, status visualization, and hierarchical information density. Information is primary; buttons are compact affordances.

Thermal Reactor
Power generation · Level 3
Hull breach detected
Efficiency −45%
Status
Operator
Dr. Chen
Output
● 45% capacity
Power draw
18 kW
Structural integrity 52%
Thermal load 78%
Key patterns
Panel-primary button (repair): Full-width panel_button_primary.tres, slate + magenta accent. Used for primary building action — repair, assign, build upgrade.
Alert banner above actions. Only shown when urgent (damage, missing resources). Uses red + icon for instant scanning.
Inset card with mini progress bars. Information density kept high — 4px bars, 9px labels. No extra padding.
btn-xs trio (Pause, Settings, Demolish) on own row. Compact secondary controls — they don't compete with the primary repair action.
Section label "Status" (9px, uppercase) groups related data. Soviet-functional: everything scannable in ~500ms.
Only critical values (integrity: red, thermal: cyan) use accent colours. Everything else is dust shadow to reduce noise.

Button decision tree for this panel

Repair action: panel_button_primary.tres (full-width, dark slate with magenta hover) — high-value action, deserves visual weight but never primary color (which is for menus). Communicates "this is what you came here to do" while staying practical for dense UI.

Pause / Settings / Demolish: btn-xs trio — information sharing space, buttons must be secondary. Pause and Settings use btn-secondary (neutral), Demolish is btn-danger (red). Never full-width — info is the focal point, not actions.

Never use: button_big.tres (main menu only) or button_primary.tres (pause menu only). Never use btn-lg / btn-md inside a detail panel. Screen real estate is premium.

Example — Hab Module Panel

A building panel that contains a resident list. The primary action (Assign Resident) is a centered full-width flat button. All per-row controls use btn-icon only. Secondary details (slots count, power, O₂ source) live in a collapsed accordion — players scan the resident list first, then drill in only if needed.

Hab Module
No oxygen source — sleeping disabled
Yuri
Assigned
Katya
Assigned
Boris
Assigned
Details
Slots
3 / 4 filled
Power
8 kW
O₂ source
Oxygen Generator
Annotations
O₂ warning sits between header and Assign — urgency before action.
"Assign Resident" = centered flat tinted button, not a styled CTA. Visible but not dominant.
Unselected rows: no background or border. Just spacing (4px padding). Clean list.
Selected row: #4AC1F2 @ 12% bg, name in #BFE8FF. No border needed.
× = bare icon button, no background. Red colour is the only affordance needed.
Accordion "Details ▼": secondary info (slots, power, O₂). Collapsed by default. Row-label left / value right, 10px text.

Example — Unit Details Panel

Read-mostly colonist overview. Stat labels are ALL CAPS, bars are 4px thin. The value text uses accent colour only when the stat is warning/critical — OK states stay in Dust Shadow to avoid noise. No primary action button.

Normal state
Boris
Engineer
▶ Recovering oxygen
HealthOK
OxygenLow
HungerFed
EnergyOK
Quarters
Hab Module
Sleep
Nightfall (auto)
Work zone
Unassigned
Critical state — alert banner
CRITICAL — REQUIRES ATTENTION
Boris
Engineer
▶ Unconscious
HealthCritical
OxygenCritical
HungerHungry
EnergyTired
Quarters
Hab Module
Work zone
Unassigned
Annotations
Role label: Dust Shadow. ARC Cyan is reserved for interactive elements and active states — not decorative labels. Task line: Dust Shadow with ▶ prefix.
Stat labels: ALL CAPS, 9px, Dust Shadow. Bars: 4px height, full-width.
Value "OK" / "Fed" = Dust Shadow. Only warning/critical states use accent colour.
"Low" = ARC Yellow. "Critical" = ARC Red. Colour alone communicates severity.
Alert banner: full-bleed, above padding zone. First thing seen. No button inside — just status.
This panel has no primary CTA — it's a viewer. Assignment values are cream; unassigned is Dust Shadow.

Example — Dialogue Box

Appears at the bottom of the screen during NPC conversations. Portrait left (pixel art, 80×80 px, r=4 px). Speaker name in ARC Orange at 14 px bold. Body text Cream at 12 px. Continue indicator: Animated bouncing arrow (▼) centered below the text — no label. The animation alone signals interactivity.

Katya
Sun's going down. Power holding? The batteries can't keep up with night-side drain.
Annotations
Speaker name: Onest-Bold 14px, ARC Orange #F28C38.
Dialogue text: Onest-Bold 12px Cream. Line-height 1.65. Can wrap to multiple lines.
Portrait: 80×80 px, r=4 px (inset card rule). image-rendering: pixelated.
Continue arrow: Centered below text in its own row. Bounces 6px up/down, 1s loop. No label — the animation is the affordance.
Panel bg: #1E2023 (slightly lighter than --basalt). Padding: 16px v / 20px h. Arrow + text are overlay, not part of text flow.

Animation

@keyframes dialogue-bounce {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
 
.dialogue-arrow {
  animation: dialogue-bounce 1s ease-in-out infinite;
  font-size: 14px;
  color: var(--dust-shadow);
}
Pokemon-style UX: The arrow alone signals "more to come / press to advance" without needing text. Animation (gentle bounce, 1s loop) draws the eye without screaming. Text tooltip on hover keeps the UI clean until players need it. Total visual weight is minimal — the dialogue text is the primary element.

Example — Mission Log

Interactive mission log. Completed missions collapse to a single row — click to reveal objective and what they unlocked. The active mission stays expanded with its semantic colour and live progress. Upcoming missions hint at what's ahead (name + type) but hide objectives until unlocked; click the next-in-line to surface the prerequisite. Distant missions are obscured entirely. Overall campaign progress shows at the top without spoilers.

Click rows to interact
MISSION LOG
Campaign progress 2 / 10
DONE
1. First Light
DONE
2. Into the Night
ACTIVE
3. Mouths to Feed
SURVIVAL
Produce 30 Food to sustain the colony.
Food produced12 / 30
UNLOCKS  Electronics Fab · Oxygen Outpost
Upcoming
4. Unidentified Shipment SUPPLY
5. System Failure EMERGENCY
6. Restore Comms COMMS
7. Lunar Permanence
3 further missions  ···
Annotations
Campaign progress bar (Plasma Purple, 20%) + "2 / 10" count. Gives overall context without spoiling objectives.
Completed: Plasma Purple DONE badge. Title struck-through in Dust Shadow. Collapsed by default — click to expand and see objective + what it unlocked.
Active: semantic colour card (arc-lime for Survival). 14px bold title, dim type label right-aligned, objective 12px Cream, live progress bar.
"Upcoming" label + hairline rule separates active from locked. Next-in-line (4) at 75% opacity — click to reveal the prerequisite message. Further missions fade: 55% → 45% → 35%.
Deep-locked missions 8–10 collapsed to a single "3 further missions ···" row at 25% opacity. No names, no objectives — enough to signal more story exists.

Quick Reference

ContextFontSizeColourRadiusPadding
Main menu titleOrbit-Headers48 pxScanline Cream
Main menu buttonPIXEARG_14–16 pxScanline Cream12 px20 px
Modal panel headerOnest-Bold14–16 pxScanline Cream12 px20 px
Modal button (primary)Onest-Bold16 pxDark on Cream bg12 px12×24 px
Modal button (secondary)Onest-Bold14 pxCream on Slate bg12 px9×20 px
In-game panel headerOnest-Bold16 pxScanline Cream12 px12 px
In-game panel bodyOnest-Bold10–12 pxDust Shadow12 px12 px
Panel action (main action)Onest-Bold10 pxCream on Slate bg · btn-xs btn-secondary4 px3×10 px
Panel action (dismissive)Onest-Bold10 pxDust Shadow · btn-xs btn-ghost4 px3×10 px
Panel action (destructive)Onest-Bold10 pxARC Red tint · btn-xs btn-danger4 px3×10 px
Inset / tech cardOnest-Bold9 pxDust Shadow4 px4×6 px
Inline action (btn-xs)Onest-Bold10 pxCream on Slate bg4 px3×10 px
Icon buttonDust Shadow / Red4 px
TooltipOnest-Bold10 pxDust Shadow4 px12 px
Progress bar4 px hCyan → Red2 px
Dialog speaker nameOnest-Bold14 pxARC Orange #F28C38
Dialog portrait80×80 px4 px
Mission active badgeOnest-Bold9 pxARC Yellow3 px2×6 px
Mission complete badgeOnest-Bold9 pxPlasma Purple #A855F73 px2×6 px
Alert bannerOnest-Bold9 pxARC Red0 (full-width)6×12 px

Remediation Checklist

Confirmed divergences from this guide. Tick off as fixes land.

  • button_danger.tres uses PIXEARG_font
    Replace with Onest-Bold for all in-game destructive actions: save-slot delete, building demolish, quit without saving.
  • Pause menu title uses inline PIXEARG_ font overridefont
    Remove the override. Use Onest-Bold @ 16 px (section header size). File: pause_menu.tscn.
  • card_front.tres corner radius is 6 px — must be 4 pxradius
    card_bgr_panel.tres is 12 px (outer). Change card_front.tres to exactly 4 px (--r-card). 4 px is the only correct value for all inset cards.
  • Building details panel disabled-state colour #BD4A7Bcolour
    Purple/rose, unrelated to palette. Replace with Dust Shadow #8A8A7A @ 50% alpha.
  • Hab residents inline StyleBoxFlat selected-state colourcolour
    Duplicates logic that should be a shared constant. Document the canonical value (#4AC1F2 @ 25% alpha) and extract to a shared theme or constant.
  • Font size overrides scattered as raw integers in .gd filesfont
    Audit all raw font_size assignments. Every value must match one of: 9, 10, 12, 14, or 16 px.
  • Dialog speaker name uses Color(1, 0.71, 0.318)colour
    Golden orange hardcoded value. Map to ARC Orange #F28C38 from the palette.