Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions agent-test/docs/asset_protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,30 @@ If generating \*too many assets**, split into **2 separate tool calls\*\* to avo
| `image` | `key`, `description` | PNG 386\*560 (portrait) | Yes |
| `audio` | `key`, `description`, `audioType`, `duration?`, `genre?`, `tempo?` | WAV (8-bit chiptune) | N/A |

### 1.2.0 3D Image Assets (`threed_basic`)

Three.js games use the same `generate_game_assets` image pipeline. These are
2D images applied to geometry; they are not 3D models and do not create a new
tool type.

| 3D role | Existing type | Required description/runtime contract |
|---|---|---|
| skybox | `background` | equirectangular sky texture, `1024*1024`, no background removal |
| surface texture | `image` | seamless or centered surface art, runtime display/source <= `1024*1024` |
| billboard sprite | `image` | one centered subject, transparent background/removal allowed |
| circular floor patch | `image` | top-down circular patch, transparent outside edge |

- Asset Registry `displaySize` remains GDD/runtime metadata; never pass it as
an unsupported MCP parameter. Source textures and declared display size must
not exceed `1024*1024`.
- Keep every 3D image in the normal Asset Registry/display list and generated
`asset-pack.json`; key and URL consistency rules below are unchanged.
- `colormap` is allowed only for matte/non-glossy art. Never colormap glossy,
translucent, emissive, metallic, or skybox art.
- Allowed runtime consumers are `Texture`, `MeshStandardMaterial.map`, scene
background, and `SpriteMaterial`. Never request GLB/FBX/OBJ, normal maps,
model generation, or a text-to-3D API.

**CRITICAL — Parameter restrictions:**

- `type: "image"` accepts ONLY `key` and `description`. **Do NOT pass `size`, `resolution`, or any other parameter** — the output is always 386\*560 PNG. Game code scales the image via `setScale()` or `setDisplaySize()`. Icons, projectiles, and small sprites all use the same output size; scale in code.
Expand Down
62 changes: 62 additions & 0 deletions agent-test/docs/modules/threed_basic/design_rules.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# threed_basic Design Rules

## 1. Product shape

Build one short, finishable 3D route: the player moves through a single world,
collects every required item, and reaches one completion state. Use three.js,
simple geometry, lights, fog, a sky texture, and DOM overlays.

Do not add physics, touch controls, multiplayer, imported 3D models, or any
text-to-3D service. 2D Phaser templates are unrelated and must remain unchanged.

## 2. Required runtime contract

| Area | Required |
|---|---|
| Renderer | `WebGLRenderer`, `PerspectiveCamera`, resize handling, visible non-black frame |
| World | primitives or custom low-poly geometry, ambient + directional light, fog |
| Collision | player circle stays on an authored floor patch and outside static obstacle circles |
| Input | WASD and arrow keys; mouse drag/look; ESC pause |
| HUD | DOM in `#ui-root`; canvas stays dedicated to three.js |
| Pause | resolve `gameSceneKey ?? currentLevelKey ?? LevelManager.getFirstLevelScene()` |
| Win | one explicit, reachable completion condition |

## 3. Asset registry rules

3D assets are still ordinary images produced by `generate_game_assets`.

| Key role | Tool type | Max/source rule | three.js use |
|---|---|---|---|
| `skybox_texture` | `background` | `1024*1024`; `displaySize: 1024*1024` in GDD | equirectangular scene background |
| `floor_patch` | `image` | generated image; declare display size <= `1024*1024` | `CircleGeometry` material map |
| `energy_billboard` | `image` | one centered subject, transparent removal allowed | `SpriteMaterial` |
| surface texture | `image` | <= `1024*1024`; no glossy colormap | `MeshStandardMaterial.map` |

Never request a model, mesh, GLB, FBX, normal map, or text-to-3D output. Do not
use `colormap` for glossy, translucent, emissive, or sky assets.

## 4. Level and camera budget

