RECORDANDRONCO/MEGAPLAN.md
2026-07-20 04:51:31 +10:00

13 KiB
Raw Blame History

VINYLGOD MEGAPLAN — execution instructions

Audience: an executing coding agent (Opus 4.8). Read this whole file before phase 1. Lore, names, and art prompts live in LORE.md — use it as canon.

0. Mission & hard rules

Build VINYLGOD, an original vinyl-themed RTS, as an OpenRA total-conversion mod in this repo. The classic RTS at ~/Documents/CnC_Remastered_Collection is the read-only design reference for balance and feel. Hard rules:

  1. Never copy code, text, names, or assets from the reference repo into this one. No EA trademarks anywhere — not in ids, comments, commit messages, or filenames. Balance numbers (costs, HP, ranges) are facts and fine to reuse.
  2. This repo is GPL v3 (OpenRA engine + SDK). Everything we add stays GPL-compatible. All art/audio we generate on MODELBEAST is our own — keep provenance: every asset in assets_src/ comes from a prompt logged in assets_src/PROMPTS.md (append as you go).
  3. Data-driven first. YAML in mods/vinylgod/ solves 95% of everything. Only write C# traits in OpenRA.Mods.Vinylgod/ when no stock trait combination works, and check engine/OpenRA.Mods.Common/Traits/ thoroughly first.
  4. After every phase: run the checks in §2, commit with a one-line message. Don't push anywhere without John's say-so.

1. Environment (ultra, macOS arm64)

cd ~/Documents/VINYLGOD
export PATH="/opt/homebrew/opt/dotnet@8/bin:$PATH"
export DOTNET_ROLL_FORWARD=LatestMajor     # engine targets net6, we run net8 — required
make                    # build engine (cached) + mod dll
./utility.sh --check-yaml                  # lint all mod yaml — must stay clean
./launch-game.sh Game.Mod=vinylgod         # run the game
./launch-game.sh Game.Mod=vinylgod Launch.Benchmark=true   # headless-ish smoke test
  • Engine source lives in ./engine (auto-fetched, treat read-only; version pinned in mod.config ENGINE_VERSION="release-20250330").
  • Logs: ~/Library/Application Support/OpenRA/Logs/ (debug.log, exception.log).
  • The single best reference is engine/mods/ra and engine/mods/cnc — complete, working mods using the same engine version. When unsure how to wire a trait, find the equivalent actor there and adapt. (Referencing their YAML structure is what they're for; don't ship their art/strings.)

2. Definition of done (every phase)

  1. ./utility.sh --check-yaml → zero errors.
  2. make → zero errors.
  3. Launch the game, start a skirmish on the test map, exercise the new feature.
  4. git add -A && git commit (local only).

3. Repo layout (what the SDK gives us)

mod.config                  # MOD_ID=vinylgod, packaging names
mods/vinylgod/
  mod.yaml                  # manifest: packages, rules/weapons/sequences includes
  rules/                    # actor definitions (vinylgod.yaml, world.yaml, ...)
  weapons/                  # weapon/warhead definitions
  sequences/                # sprite-name → image-sheet mappings
  tilesets/                 # terrain definition
  maps/vinylgod/, maps/shellmap/
  chrome/, fluent/          # UI layout, user-facing strings (fluent = translations)
  notifications/, voices/, music/
OpenRA.Mods.Vinylgod/       # C# project for custom traits (mostly empty — keep it so)
tools/mbgen.py              # MODELBEAST asset generation (works, tested)
assets_src/                 # generated art sources (concepts, renders, sheets)
LORE.md                     # canon: factions, roster, art prompt seeds

The current mod content is the SDK example (one test unit, one tileset) renamed to vinylgod — it boots. You will progressively replace it.

4. Balance bible (verified from the reference codebase)

Anchor numbers, lifted from the reference RTS's data tables (its harvester block and building cost table were read directly from source). Use as starting values, tune later:

Thing Reference value VINYLGOD actor
Harvester cost 1400, HP 600, slow, unarmed, prereq refinery digger
Refinery cost 2000 pressplant
Power plant cost 300 / adv 700 ampstack
Silo cost 150 vault
Barracks cost 300 merchtable / podfarm
War factory cost 2000 garage
Construction yard cost 5000 (deploys from MCV) popupshop
Basic infantry cost 100 djgrunt / bufferbot
Medium tank cost 800 stacktank
Artillery cost 450, long range, fragile basscannon
Full harvester load ~700 credits one digger load of wax
Tech centre cost 1500, unlocks superweapon mastering

