Schema lock built bottom-up from the Duncarrow specimen (candidate-town.md):
- disposition rungs as bands over the engine integer (code owns numbers)
- town fact = engine reveal-topic (authoring layer over §6, no new runtime)
- MD bible -> build -> JSON; split by role (game vs server), secrecy as lint
- canon home: content/lore (source) -> content/world + content/server (built)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HuHRPE7VfppUJEaoGBEUqZ
Settles the §17 class-name reconcile (charter §8 vs mock callings) in
favor of the gritty callings, and gives every race trait a concrete rule.
Feeds M4 character creation; combat ability kit deferred to M5.
- Resolution model: deterministic value vs DC, LCK selects the borderline
band (§7) — flat mods, no random d20, no advantage.
- 5 saves (LCK owns none); death saves = LCK.
- Races: features only, no stat mods; Nightsight ruling for darkvision.
- 7 callings (charter-7), 2 names [CANON-TBD]; casters=MP, martials=cooldowns.
- Flags two contract migrations for M4: canon-log gains `race`; deserter
origin's allowed_classes migrates to new calling ids.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M3 — Title screen + unified app version. The entry point: editor-first
Title screen (warm shader background, pulsing glow, drifting embers, the
CODE OF CONQUEST logo, keyboard/mouse menu, footer) set as the boot scene;
New Game -> the Main Window shell, Quit exits, rest inert. Suite 146/146.
Plus a single /VERSION source of truth (0.01-alpha): the API reads it at
startup (+ GET /version), the client bakes it into project.godot via
scripts/sync-version and reads it through the Version helper. No runtime
coupling; both sides agree. Adds TitleLogo/TitleKicker theme variations.
The hex-removal correction set _glow.color = Palette.BLOOD (opaque), which
with the 0.5-0.8 modulate pulse read as a near-solid red slab. Restore the
intended low alpha via Color(Palette.BLOOD, 0.22) — RGB still from Palette,
alpha a numeric param (same idiom as the ember ramp). Whole-branch review
catch. Title tests 5/5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Add scripts/sync-version to sync root /VERSION into client/project.godot
- Add Version GDScript helper (reads application/config/version)
- Test coverage: 2 tests for Version.string() and footer()
- Synced config/version="0.01-alpha" to project.godot
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Editor-first Title screen from mock: warm atmosphere (GPUParticles embers,
AnimationPlayer glow, palette-uniform shader bg), logo block, keyboard/mouse
menu (New Game -> shell, Quit works, rest inert), footer. Plus a single
/VERSION source of truth read by both the API (startup + /version) and the
client (synced into project.godot config/version, read via ProjectSettings).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M3-b — Main Window shell (2a): the exploration HUD frame every screen
lives in. Two-panel tabletop split — dark world slot (turn rail, minimap,
slide-in system dock, command bar) + the permanent DM narration book wired
to the proven /dm/narrate loop (prose-only + refire, considering-state,
fallback, fact-harvest). Thin tested ShellState; suite 138/138.
Establishes the editor-first UI-scene convention (ADR 0001): screens are
authored as .tscn node trees, scripts do on-load work only. Theme gained
Button-base DockButton/ParchmentButton + a base RichTextLabel prose style.
Capture the direction change from M3-b: UI screens are authored editor-first
as .tscn node trees (previewable/arrangeable in the Godot editor), scripts do
on-load work only — never build the tree in _ready(). Add ADR 0001, a
"UI scene conventions" how-to in client/docs, a §16 mandate in the charter,
and mark M3-a/M3-b done in the roadmap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wider consumable tiles overflowed the command bar, shoving END TURN under
the dock column. Trim the vitals min-width (230->120) and END TURN
(150->140) and separation so the row fits — END TURN lands cleanly at the
bottom-right, below the dock.
Move the dock handle to the outer (right) side per mock 2a: the menu now
sits left of the handle and slides right off-screen to hide, the handle
staying at the world's right edge. Dock sits flush to that edge.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 62px tiles clipped longer names (Draught, Antidote). Widen to 93px
(~1.5x) — there is room in the command bar — so labels fit while tiles stay
uniform.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The narration RichTextLabel had no theme styling, so it rendered near-white
and was unreadable on parchment. Add a base RichTextLabel style to the theme
(dark INK_BODY serif at 20px, italic face wired) — systemic and previews in
the editor; every parchment prose surface now reads as dark ink. Also clip
the consumable slot labels so a long name ("Antidote") can't stretch its tile
wider than the empty ones — all 8 stay a uniform 62px.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the three shell scenes (SystemDock, NarrationBook, MainWindowShell)
from build-everything-in-_ready() to authored .tscn node trees with the
theme + type-variations set in the editor, so the layout previews and can
be arranged in the Godot editor. Scripts keep only on-load work: @onready
node refs, DM-loop wiring, the dock slide, and binding seed ShellState into
the fixed authored turn-order tokens + consumable slots.
Fixes the dock offset + over-long buttons (now fixed-width DockButtons in a
right-anchored menu). Headless probe: root 1920x1080, world/book split
1180/740, dock at the world's right edge — no collapse. Suite 138/138.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ThemeKeys.PARCHMENT_CARD is a PanelContainer-base variation (only a
`panel` stylebox) — a Button looks up normal/hover/pressed/disabled,
which don't exist there, so a Button styled with it renders unskinned.
Add PARCHMENT_BUTTON, a Button-base variation with those four
styleboxes plus an empty focus box, built from Palette colours only.
Same fix pattern as DOCK_BUTTON for the system dock. Regenerated
game_theme.tres from the builder.
DarkPanel is a PanelContainer-base variation (only a `panel`
stylebox); a Button looks up normal/hover/pressed, which don't exist
on it, so SystemDock's menu buttons rendered as default gray Godot
buttons instead of mock-faithful dark nav buttons.
Add a dedicated Button-base DockButton variation (Palette-only
colours, dock-dark normal/hover/pressed styleboxes), point
system_dock.gd's menu buttons at it, and regenerate the committed
game_theme.tres artifact from the builder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The exploration HUD frame: two-panel tabletop split, DM narration book
wired to the proven /dm/narrate loop (prose-only + refire), thin tested
ShellState for HUD readouts, inert system dock + command bar as faithful
placeholder. Pure-core/thin-shim per the house pattern.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the design/logical canvas at 1920x1080 (charter §16 / mockups) but add a
window-size override so the window opens at 1600x900 and doesn't fill the whole
screen; canvas_items + keep-aspect scales the canvas to fit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two root causes behind the blank F6 run:
1. project.godot had no display/stretch config (README mandates canvas_items
@ 1920x1080). Added [display] window size + stretch mode/aspect — the
project's canvas foundation, needed by every screen.
2. A root Control run directly (F6) is not sized to the viewport by full-rect
anchors — it collapses to (0,0), clipping the ScrollContainer and hiding all
content. Size the root to the viewport explicitly and track size_changed
(dropping the full-rect anchors, which conflict with setting size directly).
Faithful main-scene run now measures root = scroll = viewport = 1920x1080.
Suite 125/125.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
palette.gd / theme_keys.gd already declare `class_name`, so `const Palette =
preload(...)` in every consumer shadowed the global class and emitted 4
editor errors ("has the same name as a global class"). Reference the global
class_names directly. Editor reload now clean; suite 125/125; runtime probe
still builds all 75 showcase nodes with the theme applied.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- build_game_theme.gd: extract build_theme() as a static func returning the
fully-built Theme; _init() is now a thin save+quit wrapper. Enables a test
to build a fresh Theme in memory without running the SceneTree main loop.
- test_theme_resource.gd: add test_committed_tres_matches_builder() — builds
a fresh Theme via the preloaded builder and compares bg_color against the
committed game_theme.tres for PrimaryCTA/normal, ParchmentCard/panel, and
DarkPanel/panel. Catches "palette/builder changed, .tres not regenerated."
- build_game_theme.gd: give Tab, TabActive, and Chip explicit hover/pressed/
focus styleboxes (focus is StyleBoxEmpty to suppress the default ring) so
they no longer fall back to Godot's default gray button on interaction.
Add a disabled stylebox + font_disabled_color to PrimaryCTA for the
unaffordable-CTA state the 2a shell will need.
- theme_keys.gd: add HEADING/ACCENT/MONO font-role consts (kept out of ALL,
which is stylebox-variation-only); build_game_theme.gd and
theme_showcase.gd now reference them instead of raw StringName literals.
- theme_showcase.gd: add an italic DM-voice RichTextLabel (EB Garamond
italic face, spec §6) and two semantic-coloured chips (BLOOD for
aggressive actions, GOLD for pay/faith) alongside the existing neutral
chip, demonstrating the script-applied colouring from spec §5.3.
- dark_bay.gdshader: comment noting the stripe uses FRAGCOORD (screen-space)
while the vignette uses UV (node-local) — intended for full-bleed use.
- surfaces/*.gd: ## comments documenting the accepted deviation from spec
§5.4 (uniforms set at runtime from Palette rather than baked into the
.tscn) — no behavior change.
- Regenerated game_theme.tres via build_game_theme.gd.
Full suite: 125/125 (was 124, +1 drift-guard test).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GFDm1ku9WDUacK2S78m2be
- _surfaces(): add VignetteOverlay.tscn alongside ParchmentPanel/DarkBay,
backed by a Palette.STEEL ColorRect so the dim is visibly rendering.
- _variations(): add ItemTileEmpty (next to filled ItemTile), ParchmentInset,
and DarkPanel stylebox nodes.
- _fonts(): new section rendering default serif body, Accent
(Architects Daughter), and Mono (JetBrains Mono) labels at real sizes.
- _swatches(): wrap each ColorRect in a VBoxContainer with a Mono caption
Label naming its Palette const, per spec's "labelled swatches."
No raw hex / Color(...) literals introduced; all colour via Palette.*, all
styleboxes via ThemeKeys.* variation names.
First of three M3 cycles (Theme -> shell 2a -> Title). Palette.gd consts
as the single source of truth; game_theme.tres for flat-bordered UI;
shaders for the three signature surfaces. EB Garamond replaces
proprietary Georgia. Proof is a human-eyeballed showcase harness.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The aliveness POC (M0-M2) is proven, so redefine the project as the tactical
CRPG the /mockups describe. Charter: §1 reframed (Code of Conquest / The
Margreave), §10 combat = tactical + action-economy but GRIDLESS (tokens are
flavor, no positional rules), §15 = button-driven actions + free-text NPC
dialogue (Adjudicator reshaped to the optional free-text escape hatch), §16
adopts /mockups as the UI/systems bible, §17 rewritten to the game's scope.
Two conflicts flagged not silently decided (§18): damage determinism (§7 vs
mock ranges → M5) and class names (§8 vs mock callings → M4).
Roadmap: M0-M2 kept as the built engine; M3-M9 re-sequenced around the mock
screens (Theme+shell → creation → combat → dialogue → inventory/sheet → world
systems → framing/AI-flavor/persistence). Streaming stays shelved; v2 NPC
ideas preserved, re-homed to M6.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
High-fidelity HTML/CSS/JS design references for the tactical-CRPG direction —
title, character creation, character sheet, inventory, world map, quest log,
shop, pause/settings, dialogue, combat HUD, main exploration window. README is
the handoff spec (visual system, per-screen state models, Godot translation
notes). Not production code — the source of truth for the game's look + systems.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
M2 (prove aliveness) build-complete + live-proven; feel confirmed in playtest.
Active build focus is now M3 (make it a game), starting with the Adjudicator.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Flip considering-state to done+merged+live-confirmed. Strike the streaming
item — the considering-state reframes the wait and is tested/live; real
streaming's transport rework + mid-stream failure surface isn't worth it for
the POC. Streaming spec retained as a record (banner SHELVED). Includes the
human's folded-in further-down roadmap ideas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Considering-state + transport timeout (M2 anti-freeze; streaming parked).
While a model call is in flight the client rotates authored in-character
'the Master considers…' lines (§13); HttpTransport now sets a request timeout
(35s, rejects <=0) so a hung call degrades to the fallback instead of spinning
forever. Human-confirmed working live, including the degrade path (API down →
fallback). 5 tasks, whole-branch review MERGE AS-IS. Rotation tuned to 3.0s.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
By-hand cold-start test showed 3 phrases before the response; 1.5x the
cadence so each line stays on screen a touch longer.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>