Use 8-14 floor patches, 5-10 collectibles, and 8-16 low-poly decorations.
Keep the camera far plane under 250 and cap device pixel ratio at 2. Manual
distance checks are enough for pickups and static collision; do not introduce a
physics dependency. Give every obstacle an explicit `collisionRadius` instead
of deriving gameplay collision from rendered scale.

Every `gameConfig.json` leaf must have one literal runtime consumer. Do not keep
aliases for the same value: if pickup code moves from
`levelConfig.collectRadius` to another path, delete the old leaf in the same
edit. The current linear fog consumes `renderConfig.fogNear` and `fogFar`; do
not add `fogDensity` unless the implementation changes and the superseded
linear-fog leaves are removed. Derive authored counts from `SceneMap` arrays
unless a separately consumed completion threshold is required.

## 5. GDD completion notes

The GDD must end with:

- the actual generated keys and their runtime consumers;
- a config leaf-to-consumer table with no duplicate or unconsumed leaf;
- any placeholder/fallback used;
- `3D scope: primitives + generated image textures; no model generation`;
- the command evidence from build and smoke.
81 changes: 81 additions & 0 deletions agent-test/docs/modules/threed_basic/template_api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# threed_basic Template API

## Scaffolded files

| File | Contract |
|---|---|
| `src/main.ts` | boots title, runtime, DOM HUD, pause, completion, render loop |
| `src/GameScene.ts` | owns renderer, scene, camera, world, manual pickup checks |
| `src/CollisionResolver.ts` | pure XZ road/obstacle movement resolution with substeps |
| `src/InputController.ts` | keyboard + mouse state only |
| `src/SceneMap.ts` | Editor-facing declarative positions via `initSceneMap()` |
| `src/ThreeSceneDefaults.ts` | shared light, fog, and background defaults |
| `src/gameConfig.json` | wrapped `{ value, type, description }` tuning fields |

## `GameScene` constructor

```ts
new GameScene(container, {
onProgress(collected, total) {},
onComplete() {},
onGameOver() {},
}, preloader.textures);
```

Required public methods:

| Method | Meaning |
|---|---|
| `update(deltaSeconds)` | advance input, collection, animation, and render |
| `setPaused(boolean)` | stop/resume simulation and clear held input |
| `isPaused()` | smoke/lifecycle observable pause state |
| `resize()` | update camera aspect and renderer size |

## SceneMap

`initSceneMap()` returns `playerSpawn`, `floorPatches`, `collectibles`, and `obstacles`.
Change positions there instead of hard-coding level coordinates inside the
render loop. Add new declarative arrays at the `// EXT` point only when a real
consumer is implemented.

Each obstacle declares `collisionRadius` independently from visual `scale`.
`resolveMovement()` keeps the full player circle inside at least one floor
patch, subdivides long moves to prevent tunnelling, and slides along an
unblocked axis. Dynamic bodies, impulses, and gravity remain v2 concerns.

## Config ownership

The shipped config is a starting contract, not a compatibility registry. Keep
one leaf per runtime value and require a literal consumer for every leaf. When
renaming or regrouping a field, update its consumer and delete the old field in
the same change. Do not preserve unused 2D infrastructure fields in a 3D game.

Before build, search every config leaf outside `gameConfig.json`. A leaf with no
consumer is a failed implementation check, not a harmless preset.

## Texture keys

`Preloader` reads Phaser-compatible `asset-pack.json` sections and loads image
entries into `Map<string, THREE.Texture>`. The reference module recognizes:

| Key | Fallback |
|---|---|
| `skybox_texture` | dark blue `Color` background |
| `floor_patch` | rough blue material |
| `energy_billboard` | emissive sphere primitive |

Missing optional textures must not throw or block the game.

## Pause data contract

Both `UIScene.init()` and `PauseUIScene.init()` accept:

```ts
{ gameSceneKey?: string; currentLevelKey?: string }
```

Resolve in this exact order:

```ts
data.gameSceneKey ?? data.currentLevelKey ?? LevelManager.getFirstLevelScene()
```
68 changes: 68 additions & 0 deletions agent-test/docs/modules/threed_basic/threed_basic.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# threed_basic Implementation Manual

