Skip to content

Commit 643d065

Browse files
author
DavidQ
committed
Standardize bezel/background conventions and align template
BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION
1 parent 5c493c5 commit 643d065

11 files changed

Lines changed: 212 additions & 80 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 19 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,23 @@
1+
12
MODEL: GPT-5.4
23
REASONING: high
34

45
COMMAND:
5-
Create `BUILD_PR_LEVEL_10_21_VERIFY_CENTERED_CANVAS_BEZEL_AND_GAMEPLAY_BACKGROUND`.
6-
7-
Verify the completed Asteroids fullscreen bezel and gameplay-background implementation end to end.
8-
9-
Validation targets:
10-
11-
1. Centered canvas
12-
- internal resolution unchanged
13-
- canvas remains centered
14-
- no distortion in fullscreen
15-
- no viewport-stretch behavior
16-
17-
2. Bezel
18-
- no duplicated path resolution
19-
- HTML-layer rendering
20-
- visible only in fullscreen
21-
- visible on screen
22-
- transparency-window fit rule is active
23-
- shared stretch override is honored
24-
25-
3. Override file
26-
- if bezel exists and
27-
`games/<game>/assets/images/bezel.stretch.override.json`
28-
is missing,
29-
auto-create it during startup/init before gameplay
30-
- do not overwrite existing file
31-
32-
4. Background
33-
- separate from bezel
34-
- gameplay only
35-
- after clear
36-
- before starfield/world
37-
- visible during gameplay
38-
- absent during non-gameplay states
39-
40-
5. If validation finds real defects
41-
- make only the smallest required surgical fixes
42-
- do not expand scope
43-
44-
6. Final packaging step is REQUIRED
45-
- package ALL changed files into this exact repo-structured ZIP:
46-
`<project folder>/tmp/BUILD_PR_LEVEL_10_21_VERIFY_CENTERED_CANVAS_BEZEL_AND_GAMEPLAY_BACKGROUND.zip`
47-
48-
Hard rules:
49-
- verification-focused PR
50-
- keep fixes minimal
51-
- no unrelated repo changes
52-
- no missing ZIP
6+
Create `BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION`
7+
8+
1. Align games/_template structure with Asteroids asset conventions
9+
2. Ensure shared pipeline handles:
10+
- backgroundImage (gameplay-only)
11+
- fullscreenBezel (fullscreen-only HTML layer)
12+
3. Ensure override file:
13+
- auto-created at startup if bezel exists
14+
- not overwritten
15+
4. Remove any game-specific coupling from shared code
16+
5. Validate across template + Asteroids
17+
18+
Package:
19+
<project folder>/tmp/BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION.zip
20+
21+
Rules:
22+
- minimal changes
23+
- no unrelated edits

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Verify centered canvas, fullscreen bezel, override creation, and gameplay background
2-
BUILD_PR_LEVEL_10_21_VERIFY_CENTERED_CANVAS_BEZEL_AND_GAMEPLAY_BACKGROUND
1+
Standardize bezel/background conventions and align template
2+
BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION

docs/dev/NEXT_COMMAND.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION
1+
BUILD_PR_LEVEL_10_23_MULTI_GAME_VALIDATION_PASS
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
- Added verification PR for completed Asteroids bezel/background work
2-
- Focused on centered canvas, fullscreen bezel visibility, override-file creation, and gameplay-only background
3-
- Allows only minimal surgical fixes if validation finds real defects
1+
- Standardized bezel/background conventions
2+
- Aligned template structure
3+
- Ensured override auto-create behavior
Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
- Canvas internal size unchanged
2-
- Canvas remains centered
3-
- Bezel path not duplicated
4-
- Bezel visible only in fullscreen
5-
- Bezel visible on screen
6-
- Stretch override honored
7-
- Missing override file auto-created before gameplay
8-
- Existing override file preserved
9-
- Background draws only during gameplay
10-
- Background draws after clear and before starfield/world
11-
- Output ZIP path:
12-
<project folder>/tmp/BUILD_PR_LEVEL_10_21_VERIFY_CENTERED_CANVAS_BEZEL_AND_GAMEPLAY_BACKGROUND.zip
1+
2+
- Template structure matches Asteroids
3+
- Background gameplay-only
4+
- Bezel fullscreen-only
5+
- Override file auto-created
6+
- No game-specific coupling
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
2+
# BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION
3+
4+
## Purpose
5+
Standardize bezel + background behavior across all games and align `games/_template` with Asteroids conventions.
6+
7+
## Scope
8+
9+
### A. Template alignment
10+
- Ensure `games/_template` includes:
11+
- assets/images/background.png (optional)
12+
- assets/images/bezel.png (optional)
13+
- assets/images/bezel.stretch.override.json (auto-created behavior defined)
14+
15+
### B. Background convention
16+
- `backgroundImage`
17+
- canvas-rendered
18+
- draws after clear
19+
- draws before all world/gameplay layers
20+
- gameplay-only (not attract/menu/etc)
21+
22+
### C. Bezel convention
23+
- `fullscreenBezel`
24+
- HTML overlay
25+
- fullscreen-only
26+
- uses transparency window fit
27+
- uses shared stretch override
28+
29+
### D. Override behavior
30+
- file: `assets/images/bezel.stretch.override.json`
31+
- auto-created at startup if bezel exists and file missing
32+
- never overwritten
33+
34+
### E. Cross-game rule
35+
- behavior must be consistent across all games
36+
- no Asteroids-specific logic in shared pipeline
37+
38+
## Validation
39+
- template contains correct structure
40+
- new games inherit behavior automatically
41+
- existing games not broken
42+
43+
## Packaging
44+
`<project folder>/tmp/BUILD_PR_LEVEL_10_22_TEMPLATE_BEZEL_BACKGROUND_CONVENTION_FOUNDATION.zip`
45+
46+
## Implementation Delta
47+
- Added shared resolver `resolveBezelStretchOverridePath` in `src/engine/runtime/gameImageConvention.js` so bezel override-path derivation remains centralized and game-agnostic.
48+
- Updated `src/engine/runtime/fullscreenBezel.js` to use that shared resolver (no Asteroids-specific path assumptions).
49+
- Aligned `_template` asset conventions by adding `games/_template/assets/tools.manifest.json` as the template asset-manifest foundation.
50+
- Strengthened template contract validation in `scripts/validate-games-template-contract.mjs` to require `assets/tools.manifest.json`.
51+
- Extended focused runtime tests in `tests/core/BackgroundImageAndFullscreenBezel.test.mjs` to validate:
52+
- Asteroids + `_template` game-agnostic image/bezel convention paths
53+
- startup/detection-based auto-create for `bezel.stretch.override.json` when missing
54+
- non-overwrite behavior when the override file already exists
55+
56+
## Validation Evidence (2026-04-14)
57+
- `node --check src/engine/runtime/gameImageConvention.js` PASS
58+
- `node --check src/engine/runtime/fullscreenBezel.js` PASS
59+
- `node --check tests/core/BackgroundImageAndFullscreenBezel.test.mjs` PASS
60+
- `node --check scripts/validate-games-template-contract.mjs` PASS
61+
- `BackgroundImageAndFullscreenBezel` focused test PASS
62+
- `GamesTemplateContractEnforcement` focused test PASS
63+
- `AsteroidsPresentation` focused regression test PASS
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"schema": "html-js-gaming.game-asset-manifest",
3+
"version": 1,
4+
"gameId": "_template",
5+
"domains": {
6+
"sprites": [],
7+
"tilemaps": [],
8+
"parallax": [],
9+
"vectors": []
10+
}
11+
}

scripts/validate-games-template-contract.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const TEMPLATE_REQUIRED_ASSET_DIRS = [
2727
];
2828
const TEMPLATE_REQUIRED_ASSET_FILES = [
2929
".gitkeep",
30+
"tools.manifest.json",
3031
"parallax/data/.gitkeep",
3132
"sprites/data/.gitkeep",
3233
"tilemaps/data/.gitkeep",

src/engine/runtime/fullscreenBezel.js

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import { resolveGameImageConventionPaths, resolveRuntimeAssetUrl } from "./gameImageConvention.js";
1+
import {
2+
resolveBezelStretchOverridePath,
3+
resolveGameImageConventionPaths,
4+
resolveRuntimeAssetUrl
5+
} from "./gameImageConvention.js";
26

37
const TRANSPARENT_ALPHA_THRESHOLD = 8;
48
const DEFAULT_BEZEL_STRETCH_OVERRIDE_FILENAME = "bezel.stretch.override.json";
@@ -114,15 +118,10 @@ export function sanitizeUniformEdgeStretchPx(value) {
114118
}
115119

116120
export function resolveBezelStretchConfigPath(bezelPath, fileName = DEFAULT_BEZEL_STRETCH_OVERRIDE_FILENAME) {
117-
const normalized = normalizePath(bezelPath).trim();
118-
if (!normalized) {
119-
return "";
120-
}
121-
const slashIndex = normalized.lastIndexOf("/");
122-
if (slashIndex < 0) {
123-
return fileName;
124-
}
125-
return `${normalized.slice(0, slashIndex + 1)}${fileName}`;
121+
return resolveBezelStretchOverridePath({
122+
bezelPath,
123+
fileName
124+
});
126125
}
127126

128127
function parseStretchConfigObject(candidate) {

src/engine/runtime/gameImageConvention.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@ function toImagePath(gameId, fileName) {
2727
return `games/${id}/assets/images/${fileName}`;
2828
}
2929

30+
function resolveSiblingPath(pathValue, fileName) {
31+
const normalizedPath = normalizePath(pathValue);
32+
const normalizedName = safeText(fileName, "");
33+
if (!normalizedPath || !normalizedName) {
34+
return "";
35+
}
36+
37+
const slashIndex = normalizedPath.lastIndexOf("/");
38+
if (slashIndex < 0) {
39+
return normalizedName;
40+
}
41+
42+
return `${normalizedPath.slice(0, slashIndex + 1)}${normalizedName}`;
43+
}
44+
3045
export function resolveRuntimeAssetUrl(pathValue, documentRef = null) {
3146
const normalized = normalizePath(pathValue);
3247
if (!normalized) {
@@ -61,3 +76,10 @@ export function resolveGameImageConventionPaths(options = {}) {
6176
bezelPath: toImagePath(gameId, "bezel.png")
6277
};
6378
}
79+
80+
export function resolveBezelStretchOverridePath(options = {}) {
81+
const fileName = safeText(options.fileName, "bezel.stretch.override.json");
82+
const explicitBezelPath = safeText(options.bezelPath, "");
83+
const bezelPath = explicitBezelPath || resolveGameImageConventionPaths(options).bezelPath;
84+
return resolveSiblingPath(bezelPath, fileName);
85+
}

0 commit comments

Comments
 (0)