Design intent per faction (from LORE.md): MRP = fewer/tougher/louder, The Stream = cheap/fast/swarm with aggressive build-radius creep via datacentre.

5. Phases

Phase A — Wax economy (do this first)

Goal: skirmish map where a digger harvests wax fields and returns it to a pressplant for credits; ampstack powers the base; vault extends storage.

  1. Resource type. In rules/world.yaml add to the World actor: ResourceLayer + ResourceRenderer (crib the exact block from engine/mods/ra/rules/world.yaml, resource type id wax, value ~25/cell-step), and a ResourceClaimLayer for harvester coordination. Player side: PlayerResources (on Player actor in rules/player.yaml) with DefaultCash: 5000.
  2. Wax overlay art. Placeholder first: 12 density frames of magenta-black blobs, 24×24px, one PNG sheet; wire in sequences/. Density growth = ResourceLayer handles it; seed patches in the test map with the map editor (./launch-game.sh Game.Mod=vinylgod → map editor is built into the game menu).
  3. Actors. In rules/vinylgod.yaml define digger (traits: Harvester with Resources: wax, Mobile, Health, Selectable, DockClientManager), pressplant (Refinery, DockHost, Building), ampstack (Power: 100), vault (StoresPlayerResources). Copy trait shapes from the RA mod's equivalents and rename everything.
  4. Placeholder sprites are fine (single-frame colored boxes); art comes in Phase D. Sequences yaml must exist for every actor or check-yaml fails.
  5. Acceptance: start skirmish, build nothing, select pre-placed digger → it auto-harvests, credits tick up on delivery.

Phase B — Building & production

Goal: full base loop. popupshop MCV deploys into construction yard; sidebar builds ampstack/pressplant/merchtable/garage/vault; garage produces digger and spinner; merchtable produces djgrunt and roadie.

Key traits: Transforms (MCV→HQ), BaseBuilding, ProductionQueue (on Player, one per queue type: Building, Vehicle, Infantry), Production + Exit on factories, Buildable (with Prerequisites: and Queue:) on everything, ProvidesPrerequisite on tech buildings, GivesBuildableArea + RequiresBuildableArea for build radius. Sidebar chrome: adapt chrome.yaml from the example mod's working sidebar; icons are 64×48 PNGs (placeholder text-on-color fine). Prerequisite chain (mirrors the reference game's feel): ampstack → pressplant → merchtable → garage; pressplant → vault; garage+pressplant → mastering.

Phase C — Combat & first playable faction (MRP)

Goal: winnable skirmish vs a second human (no AI yet).

  1. Weapons in weapons/: tonearm_blade (anti-inf melee-ish), seven_inch (thrown razor record, arcing), bass_ring (artillery AoE, Warhead@Concussion), feedback_burst (anti-armor). Copy warhead structure from RA weapons yaml.
  2. Combat units: spinner (fast, cheap, Armament tonearm_blade), stacktank (slow, tough, bass), basscannon (long range, min range, fragile), djgrunt (basic inf), roadie (EngineerRepair, Captures).
  3. AttackMove, stances, AutoTarget on everything armed.
  4. Win condition: MissionObjectives + ConquestVictoryConditions on World.
  5. Acceptance: two-player LAN skirmish (launch-dedicated.sh + two clients, or one client + Launch.Connect), fight to elimination.

Phase D — Real art via MODELBEAST (can interleave with B/C)

Pipeline per unit (all free, all local; ~10s/image, minutes/mesh):

  1. python3 tools/mbgen.py "<LORE.md prompt seed>, isometric game unit, plain grey background" assets_src/concepts/<id>.png
  2. For units needing rotation facings: concept → GLB via python3 tools/mbgen.py --op trellis_mac assets_src/concepts/<id>.png assets_src/mesh/<id>.glb (or hunyuan3d_mlx), then Blender (ultra has it + MCP) renders a turntable: 16 facings for vehicles, 8 for infantry, 1 for buildings + a 'make' anim later. Orthographic camera pitched ~40°, 1-2px outline, render 96×96 (vehicles) / 64×64 (infantry) / 192×192 (buildings) on transparency.
  3. Montage frames into a horizontal strip PNG (ImageMagick montage -tile x1), drop in mods/vinylgod/sequences/assets/, reference from sequences yaml (Filename:, Facings: 16, Frames:). OpenRA loads plain PNG sheets directly.
  4. Buildings: damaged state = second row (50% HP swap via sequence damaged-idle).
  5. Log every prompt in assets_src/PROMPTS.md.
  6. Shadows: Shadow render trait or baked — pick one, be consistent.

