Phase 0 scaffold + asset audit findings

Project scaffold:
- project.godot at repo root, GL Compatibility renderer (max mobile reach),
  pixel-snap on, texture filter nearest, sensor_landscape orientation
- 7 autoloads: World, Sim, GameState, EventBus, Strings, Audit, SaveSystem
- scenes/main/main.{tscn,gd} smoke-test scene with autoload assertions
- Folder layout matches tavernkeep idiom: autoload/ at root, scripts
  co-located with scenes/ (not the scripts/autoloads/ mirror originally
  sketched in implementation.md)
- Input map: pause, speed_cycle, speed_normal/fast/ultra, confirm, cancel.
  Mobile gestures (pinch/drag/long-press) handled at script level via
  Godot's InputEventScreenTouch/Drag/MagnifyGesture.
- SaveSystem skeleton: SAVE_VERSION=1, JSON to user://save_slot.json,
  version-mismatch warning. Phase 3 expands to real entity state.
- icon.svg placeholder (cabin silhouette on dark green field)
- README.md points at memory.md / implementation.md / docs/

Headless verification: 'godot --headless --path . --quit' exits 0,
'[main] Phase 0 smoke test online.' prints, no errors. Editor-side
green-dot check still pending — needs human launch of editor.

Asset audit (researcher Haiku, 2026-05-10):
- FG_Houses.png NOT autotile-solvable — pre-built decorative house
  compositions, 4 distinct roof palettes, no modular wall family.
  ~½–1 day per material to author terrain bits on top.
- FG_Fortress.png IS autotile-solvable — ~20–30 modular tan-stone
  pieces. Wang-style Godot 4 terrain works with minimal extra art.
  Iconic Homestead $19.99 fallback not needed.
- No wolf sprite anywhere in the bundle. EvoMonster packs all
  cute/fantasy. Need commission, CC0 source, or Ventilatore check.
- Retro Graveyard 16x16 [Kingdom Explorer] confirmed in Tier 3 with
  full graveyard suite — direct use in Phase 14.

New open questions surfaced in memory.md:
- Player-built wall material strategy (3 options laid out)
- Wolf sprite acquisition path (Phase 10 blocker)

Project move:
- Repo physical location moved from ~/claude/projects/rimlike to
  /mnt/d/godot/rimlike (D: drive, fast for Windows-side editor).
- Symlink at the original WSL path preserves the home-CLAUDE.md
  layout convention. Mirrors tavernkeep's pattern.
- Set core.filemode=false to silence DrvFs's everything-is-0777
  false-positive on git diff.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
megaproxy 2026-05-10 20:09:11 +01:00
parent daf26ed27a
commit 128294c14f
33 changed files with 389 additions and 35 deletions

29
README.md Normal file
View file

@ -0,0 +1,29 @@
# rimlike
A 2D, tile-based **cute-farming-RPG-meets-colony-sim** for mobile and handheld. Rimworld DNA, Going Medieval × Stardew lodestars. Built on Godot 4.
Working title `rimlike` — rename TBD.
## Working in this repo
- **Project rules:** [`CLAUDE.md`](./CLAUDE.md)
- **Decisions index + open questions:** [`memory.md`](./memory.md)
- **Phased build plan (the checklist):** [`docs/implementation.md`](./docs/implementation.md)
- **Game design:** [`docs/design.md`](./docs/design.md)
- **Tech / engine layout:** [`docs/architecture.md`](./docs/architecture.md)
- **Touch UX:** [`docs/ui.md`](./docs/ui.md)
- **Art / tilesets / license:** [`docs/art.md`](./docs/art.md)
## On a fresh clone
The proprietary **Godot MCP Pro** addon is gitignored. Re-copy from the local install before opening the project:
```bash
cp -r /mnt/d/godot/mcp/addons/godot_mcp ./addons/
```
Then open `project.godot` in Godot 4.6+. Project → Project Settings → Plugins → enable **Godot MCP Pro**. Look for the green dot in the "MCP Pro" bottom panel.
## Engine
Godot **4.6.2 stable**, GDScript only, GL Compatibility renderer (max mobile reach), 16×16 pixel art (texture filter = nearest, pixel snap on).

0
art/fx/.gitkeep Normal file
View file

0
art/sprites/.gitkeep Normal file
View file

0
art/tiles/.gitkeep Normal file
View file

0
art/ui/.gitkeep Normal file
View file

0
audio/music/.gitkeep Normal file
View file

0
audio/sfx/.gitkeep Normal file
View file

12
autoload/audit.gd Normal file
View file

