Skip to content
Merged
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
9 changes: 9 additions & 0 deletions agent-test/docs/modules/threed_basic/design_rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,20 @@ 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.
10 changes: 10 additions & 0 deletions agent-test/docs/modules/threed_basic/template_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,16 @@ Each obstacle declares `collisionRadius` independently from visual `scale`.
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
Expand Down
9 changes: 8 additions & 1 deletion agent-test/docs/modules/threed_basic/threed_basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ and the one level rather than replacing the shell.
|---|---|---|
| 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` | wrapper shape and core fields remain |
| 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 |

Expand All @@ -31,6 +31,12 @@ 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
Expand Down Expand Up @@ -58,4 +64,5 @@ playable; it does not authorize skipping the required asset call.
| 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 |
4 changes: 0 additions & 4 deletions agent-test/templates/core3d/src/gameConfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
{
"screenSize": {
"width": { "value": 1152, "type": "number", "description": "Reference width" },
"height": { "value": 768, "type": "number", "description": "Reference height" }
},
"renderConfig": {
"pixelRatioCap": { "value": 2, "type": "number", "description": "Renderer pixel ratio cap" },
"fogNear": { "value": 18, "type": "number", "description": "Fog near distance" },
Expand Down
4 changes: 0 additions & 4 deletions agent-test/templates/modules/threed_basic/src/gameConfig.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
{
"screenSize": {
"width": { "value": 1152, "type": "number", "description": "Reference width" },
"height": { "value": 768, "type": "number", "description": "Reference height" }
},
"renderConfig": {
"pixelRatioCap": { "value": 2, "type": "number", "description": "Renderer pixel ratio cap" },
"fogNear": { "value": 16, "type": "number", "description": "Fog near distance" },
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/tools/generate-gdd.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest';
import { configMergeInstruction } from './generate-gdd.js';

describe('configMergeInstruction', () => {
it('requires consumed config and deletion of superseded 3D leaves', () => {
const instruction = configMergeInstruction('threed_basic');

expect(instruction).toContain('every leaf must have a runtime consumer');
expect(instruction).toContain('superseded leaves must be removed');
expect(instruction).not.toContain('NEVER delete infrastructure fields');
});

it.each(['platformer', 'top_down'] as const)(
'preserves the existing Phaser config contract for %s',
(archetype) => {
const instruction = configMergeInstruction(archetype);

expect(instruction).toContain('NEVER delete infrastructure fields');
expect(instruction).toContain('screenSize');
expect(instruction).toContain('debugConfig');
},
);
});
9 changes: 8 additions & 1 deletion packages/core/src/tools/generate-gdd.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@ export interface GenerateGDDParams {
config_summary?: string;
}

export function configMergeInstruction(archetype: GameArchetype): string {
if (archetype === 'threed_basic') {
return '- MERGE GDD Section 2 values INTO the existing `src/gameConfig.json`; every leaf must have a runtime consumer, and renamed or superseded leaves must be removed in the same edit.';
}
return '- MERGE GDD Section 2 values INTO the existing `src/gameConfig.json` -- add/update game-specific fields using `{ "value": X }` wrapper format, but NEVER delete infrastructure fields (`screenSize`, `renderConfig`, and Phaser\'s `debugConfig`)';
}

export interface GDDModelConfig {
apiKey: string;
baseUrl: string;
Expand Down Expand Up @@ -116,7 +123,7 @@ Save content between <gdd-content> tags to \`GAME_DESIGN.md\`
- Read \`public/assets/asset-pack.json\` for generated texture keys

### Phase 4: Config (use GDD Section 2)
- MERGE GDD Section 2 values INTO the existing \`src/gameConfig.json\` -- add/update game-specific fields using \`{ "value": X }\` wrapper format, but NEVER delete infrastructure fields (\`screenSize\`, \`renderConfig\`, and Phaser's \`debugConfig\`)
${configMergeInstruction(this.params.archetype)}

### Phase 5: Code Implementation (use GDD Sections 0, 3, 5)
- **GDD Section 0** has scene keys -> update \`LevelManager.ts\` and \`main.ts\`
Expand Down