Skip to content

Commit 79b3c94

Browse files
author
DavidQ
committed
Finish Asteroids engine-owned chrome and add font manifest asset - PR 11.90
1 parent 5449506 commit 79b3c94

10 files changed

Lines changed: 186 additions & 105 deletions

docs/dev/codex_commands.md

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
1-
# Codex command
1+
# Codex Commands — PR 11.90
22

3-
Run from repo root:
3+
Model: GPT-5.4
4+
Reasoning: high
45

5-
```powershell
6-
codex exec --model gpt-5.4-codex --reasoning high --sandbox workspace-write --ask-for-approval never @docs/pr/BUILD_PR_LEVEL_11_89_ASTEROIDS_ENGINE_RENDER_OWNERSHIP_STABILIZATION.md
7-
```
8-
9-
## Required output from Codex
10-
Codex must create a ZIP artifact at:
6+
Run Codex with this task:
117

128
```text
13-
C:\Users\davidq\Documents\GitHub\HTML-JavaScript-Gaming\tmp\PR_11_89_ASTEROIDS_ENGINE_RENDER_OWNERSHIP_STABILIZATION.zip
14-
```
9+
Apply PR 11.90 from docs/pr/PR_11_90_ASTEROIDS_ENGINE_OWNERSHIP_AND_FONT_MANIFEST.md.
1510
16-
The ZIP must include changed repo files and:
17-
- docs/pr/PLAN_PR_LEVEL_11_89_ASTEROIDS_ENGINE_RENDER_OWNERSHIP_STABILIZATION.md
18-
- docs/pr/BUILD_PR_LEVEL_11_89_ASTEROIDS_ENGINE_RENDER_OWNERSHIP_STABILIZATION.md
19-
- docs/dev/reports/pr_11_89_asteroids_engine_render_ownership_report.md
20-
- docs/dev/codex_commands.md
21-
- docs/dev/commit_comment.txt
11+
Use the uploaded Asteroids.zip inspection findings as evidence. Finish Asteroids engine ownership correctness: remove remaining game-level background/clear/bezel ownership, keep gameplay-only rendering in Asteroids, make game.manifest.json the only source for bezel/background/font assets, add font.asteroids.vector-battle under asset-browser.assets, set image.asteroids.bezel to bezel1.png with stretchOverride.uniformEdgeStretchPx=10, set image.asteroids.background to deluxe.png, and verify no guessed chrome asset paths remain.
12+
13+
Return a repo-structured ZIP at <project folder>/tmp/PR_11_90_ASTEROIDS_ENGINE_OWNERSHIP_AND_FONT_MANIFEST.zip with changed files and a short validation report.
14+
```

docs/dev/commit_comment.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Finish Asteroids engine-owned background/bezel layering and manifest-only chrome loading - PR 11.89
1+
Finish Asteroids engine-owned chrome and add font manifest asset - PR 11.90
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Asteroids.zip Inspection Report
2+
3+
Inspected uploaded `Asteroids.zip`.
4+
5+
## Remaining overrides found
6+
7+
- `game/AsteroidsGameScene.js` calls `renderer.drawRect(0, 0, this.world.bounds.width, this.world.bounds.height, ...)` at the start of `render()`.
8+
- `game/AsteroidsAttractAdapter.js` calls `renderer.drawRect(0, 0, 960, 720, ...)` in `render()`.
9+
- `game/FullscreenBezelOverlay.js` contains Asteroids-specific fullscreen bezel path resolution and rendering behavior. This duplicates the engine-owned chrome layer unless fully delegated to the engine.
10+
11+
## Manifest findings
12+
13+
- `assets/fonts/vector_battle.ttf` exists.
14+
- No `font.*` entry exists in `game.manifest.json` under `asset-browser.assets`.
15+
- `image.asteroids.background` points to `/games/Asteroids/assets/images/deluxe.png`.
16+
- `image.asteroids.bezel` currently points to `/games/Asteroids/assets/images/bezel.png`; the requested SSoT path is `/games/Asteroids/assets/images/bezel1.png`.
17+
18+
## Required resolution
19+
20+
Asteroids should keep gameplay visuals only. Engine should own background, bezel, clear behavior, asset loading, and chrome layering.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# PR 11.90 Validation
2+
3+
## Scope
4+
Applied `docs/pr/PR_11_90_ASTEROIDS_ENGINE_OWNERSHIP_AND_FONT_MANIFEST.md` using the uploaded Asteroids.zip findings as the baseline evidence.
5+
6+
## Files Changed
7+
- `games/Asteroids/game.manifest.json`
8+
- `games/Asteroids/game/AsteroidsGameScene.js`
9+
- `games/Asteroids/game/AsteroidsAttractAdapter.js`
10+
- `games/Asteroids/game/FullscreenBezelOverlay.js`
11+
- `games/Asteroids/assets/images/bezel1.png`
12+
- `docs/dev/reports/pr_11_90_validation.md`
13+
14+
## What Was Fixed
15+
- Manifest SSoT updates:
16+
- `image.asteroids.bezel.path` set to `/games/Asteroids/assets/images/bezel1.png`
17+
- `image.asteroids.background.path` set to `/games/Asteroids/assets/images/deluxe.png`
18+
- `image.asteroids.bezel.stretchOverride.uniformEdgeStretchPx` remains `10`
19+
- Added `font.asteroids.vector-battle` under `asset-browser.assets.media`:
20+
- `/games/Asteroids/assets/fonts/vector_battle.ttf`
21+
- Removed remaining game-level frame background ownership:
22+
- Removed full-canvas background draw from `AsteroidsGameScene.render()`.
23+
- Removed game-level full-frame attract dim ownership:
24+
- Removed full-canvas attract overlay fill from `AsteroidsAttractAdapter.render()`.
25+
- Deprecated game-local bezel renderer path:
26+
- `FullscreenBezelOverlay` now no-ops with `reason: deprecated-engine-owned` to avoid duplicate chrome ownership.
27+
28+
## Targeted Validation
29+
- Syntax checks:
30+
- `node --check games/Asteroids/game/AsteroidsGameScene.js` PASS
31+
- `node --check games/Asteroids/game/AsteroidsAttractAdapter.js` PASS
32+
- `node --check games/Asteroids/game/FullscreenBezelOverlay.js` PASS
33+
- Manifest verification:
34+
- `rg -n "image.asteroids.bezel|image.asteroids.background|font.asteroids.vector-battle|bezel1.png|deluxe.png|stretchOverride" games/Asteroids/game.manifest.json`
35+
- Confirmed expected entries/values.
36+
- Forbidden guessed path search:
37+
- `rg -n "/games/Asteroids/assets/images/bezel\.png|/games/Asteroids/assets/images/background\.png|/games/SolarSystem/assets/images/bezel\.png|/games/SolarSystem/assets/images/background\.png" src games tools -g "*.js" -g "*.mjs" -g "*.json" -g "*.html"`
38+
- No matches in active source/runtime scope.
39+
- Engine utils literal reference search:
40+
- `rg -n "src/engine/utils/|/src/engine/utils/" src games -g "*.js" -g "*.mjs" -g "*.json" -g "*.html"`
41+
- No matches.
42+
- Runtime launch check:
43+
- `npm run test:launch-smoke:games` PASS (12/12, including Asteroids and SolarSystem).
44+
45+
## Notes
46+
- Full sample suite was not run (targeted validation only, per PR scope).
47+
- Manual browser state-by-state visual verification was not executed in this CLI-only run; automated launch smoke and code-path checks were used as evidence.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# PR 11.90 — Asteroids Engine Ownership and Font Manifest Repair
2+
3+
## Purpose
4+
Finish Asteroids alignment with the engine-owned render/chrome contract and add the Asteroids font to the asset-browser manifest assets.
5+
6+
## Findings from uploaded Asteroids.zip
7+
8+
The uploaded Asteroids game still contains game-level render/chrome overrides:
9+
10+
1. `games/Asteroids/game/AsteroidsGameScene.js` still draws a full-screen rect at the start of `render()`.
11+
- This means Asteroids still controls the frame background/clear layer.
12+
- When a manifest background exists, the fill is translucent, but the game is still overriding engine-owned background layering.
13+
14+
2. `games/Asteroids/game/AsteroidsAttractAdapter.js` still draws a full-screen attract overlay.
15+
- It is translucent when a manifest background exists, but it is still a full-frame game overlay that can visually suppress the engine background.
16+
- Keep only intentional text/sprite/menu visuals; do not use an opaque/near-opaque frame fill as a background substitute.
17+
18+
3. `games/Asteroids/game/FullscreenBezelOverlay.js` still contains Asteroids-specific bezel resolution.
19+
- Bezel/background should be engine-owned and manifest-driven.
20+
- Remove/deprecate game-local fullscreen bezel loading/rendering when the engine chrome layer provides this behavior.
21+
22+
4. `games/Asteroids/game.manifest.json` has the bezel path set to `/games/Asteroids/assets/images/bezel.png`.
23+
- The desired Asteroids bezel is `/games/Asteroids/assets/images/bezel1.png`.
24+
- Keep `stretchOverride.uniformEdgeStretchPx = 10` only on `image.asteroids.bezel`.
25+
26+
5. `games/Asteroids/assets/fonts/vector_battle.ttf` exists, but no font asset entry is present in `asset-browser.assets`.
27+
28+
## Required changes
29+
30+
### Manifest assets
31+
Update `games/Asteroids/game.manifest.json`:
32+
33+
- Ensure `asset-browser.assets.image.asteroids.bezel.path` is `/games/Asteroids/assets/images/bezel1.png`.
34+
- Ensure `asset-browser.assets.image.asteroids.background.path` is `/games/Asteroids/assets/images/deluxe.png`.
35+
- Ensure `asset-browser.assets.image.asteroids.bezel.stretchOverride.uniformEdgeStretchPx` is `10`.
36+
- Add a font asset entry:
37+
38+
```json
39+
"font.asteroids.vector-battle": {
40+
"path": "/games/Asteroids/assets/fonts/vector_battle.ttf",
41+
"kind": "font",
42+
"source": "workspace-manager"
43+
}
44+
```
45+
46+
Do not place font data outside `asset-browser.assets`.
47+
48+
### Engine ownership
49+
Asteroids must not own engine chrome/background/clear responsibilities.
50+
51+
Codex must remove or neutralize these remaining overrides:
52+
53+
- `AsteroidsGameScene.render()` full-screen background/clear fill.
54+
- `AsteroidsAttractAdapter.render()` full-screen dark frame fill when a manifest background exists.
55+
- Any Asteroids-local bezel/background loader/renderer that duplicates engine chrome responsibilities, especially `FullscreenBezelOverlay.js`, unless it is still directly required and only delegates to the engine manifest chrome layer.
56+
57+
Gameplay rendering remains in Asteroids:
58+
59+
- ships
60+
- asteroids
61+
- bullets
62+
- saucers
63+
- score/lives/menu/high-score text
64+
- intentional game-specific vector visuals
65+
66+
### No fallback asset guessing
67+
Do not introduce fallback paths such as:
68+
69+
- `/games/Asteroids/assets/images/bezel.png`
70+
- `/games/Asteroids/assets/images/background.png`
71+
- `/games/SolarSystem/assets/images/bezel.png`
72+
- `/games/SolarSystem/assets/images/background.png`
73+
74+
Game chrome assets must resolve only through manifest asset ids.
75+
76+
## Acceptance
77+
78+
- `game.manifest.json` includes font, bezel, and background assets under `asset-browser.assets`.
79+
- `image.asteroids.bezel` uses `bezel1.png`.
80+
- `image.asteroids.background` uses `deluxe.png`.
81+
- `image.asteroids.bezel.stretchOverride.uniformEdgeStretchPx` is `10`.
82+
- There is no `asset-browser.assets.bezel` duplicate contract.
83+
- Asteroids no longer draws an engine-owned background/clear layer.
84+
- Asteroids no longer uses game-local bezel/background loading/rendering that bypasses the engine manifest layer.
85+
- No 404s for bezel/background/font assets.
86+
- Background is visible in menu, attract, pause, and gameplay.
87+
- Bezel is visible and stretched using the manifest SSoT value.
88+
89+
## Testing
90+
91+
Run targeted tests only. Do not run the full samples smoke test.
92+
93+
1. Open `games/Asteroids/index.html`.
94+
2. Confirm menu/attract/gameplay/pause all keep the manifest background visible.
95+
3. Confirm the bezel renders from `image.asteroids.bezel`.
96+
4. Confirm no console 404s for chrome assets or font.
97+
5. Search repo for forbidden paths and stale references.
389 KB
Loading

games/Asteroids/game.manifest.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,13 @@
181181
"kind": "audio",
182182
"source": "workspace-manager"
183183
},
184+
"font.asteroids.vector-battle": {
185+
"path": "/games/Asteroids/assets/fonts/vector_battle.ttf",
186+
"kind": "font",
187+
"source": "workspace-manager"
188+
},
184189
"image.asteroids.bezel": {
185-
"path": "/games/Asteroids/assets/images/bezel.png",
190+
"path": "/games/Asteroids/assets/images/bezel1.png",
186191
"kind": "image",
187192
"source": "workspace-manager",
188193
"stretchOverride": {

games/Asteroids/game/AsteroidsAttractAdapter.js

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -238,20 +238,12 @@ export default class AsteroidsAttractAdapter {
238238
});
239239
}
240240

241-
render(renderer, options = {}) {
241+
render(renderer) {
242242
if (!this.active) {
243243
return;
244244
}
245245

246246
const alpha = this.getPhaseAlpha();
247-
const manifestBackgroundPresent = options?.manifestBackgroundPresent === true;
248-
renderer.drawRect(
249-
0,
250-
0,
251-
960,
252-
720,
253-
manifestBackgroundPresent ? 'rgba(2, 6, 23, 0.36)' : 'rgba(2, 6, 23, 0.86)'
254-
);
255247

256248
if (this.phase === 'title') {
257249
this.renderTitle(renderer, alpha);

games/Asteroids/game/AsteroidsGameScene.js

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -95,17 +95,6 @@ function drawLives(renderer, centerX, y, lives) {
9595
});
9696
}
9797

98-
function hasManifestBackgroundLayer(engine) {
99-
const state = engine?.backgroundImageLayer?.getState?.();
100-
if (!state || typeof state !== 'object') {
101-
return false;
102-
}
103-
return typeof state.path === 'string'
104-
&& state.path.trim().length > 0
105-
&& state.status !== 'missing'
106-
&& state.status !== 'unavailable';
107-
}
108-
10998
export default class AsteroidsGameScene extends Scene {
11099
constructor(options = {}) {
111100
super();
@@ -702,14 +691,6 @@ export default class AsteroidsGameScene extends Scene {
702691
render(renderer, engine) {
703692
const leaderboardTopScore = this.highScoreService.getTopScore(this.highScoreRows);
704693
const liveHudHighScore = Math.max(this.session.highScore, leaderboardTopScore);
705-
const manifestBackgroundPresent = hasManifestBackgroundLayer(engine);
706-
renderer.drawRect(
707-
0,
708-
0,
709-
this.world.bounds.width,
710-
this.world.bounds.height,
711-
manifestBackgroundPresent ? 'rgba(2, 6, 23, 0.22)' : '#020617'
712-
);
713694
this.world.starfield.forEach((star) => {
714695
renderer.drawRect(star.x, star.y, star.size, star.size, '#94a3b8');
715696
});
@@ -780,9 +761,7 @@ export default class AsteroidsGameScene extends Scene {
780761

781762
if (this.session.mode === 'menu') {
782763
if (this.attractController.active) {
783-
this.attractAdapter.render(renderer, {
784-
manifestBackgroundPresent
785-
});
764+
this.attractAdapter.render(renderer);
786765
} else {
787766
renderer.drawText('ASTEROIDS', 480, 220, {
788767
color: '#ffffff',

games/Asteroids/game/FullscreenBezelOverlay.js

Lines changed: 4 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,7 @@ export default class FullscreenBezelOverlay {
4646
}
4747

4848
ensureImageLoaded() {
49-
if (!this.enabled || this.image || this.imageLoadStarted || typeof Image !== "function") {
50-
return;
51-
}
52-
53-
this.imageLoadStarted = true;
54-
const image = new Image();
55-
image.onload = () => {
56-
this.image = image;
57-
this.imageStatus = "loaded";
58-
};
59-
image.onerror = () => {
60-
this.imageStatus = "error";
61-
};
62-
image.src = this.assetPath;
63-
this.imageStatus = "loading";
49+
this.imageStatus = "deprecated-engine-owned";
6450
}
6551

6652
evaluateRenderGate(options = {}) {
@@ -86,49 +72,11 @@ export default class FullscreenBezelOverlay {
8672
}
8773

8874
render(renderer, options = {}) {
89-
const gate = this.evaluateRenderGate(options);
90-
if (!gate.allowed) {
91-
return {
92-
drawn: false,
93-
...gate,
94-
assetPath: this.assetPath
95-
};
96-
}
97-
98-
this.ensureImageLoaded();
99-
const image = options.image || this.image;
100-
if (!image || typeof renderer?.drawImageFrame !== "function") {
101-
return {
102-
drawn: false,
103-
reason: "image-unavailable",
104-
drawMode: this.drawMode,
105-
assetPath: this.assetPath
106-
};
107-
}
108-
109-
const canvasSize = renderer?.getCanvasSize?.() || options.canvasSize || { width: 0, height: 0 };
110-
const width = Number(canvasSize.width) > 0 ? Number(canvasSize.width) : 0;
111-
const height = Number(canvasSize.height) > 0 ? Number(canvasSize.height) : 0;
112-
if (width <= 0 || height <= 0) {
113-
return {
114-
drawn: false,
115-
reason: "invalid-canvas-size",
116-
drawMode: this.drawMode,
117-
assetPath: this.assetPath
118-
};
119-
}
120-
121-
const sourceWidth = Number(image.width) > 0 ? Number(image.width) : width;
122-
const sourceHeight = Number(image.height) > 0 ? Number(image.height) : height;
123-
renderer.drawImageFrame(image, 0, 0, sourceWidth, sourceHeight, 0, 0, width, height);
12475
return {
125-
drawn: true,
126-
drawMode: this.drawMode,
127-
fullscreenOnly: true,
128-
coordinateSpace: "screen-space",
76+
drawn: false,
77+
reason: "deprecated-engine-owned",
12978
assetPath: this.assetPath,
130-
width,
131-
height
79+
drawMode: this.drawMode
13280
};
13381
}
13482
}

0 commit comments

Comments
 (0)