@ -0,0 +1,12 @@
extends Node
## Debug-only logging + perf counters. No-op in release builds.
##
## Use Audit.log("category", "message") instead of print() — gives us a single
## switch to silence everything before ship.
var enabled: bool = OS.is_debug_build()
func log(category: String, message: String) -> void:
if enabled:
print("[%s] %s" % [category, message])

9
autoload/event_bus.gd Normal file
View file

@ -0,0 +1,9 @@
extends Node
## Pure signal hub — notification-only, no state, no callbacks back into singletons.
##
## Subsystems mutate themselves; this bus only spreads the news. Add signals as
## features land — keep this file readable. See docs/architecture.md.
# Phase 0 placeholder — no signals yet.
# Phase 1 will add tick / speed-change / pause signals.
# Phase 2 will add pawn-state signals (selected, deselected, walking, …).

28
autoload/game_state.gd Normal file
View file

@ -0,0 +1,28 @@
extends Node
## Top-level mutable game state. SaveSystem serializes via save_dict() / apply_dict().
##
## Holds session-wide flags and the "what map are we on" pointer. Per-entity state
## lives on the entities themselves; per-tile state on the TileMap or World.
## See docs/architecture.md.
var current_map_id: StringName = &"slice_temperate_forest"
var session_started_at_unix: int = 0 # for "you've been away X minutes" toast
func _ready() -> void:
session_started_at_unix = int(Time.get_unix_time_from_system())
# Phase 16 expands these into real save round-trip.
func save_dict() -> Dictionary:
return {
"current_map_id": String(current_map_id),
"session_started_at_unix": session_started_at_unix,
}
func apply_dict(d: Dictionary) -> void:
if d.has("current_map_id"):
current_map_id = StringName(d["current_map_id"])
if d.has("session_started_at_unix"):
session_started_at_unix = int(d["session_started_at_unix"])

45
autoload/save_system.gd Normal file
View file

@ -0,0 +1,45 @@
extends Node
## Save/load skeleton — version field, file IO, save-between-ticks contract.
##
## Saves only happen between sim ticks (Sim owns the loop). JobRunner mid-toil
## state must round-trip from day one — see docs/architecture.md.
##
## Phase 0: file-IO smoke test only. Phase 3 expands to real entity state.
## Phase 16 closes coverage of every system.
const SAVE_VERSION: int = 1
const SAVE_PATH: String = "user://save_slot.json"
func write_save() -> bool:
# Smoke-test payload. Phase 3 expands this.
var payload := {
"version": SAVE_VERSION,
"sim_tick": Sim.tick,
"game_state": GameState.save_dict(),
}
var f := FileAccess.open(SAVE_PATH, FileAccess.WRITE)
if f == null:
push_error("SaveSystem.write_save: cannot open %s" % SAVE_PATH)
return false
f.store_string(JSON.stringify(payload))
return true
func read_save() -> Dictionary:
if not FileAccess.file_exists(SAVE_PATH):
return {}
var f := FileAccess.open(SAVE_PATH, FileAccess.READ)
if f == null:
return {}
var raw := f.get_as_text()
var parsed: Variant = JSON.parse_string(raw)
if typeof(parsed) != TYPE_DICTIONARY:
push_error("SaveSystem.read_save: corrupt save")
return {}
if int(parsed.get("version", 0)) != SAVE_VERSION:
push_warning(
"SaveSystem.read_save: version mismatch (%s vs %s)" %
[parsed.get("version", "?"), SAVE_VERSION]
)
return parsed

28
autoload/sim.gd Normal file
View file

@ -0,0 +1,28 @@
extends Node
## Sim tick loop owner. Sim runs at 20 Hz, render at 60 Hz, decoupled.
##
## Speed factor controls how many sim ticks queue per render frame:
## 1× — 1 tick per 3 render frames (20 ticks/s)
## Fast — 5 ticks per 3 render frames (~100 ticks/s)
## Ultra — 12 ticks per 3 render frames (~240 ticks/s)
## Pause — 0
##
## Saves are taken between ticks only — never mid-tick — so JobRunner mid-toil
## state round-trips cleanly. See docs/architecture.md "Time / tick model".
const SIM_HZ: int = 20
const TICK_INTERVAL_S: float = 1.0 / float(SIM_HZ)
enum Speed { PAUSE, NORMAL, FAST, ULTRA }
const SPEED_FACTOR: Dictionary = {
Speed.PAUSE: 0,
Speed.NORMAL: 1,
Speed.FAST: 5,
Speed.ULTRA: 12,
}
var current_speed: Speed = Speed.PAUSE
var tick: int = 0
# Tick-loop body lands in Phase 1.