Sprite QA gate: consistent camera angle + light direction across ALL units of a faction, or it reads as clip-art soup. Fix the Blender camera rig once, reuse.

Phase E — The Stream faction + AI

  1. Second side in rules/player.yaml Factions; Stream actor set per LORE.md roster; shared tech tree structure, different stats (cheap/fast/fragile).
  2. Skirmish AI: ModularBot + SquadManagerBotModule + BaseBuilderBotModule + HarvesterBotModule on the Player — copy the RA mod's bot config wholesale and re-point unit ids, then tune.
  3. Acceptance: beat the bot; watch the bot expand, harvest, and attack.

Phase F — Sound & polish

  1. Music: mbgen.py --op music_local (tags → track; primary-only, ~4min cold start per job) — 4-6 tracks, wire in music/.
  2. MC 8-TRACK announcer: tts_local (pick a gravelly Kokoro voice) or voice_clone_local with a reference wav from ~/Documents/character_kit/voices/. Lines in notifications/ yaml. ASSISTANT voice for Stream: cleanest TTS voice, dry.
  3. Shellmap: scripted background battle on the menu screen (see RA shellmap lua).
  4. Chrome re-skin: hot pink/black UI, emblem (assets_src/concepts/emblem_mrp.png) as mod logo in mod.yaml + loadscreen.
  5. Rename pass: pick final display name (see LORE.md candidates), update mod.config packaging fields; packaging/ scripts already produce a mac .dmg.

Phase G — Ship

  1. Run the ship-check skill before anything goes public.
  2. Gitea remote first (ssh://git@100.71.119.27:222), public GitHub mirror when John says go (repo must carry COPYING = GPL v3, credit OpenRA engine).
  3. itch.io page + dmg/AppImage/exe via packaging/package-all.sh <tag>.

6. Known traps

Learned the hard way on 2026-07-20 (phases AF):

  • Smoke-test any change by launching straight into a game: ./launch-game.sh Game.Mod=vinylgod Launch.Map=vinylgodLaunch.Map accepts the map's folder name, no UID needed. Run ~45s, then check ~/Library/Application Support/OpenRA/Logs/ for exception-*.log (renamed with a timestamp on crash — absence of exception.log alone proves nothing).
  • The shellmap is the integration test: it runs a bot-vs-bot match (BotA MRP vs BotB Stream, Bot: wax in map.yaml) behind the main menu. If a trait wiring is broken, the menu crashes within seconds.
  • Chrome image collections must be power-of-two textures (a 48×48 png crashes the renderer).
  • Every rules file must use the same case for shared top-level actors: player: not Player: — mismatched case = "duplicate values" manifest error.
  • Speech notification Sounds/Speech blocks: set DefaultVariant: .wav (engine default is .aud).
  • MODELBEAST music_local takes prompt (not tags); tts_local takes text.
  • ConquestVictoryConditions needs MapOptions: on the world actor; Health needs HitShape; actors need a visibility trait (HiddenUnderFog:); Selectable already includes Interactable (don't add both).
  • StartingUnits.SupportActors must be mobile units, never buildings.
  • In zsh scripts: UID is a readonly shell variable, and an unmatched glob aborts the whole command line (setopt nonomatch first).
  • Forgot DOTNET_ROLL_FORWARD=LatestMajor → "framework 6.0.0 not found" crash.
  • Every actor referenced in a map/rules needs a sequences entry, even placeholders.
  • Trait names change between engine releases — trust engine/mods/ra on THIS checkout over any wiki/tutorial (wiki tracks bleed).
  • The Fluent string files (fluent/*.ftl) must contain every label/name key you reference or check-yaml warns; keep them updated as actors land.
  • MODELBEAST guest token caps at 4 active jobs — batch sequentially; if we need bulk parallel gen, mint a proper user token on m3ultra (John approved) — the token-mint path is in the MODELBEAST repo on m3ultra (~/Documents/MODELBEAST).
  • Don't touch engine/ — engine mods belong upstream or via AUTOMATIC_ENGINE_MANAGEMENT=False (avoid).