ee5439285cb02fcf3453e4c8b82afd92e696a243
7 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ee5439285c |
M6.1: Character creation wizard foundation (.tscn + Resource-based draft)
Pivots from M5's code-built UI to the editor-authorable .tscn pattern
recommended in GODOT_PORTING_GUIDE.md, after a session of fighting
Godot idioms with code-only layout. Default theme only; the parchment
Theme lands last per the guide's §12 build order so layout bugs surface
as layout bugs, not theming bugs.
GODOT_PORTING_GUIDE.md:
Authored by Claude Design as the canonical port reference. Maps the
React prototype's structure onto Godot 4.6 with concrete code sketches
and a build-order recommendation. Drove the M6 architecture.
Fonts/:
Cormorant Garamond (Medium + MediumItalic) and Crimson Pro (Regular +
Italic + SemiBold) under OFL — the React prototype's serif-display
and serif-body families. Not yet wired through CodexTheme.Build()
because theming is deferred; CodexTheme.LoadFontFromFonts already
picks them up automatically when the Theme pass lands.
Scenes/Wizard.tscn + Wizard.cs:
Wizard shell per guide §4: codex-header (title + folio counter) +
Stepper + Page (StepHost + Aside) + NavBar (Back / validation / Next).
All node lookups via unique-name (%) syntax; layout authored as a
scene file you can open in the editor. Step lifecycle drives the
Aside via signal binding. Stepper logic mirrors app.jsx — locked
iff some EARLIER step is unsatisfied; "type not yet implemented"
doesn't lock.
Scenes/Aside.tscn + Aside.cs:
Right-rail summary per guide §10. Single Refresh() rebuild on
CharacterDraft.Changed; cheap enough not to bother with partial
updates. Width 320 (was 380 before the layout overflow fix).
Scenes/Steps/IStep.cs + StepClade.cs:
Per-step Bind(draft) + Validate() contract. StepClade renders the
3-column clade card grid; click commits via CharacterDraft.Patch
which triggers the Resource.Changed signal that Aside and Wizard
both subscribe to.
UI/CharacterDraft.cs:
Resource (not Node) per guide §2.1. Mirrors app.jsx's `state` shape
exactly. Patch(dictionary) emits the inherited Resource.Changed
signal — listeners use `draft.Changed += handler` regardless of
which field changed. CodexContent provides lazy-loaded immutable
content tables (Clades, Species, Classes, Subclasses, Backgrounds).
Main.{cs,tscn}: Node → Control
When Main was a Node, Control children couldn't anchor to a real
parent rect — they sat at (0,0) at intrinsic min size. With wide
step content (3-column 200-px-card grid), the Wizard's min size
pushed the navbar beyond the viewport's right edge, hiding the Next
button on smaller windowed viewports. Making Main a full-rect-
anchored Control gives child scenes a proper rect to lay out in.
UI/Widgets/CodexStepper.cs:
Anchored the inner vbox to fill the button rect. Without this, the
vbox sat at the button's top-left at intrinsic size and labels
rendered in the corner — visible as the active-step label being
off-center from the highlight bar.
Verified at 1152x720 windowed and (separately) at fullscreen:
- 3-column card grid fits inside Wrap margins + Aside without
horizontal overflow
- Stepper labels centered under their highlight bars
- Next button visible after clade selection; future steps switch
to "coming soon" placeholder when clicked
- Aside summary fills in CLADE block on selection
Closes M6.1. Next per guide §12 build order: M6.2 — StepStats with
drag-drop (highest-risk piece, de-risk before easy steps).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
953bb985ad |
M5: Codex design system (dark theme) + kitchen-sink
Programmatic Theme builder + reusable popover and stepper widgets, ported from CharacterCreator.zip's :root design tokens. Kitchen-sink scene exercises every primitive for visual eyeballing. CodexPalette.cs: Color tokens lifted verbatim from the React prototype's `:root` block (--bg, --ink, --gild, --seal, etc.). Variable names mirror the CSS so the audit trail stays readable. Spacing locked at the prototype's normal density (--gap=24, --pad=28, --radius=2). Scope cut: only the Dark theme ships. The React prototype designed Parchment, Dark, and Blood as switchable variations — user direction during M5 is that only Dark (leather + candlelight) is wanted for this game. Parchment/Blood code dropped, plan doc updated to match (§1 goal #5, §4.5 UI map, §5 M5 scope, §10 resolved decisions #4). No runtime theme switcher. CodexTheme.Build(): Programmatically constructs a Godot Theme from CodexPalette.Dark plus CodexSpacing/CodexType tokens. Configures Panel, Card, CodexPopover styleboxes; Label variations for H1..H4, CodexTitle, Eyebrow, Meta, ValidationOk/Error, CardName/Body/Meta, StepperNum/ Name; Button + PrimaryButton + GhostButton variants; LineEdit, CheckBox, scrollbar styling. Fonts: looks for CormorantGaramond / CrimsonPro / JetBrainsMono TTFs in res://Fonts/ (or Content/Fonts/) and graceful-falls-back to Godot defaults if missing. M5 ships with no fonts in repo; user can drop them in later for typography parity with the React prototype. CodexPopover.cs: Hoverable text trigger + floating PanelContainer, mirrors src/trait-hint.jsx. Viewport-clamps horizontally and vertically; flips above the trigger if there's no room below; 80 ms grace period when moving cursor from trigger to popover. Detriment variant uses the seal-coloured stylebox. Future TraitName / SkillChip / BonusPill widgets layer className differences on top. CodexStepper.cs: Roman-numeral horizontal stepper with Pending / Active / Complete / Locked states. Active step gets a 2-px gild underline, Complete shows a ✓ in seal-red, Locked shows ✕ + 0.45 modulate. Emits StepClicked(int) for non-locked rows. M5 is decorative — M6 wires the signal to the character-creation state machine. KitchenSink.cs + Main.cs --codex-test: Verification scene rendering every primitive (header, stepper, buttons, inputs, cards, trait popovers). Clicks log to console. Fonts default to Godot's Noto Sans until res://Fonts/ is populated. Closes M5 of theriapolis-rpg-implementation-plan-godot-port.md. Next: M6 (title + character creation). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
42d66c00c3 |
M4: Tactical render + unified seamless-zoom WorldView
Implements the seamless-zoom contract from CLAUDE.md: one Camera2D
covers both world-map and tactical scales; layers fade in/out at zoom
thresholds; polyline widths and the player marker counter-scale with
zoom so on-screen sizing stays consistent across the full range.
Layers (bottom-up in WorldView):
Biome sprite — 256x256 ImageTexture scaled by WORLD_TILE_PIXELS;
always visible (acts as backdrop past the tactical
streaming radius).
TacticalChunks — TacticalChunkNode children added on chunk-loaded
event; visible only when zoom ≥ 4.
Polylines/Bridge — Line2D children; always visible. Width recomputed
each frame as baseScreenPx / camera.Zoom so the
on-screen stroke is constant (4 px highway, 3 px
post road, 2 px dirt road, 4.5/3/2 for major-river/
river/stream, 4/2 for rail tie/line, 6 for bridge).
Settlements — SettlementDot children; hidden when zoom ≥ 2 (you
are visually "inside" them at tactical scale).
PlayerMarker — Always visible; Scale = 1/zoom keeps it at
PLAYER_MARKER_SCREEN_PX on-screen across all zooms.
TacticalAtlas:
Loads PNGs from Content/Gfx/tactical/{surface,deco}/ via ContentLoader
with name_0.png/name_1.png/... variant probing (silent miss). Falls
back to procedurally-generated solid placeholders matching MonoGame's
TacticalAtlas colour table so missing art doesn't break rendering.
TacticalChunkNode:
One Node2D per cached chunk, positioned at (OriginX, OriginY) in
world-pixel space. _Draw iterates the 64x64 tile grid once and Godot
caches the rasterised CanvasItem; subsequent frames blit instead of
re-issuing 4096 DrawTextureRect calls.
ChunkStreamer integration:
WorldView listens to OnChunkLoaded / OnChunkEvicting and adds /
removes TacticalChunkNode children. Streaming radius is computed
dynamically from the viewport size and camera zoom plus a 2-tile
buffer, so chunk loads always cover the visible viewport with margin.
Chunks only stream when zoom ≥ 4 (tactical is visible).
Main.cs:
--world-map [seed] → WorldView, fit-to-viewport zoom
--tactical [seed] [tx] [ty] → WorldView, zoom 32 at given tile
Both flags converge on the same scene; mouse wheel transitions
seamlessly between modes.
ContentLoader silent miss:
Removed the "Missing texture" PrintErr — atlas variant probing
legitimately tries name_3.png that doesn't exist, and the noise
drowned the console. Genuine asset failures still surface via
AssetTest's count summary.
Deleted (replaced by WorldView):
Theriapolis.Godot/Rendering/WorldMapView.cs
Theriapolis.Godot/Rendering/TacticalView.cs (created earlier in M4,
never committed — superseded before commit).
Closes M4 of theriapolis-rpg-implementation-plan-godot-port.md.
Next: M5 (codex design system).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
a23cf8bd97 |
M3: Asset pipeline — ContentPaths + ContentLoader + asset-test
Formalises Content/ access from the Godot host. Content lives at the repo root (sibling of Theriapolis.Godot/), not duplicated under res://, so the MonoGame branch and headless Tools keep reading from the same single source of truth. ContentPaths.cs: Static ContentRoot/DataDir/GfxDir resolved once via res:// walk-up and cached. Replaces two inline ResolveDataDir copies in SmokeTest and WorldMapView. ContentLoader.cs: LoadGfx(relativePath) -> ImageTexture, cached by relative path. Bypasses the res:// import pipeline because Content/ lives outside the project — fine for static pixel-art assets at native size, and the project default texture filter is already Nearest. Cache is per-process, never evicted (full atlas <1 MB). AssetTest.cs + Main.cs --asset-test flag: Smoke-tests the pipeline. Walks Content/Data and Content/Gfx, reports counts, attempts to load every PNG, prints per-subdir breakdown. Quits with non-zero on any failure. Verified post-refactor (--asset-test): 53 JSON files in Data, 50 PNG files in Gfx (8 tactical/deco + 42 tactical/surface), 50/50 loaded, 0 failures. Verified no regressions: --smoke-test (M1) still produces canonical FNV hashes. --world-map 12345 (M2) still produces 3 rivers / 91 roads / 226 settlements / 0 rails / 0 bridges. Scope note: plan mentioned "tile/NPC/CodexUI atlases — three separate themes". Only tactical/ exists in Content/Gfx today; NPC and CodexUI atlases never landed during MonoGame development. M3 ships what's actually present. ContentLoader.LoadGfx works for any future sub-directories without changes. Closes M3 of theriapolis-rpg-implementation-plan-godot-port.md. Next: M4 (tactical render). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
59784048cd |
M2: World map render in Godot
Renders the full worldgen output as a Godot scene at visual parity with
worldgen-dump's PNG output: biome tiles, rivers/roads/rails as Line2D
polylines, settlements as filled circles. Pan + zoom via Camera2D.
WorldMapView.cs:
- Loads Content/Data via res:// walk-up, runs WorldGenerator.RunAll
- Tile palette built from BiomeDef.ParsedColor() — same source as the
PNG dump, so colours are identical
- Tiles rendered as a 256x256 Image scaled by WORLD_TILE_PIXELS to
cover world-pixel space (matches polyline coord system)
- Polyline draw order mirrors LineFeatureRenderer.cs: roads (smaller
first) -> rivers -> rail tie underlay -> rail line. Bridges as
short Line2Ds; settlements as SettlementDot (Node2D + _Draw circle)
- Line widths in world-pixel space, tuned for visibility at world-map
zoom; M4 will add zoom-aware width scaling for tactical view
- Camera fits the whole world (95% of viewport) on first frame
PanZoomCamera.cs:
- Mouse-wheel zoom centered on cursor (cursor world-point stays fixed)
- Middle/right click + drag to pan
- MinZoom/MaxZoom configurable per-instance
Main.cs:
- --world-map [seed] flag launches the view (default seed 12345)
- Arg parser now reads both GetCmdlineArgs and GetCmdlineUserArgs so
callers don't need to remember the "--" separator
- --smoke-test path and M0 hello-world fallback unchanged
Visual diff against world_seed12345.png (generated by
worldgen-dump --seed 12345) confirmed manually: same biome palette, same
rivers/roads topology, same settlement placement and tier colours.
3 rivers, 91 roads, 226 settlements (138 PoIs), 0 rails (ENABLE_RAIL=false),
0 bridges (this seed has no road/river crossings). All match the PNG.
Settlement dot sizes iterated twice from user feedback — final values
in tile units, scaled to world-pixel space, so they shrink at world-map
zoom and grow toward tactical zoom (the right "scale with the map"
behaviour).
Closes M2 of theriapolis-rpg-implementation-plan-godot-port.md.
Next: M3 (asset pipeline).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
57fe6bf173 |
M1: Headless parity verified between Tools and Godot
Proves Theriapolis.Core works untouched under Godot's csproj — the worldgen
pipeline produces byte-identical output whether invoked from the Tools CLI
or from inside the Godot process. This is the determinism contract surviving
the port.
Architecture test:
CoreNoDependencyTests now forbids Godot.* and GodotSharp in addition to
Microsoft.Xna and MonoGame. Both bans stay in force for the duration of
the port so neither engine can leak into Core.
Determinism oracle:
New worldgen-hash Tools command runs the full pipeline and prints FNV-1a
hashes for every channel (elevation, moisture, temperature, biomes,
settlements, polylines) plus per-stage hashes. Pairs with the Godot
smoke-test for cross-process verification.
Godot-side smoke test:
SmokeTest.cs runs WorldGenerator.RunAll inside the Godot process; Main.cs
fires it on --smoke-test <seed>. Resolves Content/Data via res:// walk-up.
M0 hello-world behaviour preserved when launched without the flag.
Verification (seed 12345):
- dotnet run -- worldgen-hash and Godot --headless --smoke-test agree on
all 6 channels and all 14 per-stage hashes (diff produces zero output)
- 10-run sweeps stable on both sides post-determinism-fix
- dotnet test: 708/708 pass
Closes M1 of theriapolis-rpg-implementation-plan-godot-port.md.
Next: M2 (world map render).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
59e86af7a2 |
M0: Scaffold Theriapolis.Godot project (hello-world)
First milestone of the Godot port. Establishes the new project structure and verifies the toolchain is wired up end-to-end. - Godot.NET.Sdk/4.6.2 targeting net8.0; references Theriapolis.Core - project.godot configured for borderless fullscreen at native resolution (per port plan §10 resolved decisions); F11 toggles to windowed - Main.tscn + Main.cs hello-world; nearest-neighbor texture filtering - icon.svg placeholder (T in gild on dark) - Added to Theriapolis.sln Verification: - dotnet build Theriapolis.Godot.csproj: 0 errors, 0 warnings - dotnet build Theriapolis.sln: 0 errors (6 pre-existing warnings unrelated) - dotnet test: 708/708 pass in 26s (unchanged from master) - Godot 4.6.2 opens project; fullscreen + F11 toggle confirmed visually Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |