redesign(1.0): single-branch 1.0 rewrite#278
Conversation
…oster
Redesign 1.0 opening commit. The 3D asset experiment was never
finished — 28 MB of preview GLBs in public/assets/3d/ that no
playable path consumed. docs/DESIGN.md commits the game to the
2D paper-pinned identity, so both the 3D tree and the r3f-based
landing components go.
Removed:
- public/assets/3d/ entire tree (~28 MB, 86 files)
- src/assets/catalog.ts + catalog.test.ts (the 3D manifest + tests)
- src/assets/ directory (empty after catalog removal)
- scripts/build-catalog.sh + scripts/salvage-glbs.sh (rebuilders for
the deleted manifest)
Rewritten to 2D:
- src/components/landing/HeroCanvas.tsx — was an r3f <Canvas> with
useGLTF('clown_car'), headlights, and fog. Now a pure-CSS
tent-canvas backdrop over an animated amber headlight-glow pool.
Preserves the `{ active }` prop so Hero.tsx's lazy import works
unchanged. HeroCanvas chunk drops to ~1.17 kB; r3f bundle shrinks
by ~86 kB as a side effect because useGLTF is no longer imported
on the landing path.
- src/components/landing/Villains.tsx — was a second r3f <Canvas>
rotating beppo_clown.glb next to pull-quotes. Now a static <img>
poster of popup_clown.png with halftone-style amber vignette and
an optional CSS idle sway that honors prefers-reduced-motion.
Naming note: still called "Villains" for continuity with the
current landing composition, flagged in the file for the later
rename to BeppoReveal (docs/DESIGN.md: the game has no "villains"
concept, Beppo is a scripted three-act boss).
Added:
- src/lib/assetPath.ts — normalizedBaseUrl() + assetPath(relative)
helpers that resolve public-asset URLs against the Vite/Astro
configured base path. Used by both landing components so the
base-join logic isn't duplicated.
- src/lib/assetPath.test.ts — 6 unit tests covering root base,
subpath base, subpath-without-trailing-slash, and
leading-slash-on-relative-path cases.
New CSS keyframes in src/index.css:
- beppo-sway (Villains poster idle drift)
- hero-headlight-sweep (headlight glow pool drift)
Both collapse to 0.01ms under the existing
@media (prefers-reduced-motion: reduce) block.
README.md project-layout block updated to reflect the new shape
(no more src/assets/, no more public/assets/3d/).
pnpm typecheck + lint + test (535 pass) + build all green. No
gameplay code touched. Part of redesign/1.0 single-branch rewrite
per docs/plans/2026-04-24-beppo-1.0-redesign.prq.md.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 2 minutes and 42 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Repository YAML (base), Organization UI (inherited) Review profile: ASSERTIVE Plan: Pro Run ID: ⛔ Files ignored due to path filters (36)
📒 Files selected for processing (20)
📝 WalkthroughWalkthroughThis PR removes the 3D asset catalog generation pipeline (build scripts, JSON manifests, TypeScript catalog) and replaces three.js/r3f-based 3D rendering with simpler 2D CSS and image-based assets. New runtime asset path utilities replace the static catalog approach. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 5 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@README.md`:
- Around line 87-90: The README's public/assets tree omits the runtime asset
manifest; add an entry for public/assets/asset-catalog.json and a short note
that this JSON is the runtime asset manifest used by the game. Update the assets
tree under the public/assets section to include "asset-catalog.json" and note
its purpose/location so it isn’t removed; reference that it is consumed by
src/game/assetCatalog.ts and relied upon by src/components/game/Scene.tsx and
src/game/spawnPlan.ts so maintainers know it’s required at runtime.
In `@src/lib/assetPath.ts`:
- Around line 18-19: The code that builds the asset URL only strips a single
leading slash from relative (variable name "relative") so inputs like
"//assets/foo.png" yield double slashes; update the cleaning step in
src/lib/assetPath.ts to remove all leading slashes (e.g., trim leading '/'
characters using a regex or loop) before concatenating with normalizedBaseUrl(),
keeping the same return construction that uses normalizedBaseUrl() and the
cleaned variable.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository YAML (base), Organization UI (inherited)
Review profile: ASSERTIVE
Plan: Pro
Run ID: c73bfc00-e3ea-45b5-bb99-eee75a4f21c6
📒 Files selected for processing (92)
README.mdpublic/assets/3d/asset-catalog.jsonpublic/assets/3d/collectible/broken_pocket_watch/manifest.jsonpublic/assets/3d/collectible/broken_pocket_watch/metadata.jsonpublic/assets/3d/collectible/broken_pocket_watch/preview.glbpublic/assets/3d/collectible/crumpled_playbill/manifest.jsonpublic/assets/3d/collectible/crumpled_playbill/metadata.jsonpublic/assets/3d/collectible/crumpled_playbill/preview.glbpublic/assets/3d/collectible/faded_photograph/manifest.jsonpublic/assets/3d/collectible/faded_photograph/metadata.jsonpublic/assets/3d/collectible/faded_photograph/preview.glbpublic/assets/3d/collectible/paper_mache_elephant/manifest.jsonpublic/assets/3d/collectible/paper_mache_elephant/preview.glbpublic/assets/3d/collectible/paper_mache_lion/manifest.jsonpublic/assets/3d/collectible/paper_mache_lion/metadata.jsonpublic/assets/3d/collectible/paper_mache_lion/preview.glbpublic/assets/3d/collectible/paper_mache_seal/manifest.jsonpublic/assets/3d/collectible/paper_mache_seal/metadata.jsonpublic/assets/3d/collectible/paper_mache_seal/preview.glbpublic/assets/3d/collectible/rusty_key/manifest.jsonpublic/assets/3d/collectible/rusty_key/metadata.jsonpublic/assets/3d/collectible/rusty_key/preview.glbpublic/assets/3d/collectible/torn_ticket/manifest.jsonpublic/assets/3d/collectible/torn_ticket/metadata.jsonpublic/assets/3d/collectible/torn_ticket/preview.glbpublic/assets/3d/obstacle/broken_carousel_horse/manifest.jsonpublic/assets/3d/obstacle/broken_carousel_horse/metadata.jsonpublic/assets/3d/obstacle/broken_carousel_horse/preview.glbpublic/assets/3d/obstacle/broken_mirror_maze/manifest.jsonpublic/assets/3d/obstacle/broken_mirror_maze/metadata.jsonpublic/assets/3d/obstacle/broken_mirror_maze/preview.glbpublic/assets/3d/obstacle/burning_hoop/manifest.jsonpublic/assets/3d/obstacle/burning_hoop/metadata.jsonpublic/assets/3d/obstacle/burning_hoop/preview.glbpublic/assets/3d/obstacle/collapsed_bleachers/manifest.jsonpublic/assets/3d/obstacle/collapsed_bleachers/metadata.jsonpublic/assets/3d/obstacle/collapsed_bleachers/preview.glbpublic/assets/3d/obstacle/falling_tent_pole/manifest.jsonpublic/assets/3d/obstacle/falling_tent_pole/metadata.jsonpublic/assets/3d/obstacle/falling_tent_pole/preview.glbpublic/assets/3d/obstacle/overturned_popcorn_cart/manifest.jsonpublic/assets/3d/obstacle/overturned_popcorn_cart/metadata.jsonpublic/assets/3d/obstacle/overturned_popcorn_cart/preview.glbpublic/assets/3d/obstacle/scattered_hay_bales/manifest.jsonpublic/assets/3d/obstacle/scattered_hay_bales/metadata.jsonpublic/assets/3d/obstacle/scattered_hay_bales/preview.glbpublic/assets/3d/performer/carnival_barker/manifest.jsonpublic/assets/3d/performer/carnival_barker/metadata.jsonpublic/assets/3d/performer/carnival_barker/preview.glbpublic/assets/3d/performer/fire_breather/manifest.jsonpublic/assets/3d/performer/fire_breather/metadata.jsonpublic/assets/3d/performer/fire_breather/preview.glbpublic/assets/3d/performer/juggler/manifest.jsonpublic/assets/3d/performer/juggler/preview.glbpublic/assets/3d/performer/lion_tamer/manifest.jsonpublic/assets/3d/performer/lion_tamer/metadata.jsonpublic/assets/3d/performer/lion_tamer/preview.glbpublic/assets/3d/performer/magician/manifest.jsonpublic/assets/3d/performer/magician/metadata.jsonpublic/assets/3d/performer/magician/preview.glbpublic/assets/3d/performer/sword_swallower/manifest.jsonpublic/assets/3d/performer/sword_swallower/metadata.jsonpublic/assets/3d/performer/sword_swallower/preview.glbpublic/assets/3d/performer/tightrope_walker/manifest.jsonpublic/assets/3d/performer/tightrope_walker/metadata.jsonpublic/assets/3d/performer/tightrope_walker/preview.glbpublic/assets/3d/performer/trapeze_artist/manifest.jsonpublic/assets/3d/performer/trapeze_artist/metadata.jsonpublic/assets/3d/performer/trapeze_artist/preview.glbpublic/assets/3d/vehicle/circus_wagon/manifest.jsonpublic/assets/3d/vehicle/circus_wagon/preview.glbpublic/assets/3d/vehicle/clown_car/manifest.jsonpublic/assets/3d/vehicle/clown_car/metadata.jsonpublic/assets/3d/vehicle/clown_car/preview.glbpublic/assets/3d/vehicle/unicycle/manifest.jsonpublic/assets/3d/vehicle/unicycle/preview.glbpublic/assets/3d/villain/beppo_clown/manifest.jsonpublic/assets/3d/villain/beppo_clown/metadata.jsonpublic/assets/3d/villain/beppo_clown/preview.glbpublic/assets/3d/villain/mime/manifest.jsonpublic/assets/3d/villain/mime/preview.glbpublic/assets/3d/villain/ringmaster/manifest.jsonpublic/assets/3d/villain/ringmaster/preview.glbscripts/build-catalog.shscripts/salvage-glbs.shsrc/assets/catalog.test.tssrc/assets/catalog.tssrc/components/landing/HeroCanvas.tsxsrc/components/landing/Villains.tsxsrc/index.csssrc/lib/assetPath.test.tssrc/lib/assetPath.ts
💤 Files with no reviewable changes (57)
- public/assets/3d/collectible/paper_mache_lion/metadata.json
- public/assets/3d/performer/carnival_barker/metadata.json
- public/assets/3d/collectible/broken_pocket_watch/metadata.json
- public/assets/3d/performer/lion_tamer/metadata.json
- public/assets/3d/collectible/paper_mache_seal/manifest.json
- public/assets/3d/obstacle/broken_mirror_maze/manifest.json
- public/assets/3d/obstacle/scattered_hay_bales/manifest.json
- public/assets/3d/collectible/paper_mache_lion/manifest.json
- public/assets/3d/collectible/broken_pocket_watch/manifest.json
- public/assets/3d/collectible/torn_ticket/manifest.json
- public/assets/3d/obstacle/broken_mirror_maze/metadata.json
- public/assets/3d/performer/tightrope_walker/metadata.json
- public/assets/3d/collectible/paper_mache_elephant/manifest.json
- public/assets/3d/collectible/torn_ticket/metadata.json
- public/assets/3d/vehicle/clown_car/manifest.json
- public/assets/3d/vehicle/unicycle/manifest.json
- public/assets/3d/collectible/faded_photograph/metadata.json
- public/assets/3d/collectible/rusty_key/metadata.json
- public/assets/3d/obstacle/burning_hoop/manifest.json
- public/assets/3d/asset-catalog.json
- public/assets/3d/obstacle/falling_tent_pole/manifest.json
- public/assets/3d/performer/trapeze_artist/metadata.json
- public/assets/3d/vehicle/clown_car/metadata.json
- public/assets/3d/performer/fire_breather/metadata.json
- public/assets/3d/collectible/crumpled_playbill/manifest.json
- public/assets/3d/collectible/paper_mache_seal/metadata.json
- public/assets/3d/performer/fire_breather/manifest.json
- public/assets/3d/obstacle/collapsed_bleachers/metadata.json
- public/assets/3d/obstacle/overturned_popcorn_cart/manifest.json
- public/assets/3d/obstacle/collapsed_bleachers/manifest.json
- public/assets/3d/obstacle/scattered_hay_bales/metadata.json
- public/assets/3d/performer/trapeze_artist/manifest.json
- public/assets/3d/obstacle/broken_carousel_horse/manifest.json
- src/assets/catalog.test.ts
- public/assets/3d/performer/carnival_barker/manifest.json
- public/assets/3d/obstacle/falling_tent_pole/metadata.json
- public/assets/3d/performer/lion_tamer/manifest.json
- public/assets/3d/collectible/rusty_key/manifest.json
- public/assets/3d/performer/magician/metadata.json
- public/assets/3d/villain/beppo_clown/metadata.json
- public/assets/3d/villain/ringmaster/manifest.json
- scripts/build-catalog.sh
- public/assets/3d/obstacle/overturned_popcorn_cart/metadata.json
- public/assets/3d/performer/sword_swallower/metadata.json
- public/assets/3d/performer/sword_swallower/manifest.json
- public/assets/3d/performer/juggler/manifest.json
- public/assets/3d/performer/tightrope_walker/manifest.json
- scripts/salvage-glbs.sh
- public/assets/3d/vehicle/circus_wagon/manifest.json
- public/assets/3d/villain/mime/manifest.json
- public/assets/3d/performer/magician/manifest.json
- public/assets/3d/collectible/faded_photograph/manifest.json
- src/assets/catalog.ts
- public/assets/3d/obstacle/burning_hoop/metadata.json
- public/assets/3d/collectible/crumpled_playbill/metadata.json
- public/assets/3d/obstacle/broken_carousel_horse/metadata.json
- public/assets/3d/villain/beppo_clown/manifest.json
Reshapes the asset tree and asset-catalog.json to the redesign/1.0
taxonomy documented in docs/DESIGN.md + docs/assets/ASSET_GENERATION.md.
The catalog here is *provisional* — the canonical source of truth for
gameplay behavior and placement rules will land in a proper
archetype/definition config package in the Turboplan work. This
commit keeps the engine compilable against the new taxonomy while
that larger refactor is in flight.
File moves (35 renames + 1 deletion):
- public/assets/generated_images/ (flat) →
public/assets/images/{floors,walls,ceilings,items,drops,slides,popups}/
- `slide_spiked_door.png` deleted (cut during design review —
`items/souvenir_pin.png` didn't have a clean mechanical
resolver fit for the guillotine, so we trimmed to 5 blockade arts
aligned 1-to-1 with 5 resolver items)
- Three files reclassified from walls to ceilings:
`wall_velvet_drape`, `wall_ringmaster_banners`,
`vintage_circus_tent_canvas` (the last being both the outer-ring
ceiling AND the landing-page background — no duplicated file,
consumers share the same path)
- Items renamed to drop legacy prefixes: `item_*` → bare name,
`paper_mache_*_item` → `exit_key` / `circus_ticket`, `item_pin` →
`souvenir_pin`
Catalog schema rewrite (public/assets/asset-catalog.json):
- Buckets: floors[], walls[], ceilings[], items[], drops[],
slides[], popups[]
- Each asset carries `id`, `fileName`, `path` (category-relative),
`prompt`, `aspectRatio`
- Floors/walls/ceilings add `zoneBias: 'outer' | 'outer-mid' |
'inner-mid' | 'inner'`
- Items add `role: 'resolver' | 'sanity' | 'mitigator' | 'special'`
plus `resolverOf` / `restores` / `mitigates` / `effect`
- Drops/slides add `resolverItem: string` — the id of the item that
opens this blockade
- Popups add `script: 'jester' | 'tubeman' | 'clown'`
- `ui: { landingBackground }` points at the shared tent image
- Regenerated via scripts/redesign/rewrite-catalog.mjs (committed
as provenance of the one-shot migration; safe to delete once the
archetype/definition package lands)
Type rewrites (src/game/assetCatalog.ts):
- New discriminated types: FloorAsset, WallAsset, CeilingAsset,
ItemAsset, DropAsset, SlideAsset, PopupAsset — each extends a
shared CatalogImageAsset
- ASSET_IMAGE_BASE now points at /assets/images/ (via assetPath
helper)
- New imageUrl() helper joins category-relative path to the base
Consumer updates:
- src/game/spawnPlan.ts: blockades sourced from drops+slides;
resolvers sourced from items.filter(role='resolver'); pairings
matched via resolverItem <-> resolverOf instead of the old
"unlock-<nodeId>" placeholder
- src/game/textures.ts: thin surface kept for non-migrated
consumers; paths updated to assets/images/<category>/<id>.png
- src/components/game/Maze.tsx: reads wall/ceiling/floor pools from
new schema buckets
- src/components/game/Collectibles.tsx: reads items pool from new
schema; asset.path replaces asset.fileName + manual concat
- src/components/landing/{HeroCanvas,Villains}.tsx: updated to
new paths
Test rewrites:
- src/game/assetCatalog.test.ts: rewritten for new schema; tests
constants, imageUrl, loadAssetCatalog lifecycle, pickSeededAsset
- src/game/spawnPlan.test.ts: rewritten with new mock factories for
the drops/slides/resolvers shape; covers null-catalog,
empty-blockade, empty-resolver, pairing, collectible/blockade
correspondence, and determinism
- src/game/textures.test.ts: path assertions updated
(generated_images → images)
- src/components/game/{Maze,Collectibles}.test.tsx: mocks updated
to new schema
Typecheck + lint + build all green.
Two minor findings from the first CodeRabbit review pass on PR #278: - src/lib/assetPath.ts: assetPath() only stripped a single leading slash, so "//assets/foo.png" still produced a double-slash URL after joining. Switched to `replace(/^\/+/, '')` so runs of leading slashes collapse. Added a regression test covering "//" and "///" prefixes. - README.md: the Project Layout block described public/assets/ but omitted asset-catalog.json, which is still fetched at runtime by src/game/assetCatalog.ts and src/game/spawnPlan.ts. Added it explicitly with a one-line description; also renamed the tree entry from generated_images/ to images/ to reflect the taxonomy rewrite that landed in the previous commit.
Both findings addressed in commit 6c9d71a: assetPath multi-slash strip + regression test, README project-layout includes asset-catalog.json.
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
CI on PR #278 surfaced two real issues from the taxonomy rewrite plus a long-running infrastructure nuisance: 1. **textures.test.ts** — 7 tests still asserted on the OLD filenames (paper_mache_circus_ticket_item.png, etc.) and on the old "paper mâché" description copy. The rename in the asset reorg broke these. Updated to assert new category-scoped paths (items/circus_ticket.png, items/exit_key.png, floors/..., ceilings/..., walls/...) and dropped the now-obsolete "paper mâché" description substring check. 2. **Playwright smoke — React duplicate-key warning fails the console-errors assertion.** spawnPlan.buildSpawnPlan was using the resolver item id (e.g. "mallet") as the collectible.id. Two blockades needing the same resolver produced two collectibles with the same id, and React rendering them via `<Collectible key={item.id} />` emitted "Encountered two children with the same key" to the console, which e2e treats as a failure. Collectibles now use a per-placement id (`item-<nodeId>`); the resolver-item id is still carried as `name` and the blockade pairing still works via `unlocksBlockadeId`. Test updated to assert collectible-id uniqueness + name/unlocks pairing. 3. **.claude/settings.json: removed the Stop hook.** The old polish-batch Stop guard was firing ASSESS.play-and-improve on every turn against a stale state file from an earlier batch (.claude/state/task-batch/batch-20260423-beppo-1.0.json). Archived the stale state file and removed the hook entirely — the redesign PRD is the governing driver now, not a per-turn batch loop.
The landing component was carrying forward the legacy 'Villains' name from pre-redesign. The game has no 'villains' concept in redesign/1.0 — Beppo is a scripted three-act boss (jester → tubeman → clown, see docs/DESIGN.md popup choreography). The landing section is a single Beppo reveal, not a gallery of antagonists. - src/components/landing/Villains.tsx → BeppoReveal.tsx (git mv) - Internal export Villains → BeppoReveal, doc comment updated - src/components/landing/Landing.tsx import/usage updated No behavior change. The in-game src/components/game/Villains.tsx is a separate file and stays named Villains for now — it manages the SDF-shader encounter entities that'll be refactored into proper per-popup scripts (jester/tubeman/clown) in the Turboplan ECS work.
…aphy The Mechanics section on the landing page still described the game in pre-redesign terms: 'Villains drift the maze' (wrong — popups are scripted boss moments, not drifting entities) and 'Two doors open at the edge. Only one leads out' (wrong — docs/DESIGN.md commits to one specific exit_key that must be collected to leave, no door decoys). Card 03: 'Stay ahead of the laughter' → 'Meet Beppo on his terms'. Copy rewritten around the three-act popup structure (jester → tubeman → clown) matching DESIGN.md popup choreography. Card 04: 'Find the real exit' → 'Find the key that lets you leave'. Copy rewritten around exit_key as the gating mechanic. Kept the 'still laughing' sting from the original. Part of redesign/1.0. No behavior change — copy only.
|



Overview
Draft — single-branch 1.0 rewrite. Replaces the phase-by-phase approach: the phase PRs would have forced every affected file to be rewritten multiple times (each phase inherited the previous phase's still-wrong shape), burning review cycles on intermediate wrongness.
Instead: logical commits land directly on this branch. Each push triggers a fresh review round. Integration happens once, when the whole thing's coherent. One squash-merge to main.
Follows:
docs/DESIGN.md— canonical game spec (identity, dual sanity meters, popup choreography, maze guarantees, cockpit layout, landing unification, ECS boundary, config package layout).docs/assets/ASSET_GENERATION.md— asset-by-asset audit + generation plan.docs/plans/2026-04-24-beppo-1.0-redesign.prq.md— full PRD (sequenced as phases there; this PR executes them as logical commits instead of PRs).Commits (running log, appended as work lands)
refactor(landing): replace 3D landing with 2D tent backdrop + Beppo poster— deletespublic/assets/3d/tree (~28 MB),src/assets/catalog.ts,scripts/{build-catalog,salvage-glbs}.sh. ReworksHeroCanvas.tsx+Villains.tsxto pure-CSS 2D using a newsrc/lib/assetPathhelper. 535 tests still green.Remaining scope
Executed as additional commits on this branch. Reviewers can start eyeing commit 1 while these are in flight:
public/assets/images/{floors,walls,ceilings,items,drops,slides,popups,ui}/with final names (stripitem_,paper_mache_,vintage_circus_tent_canvas_texture; reclassify velvet_drape + ringmaster_banners + tent_canvas as ceilings).config/raw/+config/compiled/package with every tunable (sanity rates, popup scripts, item effects, asset manifest, palette, strings).src/ecs/) replaces Zustand.Jester,Tubeman,Clownentities — no "Villains" abstraction anywhere in game code.DESIGN.mdtable./landing,/playscene — no MainMenu overlay), Help button replaces forced tutorial.landing/Villains.tsx→BeppoReveal.tsxandHeroCanvas.tsx→HeroBackdrop.tsxas part of the final integration pass.Test plan
pnpm typecheck,pnpm lint,pnpm test(535 pass),pnpm build— all greenKept as draft until the game is fully playable end-to-end on this branch. Converted to ready-for-review for the final integration pass.
Summary by CodeRabbit
Documentation
Chores