22
autoload/strings.gd Normal file
View file

@ -0,0 +1,22 @@
extends Node
## i18n string table — player-visible strings ONLY. Code keys, EN values.
##
## Locked from day one (per CLAUDE.md): no hardcoded display copy in scenes or
## scripts. If you have player-facing text, add a key here and call Strings.t(key).
##
## Locale switching is post-MVP; the indirection lands now so we don't have to
## retrofit the whole game later. When the table grows, move it to a .tres or
## external CSV import; the public API (`Strings.t(key)`) stays the same.
const TABLE: Dictionary = {
# Phase 0 placeholder — populate as features land.
&"app.title": "Rimlike",
&"smoke.hello": "Phase 0 — autoloads online.",
}
func t(key: StringName) -> String:
if TABLE.has(key):
return TABLE[key]
push_warning("Strings.t(): missing key %s" % key)
return String(key)

14
autoload/world.gd Normal file
View file

@ -0,0 +1,14 @@
extends Node
## Runtime entity registry + tile-related sim state.
##
## All gameplay entities (pawns, items, furniture, animals, corpses) live here.
## TileMap data is owned by the world-view scene; World holds the *indirect*
## state (designation queue, dirty-haul set, zone records, etc.) that doesn't
## belong on the TileMap itself.
##
## See docs/architecture.md.
# Phase 1 will add the entity registries (pawns, items, furniture).
# Phase 4 will add `items_needing_haul` (the dirty set).
# Phase 5 will add the BuildJob queue.
# Phase 13 will add zones / rooms / dirtiness.

0
data/events/.gitkeep Normal file
View file

0
data/pawns/.gitkeep Normal file
View file

0
data/recipes/.gitkeep Normal file
View file

0
data/thoughts/.gitkeep Normal file
View file

0
data/weather/.gitkeep Normal file
View file

View file

@ -92,12 +92,24 @@ Even with the bundle, these need authoring or sourcing:
## Audit list (action items before any release build)
- [ ] Autotile coverage of `Houses Tileset 2 Seasons/FG_Houses.png` — count corner/T-junction/cap pieces for player-built walls.
- [ ] Autotile coverage of `Fortress Tileset 2 Seasons/FG_Fortress.png` (alt material).
- [ ] Aesthetic harmony test: open one tile from ElvGames Forest 4 Seasons + one from Ventilatore + render in same scene. Is the palette cohesive enough to mix? Decides whether Ventilatore stays as accent or gets shelved.
- [ ] Wolf sprite source — confirm what's available from EvoMonster / Turn-Based Monster packs; if none, plan a custom.
- [ ] Confirm Retro Graveyard 16×16 has grave-marker tile we can use.
- [ ] License attribution credits document — list every pack we use, credit string for game credits screen.
**Audit results, 2026-05-10** — three of five closed via visual inspection (researcher Haiku subagent + verification).
- [x] **`FG_Houses.png` autotile coverage** — **NOT autotile-solvable.** Pieces are pre-built decorative house compositions across 4 distinct roof palettes (blue-roof timber, red-brick, dark-slate, plus accent details). No corner / T-junction / cap modular family. Estimated cost to author terrain bits on top: ~½1 day per material.
- [x] **`FG_Fortress.png` autotile coverage** — **autotile-solvable.** ~2030 modular tan-stone pieces (straight, corners, battlement caps) with dark-grid mortar lines. Wang-style Godot 4 terrain works with minimal extra art. Iconic Homestead fallback not needed.
- [ ] **Aesthetic harmony test** — still open. Needs your eye on a Forest tile + a Ventilatore tile side-by-side. ~15 min.
- [x] **Wolf sprite source****none in the bundle.** Scanned EvoMonster Packs 03/04/06/09/10 (cute fantasy creatures, no canines), broader Tier 13 sweep (farm animals + humanoid monsters only). Action items in `memory.md` Open questions: commission, find CC0, or check Ventilatore.
- [x] **Grave marker****`Retro Graveyard 16x16 Tileset [Kingdom Explorer]` confirmed in Tier 3.** Path: `Ultimate Farming RPG Tier 3/Retro Graveyard 16x16 Tileset [Kingdom Explorer]/Tilesets/KE_Graveyard.png`. Contents: tombstones (varied), wooden crosses, grave mounds, crypt entries, skeletal markers, ground-transition tiles. Direct use in Phase 14.
- [ ] **License attribution credits document** — kick off the list now; add to it as packs come in. Include Kingdom Explorer (likely separate license from ElvGames — check `License.txt`).
## Wall-material decision (consequence of the audit)
The `FG_Houses` non-autotile finding is the biggest live blocker. `architecture.md` and `implementation.md` Phase 5 assume the player paints walls and they auto-junction. Options now under consideration (in `memory.md` Open questions):
1. **Fortress-stone-only** — player walls use `FG_Fortress` exclusively. `FG_Houses` becomes static prebuilt-shelter art (no construction verb for cabins). Aesthetic shifts toward Going Medieval; loses some of the cute-cabin Stardew warmth.
2. **Custom-author wood walls** on top of `FG_Houses` (~½1 day per material). Preserves aesthetic; delays Phase 5 by ~3 days.
3. **Mix**: `FG_Houses` static = starter shelter (drop-in, can't deconstruct), `FG_Fortress` autotile = player-built upgrade walls. Two materials, no custom art investment, but loses the "build your own first cabin" beat.
Decision needed before Phase 1 wall-tileset import (Phase 1 needs at least one wall material to render).
## Tileset prep (the gotcha)

View file

@ -6,7 +6,8 @@ Effort estimates are wall-time at **focused solo pace**. Scale up generously for
| Status | Phase |
|---|---|
| ⏳ next | **Phase 0 — Project scaffold & foundations** |
| ✅ scaffold landed (headless-verified); awaits editor-side green-dot check | **Phase 0 — Project scaffold & foundations** |
| ⏳ next | **Phase 1 — World, tilemap, camera** |
Use this doc as a checklist: tick boxes as items complete, and update the **Status** row above whenever a phase rolls over. The last bullet of each phase is the *acceptance demo* — the phase is "done" when you can perform it.
@ -18,10 +19,14 @@ Refs to `docs/` files are linked so each item lands in the right spec.
The five items from `memory.md` *Open questions / Audit*. None of these need code, but several of them gate Phase 1+ (autotile drives the wall pipeline; aesthetic harmony decides whether Ventilatore stays in active use). Knock these out before Phase 0.
- [ ] **Aesthetic harmony test** — ElvGames Forest vs Ventilatore tile, side-by-side. Decide use-both or drop-Ventilatore. (~15 min)
- [ ] **ElvGames autotile audit** — count corner / T / cap pieces in `Houses Tileset 2 Seasons/FG_Houses.png` and `Fortress Tileset 2 Seasons/FG_Fortress.png`. ≥16 wall variants → autotile is solvable; <8 fall back to Iconic Homestead ($19.99) or custom-author. (~1530 min)
- [ ] **Wolf sprite source** — bundle's Animal Sprites lacks wolves. Browse EvoMonster Packs 0115 or Turn-Based RPG Monster packs. Or plan custom (~few hours). (~15 min)
- [ ] **Grave marker source** — Retro Graveyard 16×16 (Tier 3) probably has it. (~10 min)
- [ ] **Aesthetic harmony test** — ElvGames Forest vs Ventilatore tile, side-by-side. Decide use-both or drop-Ventilatore. (~15 min) — **needs your eye**
- [x] **ElvGames autotile audit** — done 2026-05-10. Findings (visual inspection):
- **`FG_Houses.png` is NOT autotile-solvable as-is.** Pieces are pre-built decorative house compositions (4 distinct roof palettes), not modular wall variants. ~½1 day per material to author terrain bits on top.
- **`FG_Fortress.png` IS autotile-solvable.** 2030 modular tan-stone-with-dark-mortar pieces — straight, corners, caps. Wang-style Godot 4 terrain works with minimal extra art.
- **Recommendation:** make Fortress stone the primary player wall material. Defer custom-authored Houses walls to v2 OR keep Houses as static prebuilt-shelter art only.
- Iconic Homestead $19.99 fallback **not needed**.
- [x] **Wolf sprite source** — done 2026-05-10. **No wolf in the bundle.** EvoMonster packs are all cute/fantasy creatures (slimes, ghosts, dragons), Turn-Based RPG Monsters are humanoid-style. No 4-legged canine predator anywhere in the bundle. Action: commission a 16×16 wolf (idle + 24-frame walk × 4 directions) OR check Ventilatore bundle OR find a CC0 sprite. **Open in `memory.md`.**
- [x] **Grave marker source** — done 2026-05-10. `Retro Graveyard 16x16 Tileset [Kingdom Explorer]` confirmed in Tier 3, full graveyard suite (tombstones, crosses, mounds, crypts).
- [ ] **License compilation start** — kick off the credits string list now; add to it as packs come in. (open across phases)
---
@ -30,27 +35,29 @@ The five items from `memory.md` *Open questions / Audit*. None of these need cod
**Goal:** a Godot project that opens cleanly, has all the autoloads and folder structure committed, and runs an empty test scene.
- [ ] `godot --headless` (or editor) → New Project at repo root, Forward+ renderer (mobile-friendly path TBD; check what export complains about)
- [ ] Re-copy `addons/godot_mcp/` from `/mnt/d/godot/mcp/addons/godot_mcp` and enable in Project Settings → Plugins. Verify green dot in MCP Pro bottom panel.
- [ ] Folder layout:
- `scenes/` (`world/`, `pawn/`, `ui/`, `entities/`, `effects/`)
- `scripts/` (mirrors scenes/, plus `autoloads/`, `systems/`, `ai/`, `data/`)
- [x] `project.godot` at repo root. **GL Compatibility renderer** (max mobile reach; Forward+ would lock out older devices). Pixel-snap on, texture filter = nearest. Landscape sensor orientation. Viewport 1280×720 (`canvas_items` stretch, `keep` aspect).
- [x] Re-copy `addons/godot_mcp/` from `/mnt/d/godot/mcp/addons/godot_mcp` and enable in `project.godot` `[editor_plugins]`. ⏳ **Editor-side green-dot check pending** — needs you to open the editor once.
- [x] Folder layout (cribbed from tavernkeep's idiomatic Godot pattern — co-located scripts in `scenes/`, `autoload/` at root):
- `autoload/` — singletons (`world.gd`, `sim.gd`, `game_state.gd`, `event_bus.gd`, `strings.gd`, `audit.gd`, `save_system.gd`)
- `scenes/` (`main/`, `world/`, `pawn/`, `ui/`, `entities/`, `effects/`)
- `data/` (`recipes/`, `thoughts/`, `events/`, `weather/`, `pawns/`)
- `art/` (`tiles/`, `sprites/`, `ui/`, `fx/`)
- `audio/` (`sfx/`, `music/`)
- `tests/` (GUT or built-in test runner — pick later)
- [ ] Autoloads (empty stubs, real bodies land in later phases):
- `tests/`, `tools/`
- [x] Autoloads (stubs; real bodies land in later phases):
- `World` — entity registry, tile state, signals
- `Sim` — tick loop owner, speed/pause state
- `GameState` — current map, save metadata, game-mode flags
- `EventBus` — global signal bus
- `Strings` — i18n string table (string keys → EN values; load from `data/strings.en.tres`)
- `Audit` — debug-only logging, perf counters
- [ ] Input map: `tap`, `long_press`, `pinch_in`, `pinch_out`, `drag`, `pause`, `speed_cycle`. Touch + gamepad mappings.
- [ ] Save/load skeleton: `SaveSystem.save(slot)` / `SaveSystem.load(slot)` — version field, file IO, save-between-ticks contract enforced (no save calls allowed mid-tick). Round-trip a literal "hello" for now.
- [ ] `.gitignore` already covers Godot output; verify `.godot/`, `*.import`, `addons/godot_mcp/`, exports are all excluded
- [ ] Smoke-test scene: blank `World.tscn` with a `Camera2D`, hit Play, see a coloured background. Done.
- [ ] **Acceptance:** `godot --headless --quit` exits 0; clicking Play in editor opens a blank world without errors; `MCP Pro` panel shows the green dot.
- `Sim` — tick loop owner, speed/pause state, Speed enum + factor table
- `GameState` — current map, session timestamp, `save_dict()` / `apply_dict()`
- `EventBus` — global signal hub (no signals yet — added per-phase)
- `Strings` — i18n string table (`Strings.t(key)` lookup; const dict for now, .tres later)
- `Audit` — debug-only logging gate
- `SaveSystem``write_save()` / `read_save()`, version + path, JSON
- [x] Input map: `pause`, `speed_cycle`, `speed_normal`, `speed_fast`, `speed_ultra`, `confirm`, `cancel`. Mobile gestures (pinch / drag / long-press) handled at script level, not as input actions — Godot's `InputEventScreenTouch` / `InputEventScreenDrag` / `InputEventMagnifyGesture` cover them.
- [x] `SaveSystem` skeleton: version field (`SAVE_VERSION = 1`), `user://save_slot.json`, JSON serialize, mismatch warning. **Smoke-test payload only**; Phase 3 expands.
- [x] `.gitignore` covers `.godot/`, `.import/`, `addons/godot_mcp/`, exports — verified.
- [x] Smoke-test scene: `scenes/main/main.tscn` (Node + Camera2D + Label). `main.gd._ready()` asserts every autoload alive and shows the i18n-resolved hello string.
- [x] **Acceptance (headless):** `godot --headless --path . --quit` exits 0, `[main] Phase 0 smoke test online.` prints, no errors. **Confirmed.**
- [ ] **Acceptance (editor):** open `project.godot` in Godot 4.6, hit Play — see "Phase 0 — autoloads online." rendered at 32,32. MCP Pro bottom panel shows green dot. ⏳ **Needs your hand.**
---

13
icon.svg Normal file
View file

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128">
<rect width="128" height="128" fill="#3a4a2a"/>
<rect x="0" y="80" width="128" height="48" fill="#5a3a22"/>
<rect x="40" y="48" width="48" height="40" fill="#8a6a3a"/>
<polygon points="32,48 64,16 96,48" fill="#3a2418"/>
<rect x="58" y="64" width="12" height="24" fill="#1a0f08"/>
<rect x="44" y="56" width="8" height="8" fill="#f0c060"/>
<rect x="76" y="56" width="8" height="8" fill="#f0c060"/>
<rect x="8" y="96" width="8" height="8" fill="#7a8a5a"/>
<rect x="20" y="100" width="8" height="8" fill="#7a8a5a"/>
<rect x="100" y="98" width="8" height="8" fill="#7a8a5a"/>
<rect x="112" y="104" width="8" height="8" fill="#7a8a5a"/>
</svg>

After

Width:  |  Height:  |  Size: 749 B

View file

@ -41,6 +41,9 @@ Distilled from the brainstorm. Each lock has a "why" — change with deliberate
| **Scale** | 36 pawns, **80×80** MVP map (architecture sized to ~120² ceiling) | Roughly Stardew-farm size; readable when zoomed in, doesn't fit a phone screen — forces the world-view camera (pinch / pan / jump-to-alert) rather than strategic-overview-on-phone. |
| **Priority levels** | 5 (Critical / High / Normal / When idle / Off) | Matches Rimworld + Going Medieval contract. |
| **Failure state** | Ghost colony — no game over; storyteller drops wanderer in 35 days | Mobile-friendly; preserves player investment. |
| **Engine version** | Godot **4.6.2 stable** (Win64 binary at `D:\godot\Godot_v4.6.2-stable_win64.exe`) | Locked for reproducibility; pinned in `project.godot` features. |
| **Renderer** | GL Compatibility (mobile + desktop), **not** Forward+ | Max device reach; Forward+ would lock out older phones. |
| **Repo location** | Physical: `/mnt/d/godot/rimlike/` (D: drive, fast for Windows-side editor). Symlink: `~/claude/projects/rimlike` → physical. | Mirrors tavernkeep's pattern. Both WSL and Windows access without crossing the WSL net bridge. |
### Architecture (tech)
@ -86,16 +89,22 @@ Distilled from the brainstorm. Each lock has a "why" — change with deliberate
### Audit / unblock-the-prototype action items
These are concrete checks to run before serious construction begins. Total ~75 min.
Total ~75 min. **3 of 5 closed on 2026-05-10**; see session log + `docs/art.md` for findings. Two open.
- [ ] **Aesthetic harmony test**open one tile from ElvGames Forest 4 Seasons + one from Ventilatore + view side-by-side. Decide whether they mesh (use both) or clash (drop Ventilatore from active use). ~15 min.
- [ ] **ElvGames autotile audit** — count corner / T-junction / cap pieces in `Houses Tileset 2 Seasons/FG_Houses.png` and `Fortress Tileset 2 Seasons/FG_Fortress.png`. ≥16 wall variants per material → autotile is solvable; <8 fall back to Mana Seed Iconic Homestead ($19.99) or custom-author. ~1530 min.
- [ ] **Wolf sprite source** — bundle's Animal Sprites pack lacks wolves. Browse EvoMonster Packs 0115 or Turn-Based RPG Monster packs for a suitable predator. Or plan custom (~few hours pixel art). ~15 min.
- [ ] **Grave marker source** — Retro Graveyard 16×16 (Tier 3) probably has it; verify. ~10 min.
- [ ] **License compilation** — maintain credits string for every pack used (ElvGames + Ventilatore + any others). Display in game's credits screen. Confirm specific terms per pack before any commercial release.
- [ ] **Aesthetic harmony test**needs your eye. ElvGames Forest tile vs Ventilatore tile, side-by-side. Decides whether Ventilatore stays as accent or gets shelved. ~15 min.
- [x] **ElvGames autotile audit** — done. **`FG_Fortress.png` IS autotile-solvable** (tan stone, ~2030 modular pieces); **`FG_Houses.png` is NOT** (pre-built decorative house compositions, not modular wall variants). Iconic Homestead $19.99 fallback **not needed**. New decision required — see Open questions below.
- [x] **Wolf sprite source** — done. **No wolf in the bundle anywhere.** Need a custom commission, a CC0 sprite, or a Ventilatore find. New decision required — see Open questions below.
- [x] **Grave marker source** — done. `Retro Graveyard 16x16 Tileset [Kingdom Explorer]` confirmed in Tier 3, full graveyard suite. Direct use, no custom work.
- [ ] **License compilation** — maintain credits string for every pack used (ElvGames + Ventilatore + Kingdom Explorer + any others). Display in game's credits screen. Confirm specific terms per pack before any commercial release.
### Design topics still open
- [ ] **Player-built wall material strategy** (NEW from 2026-05-10 audit): `FG_Houses.png` doesn't autotile — it's pre-built house compositions, not modular wall pieces. Options:
- (a) **Fortress-stone-only** for player walls (uses `FG_Fortress.png` autotile-solvable). Cabin starts as a pre-placed `FG_Houses` static prop; player upgrades to stone fortress walls. Aesthetic shifts toward Going Medieval, away from cute-cabin Stardew vibe.
- (b) **Custom-author wood + stone walls** on top of `FG_Houses.png` and `FG_Fortress.png` — ~½1 day per material. Preserves the cute-farming-RPG warmth but delays Phase 5 by ~3 days.
- (c) **Mix**: use `FG_Houses` static prebuilt as starter shelter (no construction verb for it) + `FG_Fortress` autotile for player-built upgrade walls. Two materials, no custom art investment, but loses the "build your own first cabin" beat.
- Decision before Phase 1 wall-tileset import (Phase 1 needs at least one wall material to render).
- [ ] **Wolf sprite acquisition** (NEW from 2026-05-10 audit): bundle has nothing canine-predator. Options: (a) commission a 16×16 wolf (idle + 24-frame walk × 4 directions; ~few hours pixel art or paid commission ~$3060); (b) check Ventilatore bundle for a usable beast; (c) source a CC0 wolf from OpenGameArt; (d) reskin an existing animal placeholder (dark dog?) for MVP and replace later. Phase 10 blocker; can defer until then.
- [ ] **Auto-roof big-room UX**: the ≤8-cell BFS cap silently fails on rooms larger than 8×8. Decide whether to (a) keep the cap and surface "this area is too large to roof — split with an interior wall" hint when the player encloses one, (b) bump the cap to ~16 with the same hint at the new threshold, or (c) detect any enclosed area regardless of size. Affects `EnclosureDetector` + a new room-feedback UI.
- [ ] **Onboarding / first 60 seconds**: mobile-specific. Don't copy Rimworld's tutorial.
- [ ] **Touch UI for non-priority screens**: world view, build drawer, alerts, day-summary, pawn detail. See `docs/ui.md` "Screens still to design."
@ -157,7 +166,13 @@ Same scope as locked in `~/claude/ideas/rimlike/plan.md`. Realistic timeline 3
- Updated `docs/architecture.md` perf assumptions (60² → 80² with 120² ceiling).
- `docs/ui.md` got a new **World view camera (locked)** section; removed the world-view bullet from "Screens still to design".
- Open: auto-roof big-room UX (added to TODOs above) — the ≤8-cell BFS cap silently fails on bigger rooms; player feedback path needs a decision before EnclosureDetector lands.
- Wrote `docs/implementation.md` — 21-phase build plan with checkboxes, acceptance demos, scope-cut levers, and de-risking spikes. Status row at the top of that file is the canonical "where are we now" pointer; current value is **Phase 0 — Project scaffold & foundations** (gated by the 75-min pre-implementation audit). Wired into the index table above.
- Wrote `docs/implementation.md` — 21-phase build plan with checkboxes, acceptance demos, scope-cut levers, and de-risking spikes. Status row at the top of that file is the canonical "where are we now" pointer.
- **Project location moved** from `/home/megaproxy/claude/projects/rimlike/` to `/mnt/d/godot/rimlike/` (D: drive). Symlink at the original WSL path preserves the home-CLAUDE.md layout convention. Set `git config core.filemode false` to silence DrvFs's everything-is-0777 false-positive. Mirrors tavernkeep's pattern; both WSL and Windows access without crossing the WSL net bridge.
- **Phase 0 scaffold landed.** `project.godot` + 7 autoloads + smoke-test scene + addons re-copy + folder layout. Used **GL Compatibility renderer** (not Forward+) for max mobile reach. Folder layout matches tavernkeep (`autoload/` at root, scripts co-located in `scenes/`) — *not* the `scripts/autoloads/` mirror layout originally sketched in `implementation.md`. Headless verification: `godot --headless --path . --quit` exits 0 with the smoke-test message. Editor-side green-dot check pending — needs you to open the editor once.
- **Asset audit ran via researcher subagent (Haiku).** 3 of 5 items closed. Findings:
- `FG_Fortress.png` autotile-solvable (tan stone). `FG_Houses.png` NOT autotile-solvable (pre-built decorative compositions). Iconic Homestead fallback not needed. **Opens a new wall-material decision** (see Open questions).
- No wolf sprite anywhere in the bundle. **Opens a wolf-acquisition decision** (see Open questions).
- `Retro Graveyard 16x16 Tileset [Kingdom Explorer]` confirmed in Tier 3 — full graveyard suite, ready for direct use in Phase 14.
## External references

85
project.godot Normal file
View file

@ -0,0 +1,85 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=5
[application]
config/name="Rimlike"
config/description="2D tile-based cute-farming-RPG meets colony sim. Mobile-first, Godot 4."
run/main_scene="res://scenes/main/main.tscn"
config/features=PackedStringArray("4.6", "GL Compatibility")
config/icon="res://icon.svg"
[autoload]
EventBus="*res://autoload/event_bus.gd"
Strings="*res://autoload/strings.gd"
Audit="*res://autoload/audit.gd"
GameState="*res://autoload/game_state.gd"
World="*res://autoload/world.gd"
Sim="*res://autoload/sim.gd"
SaveSystem="*res://autoload/save_system.gd"
[display]
window/size/viewport_width=1280
window/size/viewport_height=720
window/stretch/mode="canvas_items"
window/stretch/aspect="keep"
window/handheld/orientation="sensor_landscape"
[editor_plugins]
enabled=PackedStringArray("res://addons/godot_mcp/plugin.cfg")
[input]
pause={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":32,"location":0,"echo":false,"script":null)
]
}
speed_cycle={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194306,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
speed_normal={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":49,"physical_keycode":0,"key_label":0,"unicode":49,"location":0,"echo":false,"script":null)
]
}
speed_fast={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":50,"physical_keycode":0,"key_label":0,"unicode":50,"location":0,"echo":false,"script":null)
]
}
speed_ultra={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":51,"physical_keycode":0,"key_label":0,"unicode":51,"location":0,"echo":false,"script":null)
]
}
confirm={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
cancel={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194305,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
]
}
[rendering]
textures/canvas_textures/default_texture_filter=0
renderer/rendering_method="gl_compatibility"
renderer/rendering_method.mobile="gl_compatibility"
2d/snap/snap_2d_transforms_to_pixel=true
2d/snap/snap_2d_vertices_to_pixel=true