Read this file and every scaffolded `src/` file before editing the generated
game. Keep the reference lifecycle intact; customize data, materials, text,
and the one level rather than replacing the shell.

## Phase 5 implementation order

| Order | Action | Done when |
|---|---|---|
| 1 | map GDD asset keys to `skybox_texture`, `floor_patch`, `energy_billboard` | every used key exists in `asset-pack.json` |
| 2 | edit `SceneMap.ts` | main route and every pickup are reachable; obstacle collision radii leave a traversable lane |
| 3 | merge tuning into `gameConfig.json` | every leaf has one runtime consumer; superseded aliases are deleted |
| 4 | theme materials and DOM text | canvas remains WebGL-only; HUD remains DOM-only |
| 5 | run build and smoke | zero errors, non-black canvas, WebGL context, ESC resume |

## Runtime lifecycle

```text
Preloader.load -> TitleScreen.show -> GameScene constructor
-> applyThreeSceneDefaults -> initSceneMap -> HUD.show
-> requestAnimationFrame -> GameScene.update -> resolveMovement -> renderer.render
-> all collectibles removed -> onComplete -> GameCompleteUIScene
```

`deltaSeconds` is capped by `main.ts`; all movement must multiply by it.
`setPaused(true)` must clear input so a key held before pause cannot continue
moving after resume.

Keep `CollisionResolver.ts` pure. Floor patches and obstacle circles come from
`SceneMap.ts`; player radius comes from `gameConfig.json`. Do not replace this
with a physics dependency in v1.

Treat config as executable data. Keep the existing path when it already serves
the intended value; if a generated design chooses a new path, update the code
and remove the old path together. Never add `fogDensity`, a second pickup
radius, or a duplicate collectible count while their existing equivalents stay
in the file. Record the final leaf-to-consumer mapping in GDD completion notes.

## Asset hookup

Only call `generate_game_assets`. A skybox is a generated 2D equirectangular
image, floor art is a generated 2D patch/texture, and an energy marker is a
generated billboard sprite. Do not call shell image tools or any 3D model API.

If a texture is unavailable, keep the supplied primitive fallback and append
the fallback key to the GDD Asset Degradation Log. The fallback makes the game
playable; it does not authorize skipping the required asset call.

## Manual play check

1. Press Enter on the title screen.
2. Move with W/A/S/D or arrow keys; drag the mouse to look.
3. Press ESC, confirm the pause overlay, then ESC again and confirm movement.
4. Follow the single route and collect all energy markers.
5. Confirm `TRAIL COMPLETE`, then verify restart.

## Frequent failures

| Symptom | Root cause | Fix |
|---|---|---|
| black canvas, no console error | level never rendered after title | keep the RAF loop and call `renderer.render` every active frame |
| ESC overlay opens but game stays paused | wrong scene key | use the three-key fallback contract exactly |
| image 404s | invented key or leading slash mismatch | read the generated `asset-pack.json`; use its key/url |
| movement depends on frame rate | raw per-frame displacement | multiply by capped `deltaSeconds` |
| player leaves the road or crosses a pylon | movement bypasses `resolveMovement` or collision radii are missing | route every XZ move through the resolver and keep SceneMap radii explicit |
| acceptance reports dead config | a field was copied or renamed without removing its old path | keep one canonical leaf, update its consumer, and delete the duplicate |
| huge GPU cost | uncapped DPR or oversized textures | DPR <= 2; texture/display size <= 1024 squared |
3 changes: 3 additions & 0 deletions agent-test/templates/core3d/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
dist
shots
10 changes: 10 additions & 0 deletions agent-test/templates/core3d/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# OpenGame core3d template

Minimal three.js + TypeScript + Vite shell. It preserves the existing DOM
screen contract while keeping 3D rendering isolated from every Phaser template.

```bash
npm ci
npm run build
npm run dev
```
13 changes: 13 additions & 0 deletions agent-test/templates/core3d/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenGame 3D</title>
</head>
<body>
<main id="game-container" aria-label="3D game"></main>
<div id="ui-root"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Loading