0
scenes/effects/.gitkeep Normal file
View file

0
scenes/entities/.gitkeep Normal file
View file

20
scenes/main/main.gd Normal file
View file

@ -0,0 +1,20 @@
extends Node
## Phase 0 smoke-test scene root.
##
## Verifies the autoload graph is alive and the i18n table resolves a key.
## Once Phase 1 lands the world view, this becomes the bootstrap that loads
## the right scene based on game state (new game / continue / settings).
@onready var hello_label: Label = $HelloLabel
func _ready() -> void:
Audit.log("main", "Phase 0 smoke test online.")
# Verify autoloads are alive.
assert(World != null, "World autoload missing")
assert(Sim != null, "Sim autoload missing")
assert(GameState != null, "GameState autoload missing")
assert(EventBus != null, "EventBus autoload missing")
assert(Strings != null, "Strings autoload missing")
assert(SaveSystem != null, "SaveSystem autoload missing")
hello_label.text = Strings.t(&"smoke.hello")

15
scenes/main/main.tscn Normal file
View file

@ -0,0 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://rimlike_main"]
[ext_resource type="Script" path="res://scenes/main/main.gd" id="1_main"]
[node name="Main" type="Node"]
script = ExtResource("1_main")
[node name="Camera2D" type="Camera2D" parent="."]
[node name="HelloLabel" type="Label" parent="."]
offset_left = 32.0
offset_top = 32.0
offset_right = 800.0
offset_bottom = 96.0
text = "(boot)"

0
scenes/pawn/.gitkeep Normal file
View file

0
scenes/ui/.gitkeep Normal file
View file

0
scenes/world/.gitkeep Normal file
View file

0
tests/.gitkeep Normal file
View file

0
tools/.gitkeep Normal file
View file