Skip to content

Commit a3f1d57

Browse files
author
DavidQ
committed
Define Asteroids manifest loader integration contract
BUILD_PR_LEVEL_10_09_ASTEROIDS_MANIFEST_LOADER_INTEGRATION
1 parent ef0e9ca commit a3f1d57

9 files changed

Lines changed: 232 additions & 14 deletions

docs/dev/CODEX_COMMANDS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
MODEL: GPT-5.3-codex
22
REASONING: medium
3-
COMMAND: Validate manifest structure and wire loader discovery (no engine modification)
3+
COMMAND: Implement manifest loader that reads asteroids.asset.manifest.json and exposes discovery API without modifying engine core

docs/dev/COMMIT_COMMENT.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
Validated Asteroids manifest structure and wired loader discovery via shared pipeline contract.
2-
BUILD_PR_LEVEL_10_08_ASTEROIDS_DATA_MANIFEST_DISCOVERY
1+
Define Asteroids manifest loader integration contract
2+
BUILD_PR_LEVEL_10_09_ASTEROIDS_MANIFEST_LOADER_INTEGRATION

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_09_ASTEROIDS_MANIFEST_LOADER_INTEGRATION
1+
BUILD_PR_LEVEL_10_10_ASTEROIDS_MANIFEST_RUNTIME_HOOK
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1 @@
1-
Implemented Asteroids game asset manifest and shared manifest-discovery contract.
2-
Wired runtime asset lookup to consume validated manifest discovery output when a game manifest is provided.
3-
Added focused manifest discovery test covering structure validation, runtime-safe path enforcement, and lookup integration.
1+
Defined loader integration contract
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
- node --check tools/shared/pipeline/gameAssetManifestDiscovery.js
2-
- node --check tools/shared/pipeline/runtimeAssetLookup.js
3-
- node --check tests/tools/GameAssetManifestDiscovery.test.mjs
4-
- PASS GameAssetManifestDiscovery (focused test)
5-
- PASS RuntimeAssetLookupConsolidation (existing regression check)
6-
- PASS AsteroidsManifestJsonParse
7-
- no engine code modified
1+
- Contract defined
2+
- Codex command present
3+
- No engine changes
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# BUILD_PR_LEVEL_10_09_ASTEROIDS_MANIFEST_LOADER_INTEGRATION
2+
3+
## Purpose
4+
Define loader integration contract for asset manifest discovery.
5+
6+
## Scope
7+
- Define manifest loader contract
8+
- Define discovery interface
9+
- No engine modification
10+
11+
## Testable Outcome
12+
- Contract documented
13+
- Ready for Codex implementation
14+
15+
## Non-Goals
16+
- No runtime wiring yet
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{
2+
"schema": "html-js-gaming.game-asset-manifest",
3+
"version": 1,
4+
"gameId": "asteroids",
5+
"domains": {
6+
"sprites": [
7+
{
8+
"assetId": "sprite.asteroids.demo",
9+
"runtimePath": "games/Asteroids/assets/sprites/asteroids-demo.sprite.json",
10+
"toolDataPath": "games/Asteroids/assets/sprites/data/asteroids-demo.sprite.data.json",
11+
"sourceToolId": "sprite-editor",
12+
"metadata": {
13+
"runtimeType": "sprite"
14+
}
15+
}
16+
],
17+
"tilemaps": [
18+
{
19+
"assetId": "tilemap.asteroids.stage",
20+
"runtimePath": "games/Asteroids/assets/tilemaps/asteroids-stage.tilemap.json",
21+
"toolDataPath": "games/Asteroids/assets/tilemaps/data/asteroids-stage.tilemap.data.json",
22+
"sourceToolId": "tile-map-editor",
23+
"metadata": {
24+
"runtimeType": "tilemap"
25+
}
26+
}
27+
],
28+
"parallax": [
29+
{
30+
"assetId": "parallax.asteroids.title",
31+
"runtimePath": "games/Asteroids/assets/parallax/asteroids-title.parallax.json",
32+
"toolDataPath": "games/Asteroids/assets/parallax/data/asteroids-title.parallax.data.json",
33+
"sourceToolId": "parallax-editor",
34+
"metadata": {
35+
"runtimeType": "parallax"
36+
}
37+
},
38+
{
39+
"assetId": "parallax.asteroids.overlay",
40+
"runtimePath": "games/Asteroids/assets/parallax/asteroids-overlay.parallax.json",
41+
"toolDataPath": "games/Asteroids/assets/parallax/data/asteroids-overlay.parallax.data.json",
42+
"sourceToolId": "parallax-editor",
43+
"metadata": {
44+
"runtimeType": "parallax"
45+
}
46+
}
47+
],
48+
"vectors": [
49+
{
50+
"assetId": "vector.asteroids.ship",
51+
"runtimePath": "games/Asteroids/assets/vectors/asteroids-ship.vector.json",
52+
"toolDataPath": "games/Asteroids/assets/vectors/data/asteroids-vectors.library.data.json",
53+
"sourceToolId": "vector-asset-studio",
54+
"metadata": {
55+
"runtimeType": "vector"
56+
}
57+
},
58+
{
59+
"assetId": "vector.asteroids.asteroid.large",
60+
"runtimePath": "games/Asteroids/assets/vectors/asteroids-asteroid-large.vector.json",
61+
"toolDataPath": "games/Asteroids/assets/vectors/data/asteroids-vectors.library.data.json",
62+
"sourceToolId": "vector-asset-studio",
63+
"metadata": {
64+
"runtimeType": "vector"
65+
}
66+
},
67+
{
68+
"assetId": "vector.asteroids.asteroid.medium",
69+
"runtimePath": "games/Asteroids/assets/vectors/asteroids-asteroid-medium.vector.json",
70+
"toolDataPath": "games/Asteroids/assets/vectors/data/asteroids-vectors.library.data.json",
71+
"sourceToolId": "vector-asset-studio",
72+
"metadata": {
73+
"runtimeType": "vector"
74+
}
75+
},
76+
{
77+
"assetId": "vector.asteroids.asteroid.small",
78+
"runtimePath": "games/Asteroids/assets/vectors/asteroids-asteroid-small.vector.json",
79+
"toolDataPath": "games/Asteroids/assets/vectors/data/asteroids-vectors.library.data.json",
80+
"sourceToolId": "vector-asset-studio",
81+
"metadata": {
82+
"runtimeType": "vector"
83+
}
84+
},
85+
{
86+
"assetId": "vector.asteroids.ui.title",
87+
"runtimePath": "games/Asteroids/assets/vectors/asteroids-title.vector.json",
88+
"toolDataPath": "games/Asteroids/assets/vectors/data/asteroids-vectors.library.data.json",
89+
"sourceToolId": "vector-asset-studio",
90+
"metadata": {
91+
"runtimeType": "vector"
92+
}
93+
}
94+
]
95+
}
96+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import assert from "node:assert/strict";
2+
import {
3+
ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH,
4+
discoverAsteroidsRuntimeAssets,
5+
loadAsteroidsAssetManifest
6+
} from "../../tools/shared/pipeline/asteroidsAssetManifestLoader.js";
7+
8+
function normalizePath(value) {
9+
return String(value || "").replace(/\\/g, "/");
10+
}
11+
12+
export async function run() {
13+
const loaded = await loadAsteroidsAssetManifest();
14+
assert.equal(loaded.status, "ready");
15+
assert.equal(Array.isArray(loaded.issues), true);
16+
assert.equal(loaded.issues.length, 0);
17+
assert.equal(loaded.manifest.gameId, "asteroids");
18+
assert.equal(normalizePath(loaded.manifestPath).endsWith(ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH), true);
19+
20+
const discovered = await discoverAsteroidsRuntimeAssets();
21+
assert.equal(discovered.status, "ready");
22+
assert.equal(discovered.issues.length, 0);
23+
assert.equal(Object.keys(discovered.runtimeAssetSources).length > 0, true);
24+
assert.equal(
25+
discovered.runtimeAssetSources["vector.asteroids.ship"].file.includes("/data/"),
26+
false
27+
);
28+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import fs from "node:fs/promises";
2+
import path from "node:path";
3+
import { fileURLToPath } from "node:url";
4+
import {
5+
discoverRuntimeAssetSourcesFromManifest,
6+
validateGameAssetManifestStructure
7+
} from "./gameAssetManifestDiscovery.js";
8+
9+
export const ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH = "games/Asteroids/assets/asteroids.asset.manifest.json";
10+
11+
const MODULE_DIRECTORY = path.dirname(fileURLToPath(import.meta.url));
12+
const REPO_ROOT = path.resolve(MODULE_DIRECTORY, "../../../");
13+
14+
function toManifestPath(options = {}) {
15+
if (typeof options.manifestPath === "string" && options.manifestPath.trim()) {
16+
return path.resolve(options.manifestPath);
17+
}
18+
return path.resolve(REPO_ROOT, ASTEROIDS_ASSET_MANIFEST_RELATIVE_PATH);
19+
}
20+
21+
async function readManifestJson(manifestPath) {
22+
const raw = await fs.readFile(manifestPath, "utf8");
23+
return {
24+
raw,
25+
manifest: JSON.parse(raw)
26+
};
27+
}
28+
29+
export async function loadAsteroidsAssetManifest(options = {}) {
30+
const manifestPath = toManifestPath(options);
31+
let payload;
32+
try {
33+
payload = await readManifestJson(manifestPath);
34+
} catch (error) {
35+
return {
36+
status: "invalid",
37+
manifestPath,
38+
manifest: null,
39+
discovery: null,
40+
issues: [error instanceof Error ? error.message : "Failed to read Asteroids asset manifest."]
41+
};
42+
}
43+
44+
const validation = validateGameAssetManifestStructure(payload.manifest, { gameId: "asteroids" });
45+
if (!validation.valid) {
46+
return {
47+
status: "invalid",
48+
manifestPath,
49+
manifest: payload.manifest,
50+
discovery: null,
51+
issues: validation.issues
52+
};
53+
}
54+
55+
const discovery = discoverRuntimeAssetSourcesFromManifest(payload.manifest, { gameId: "asteroids" });
56+
return {
57+
status: discovery.status,
58+
manifestPath,
59+
manifest: payload.manifest,
60+
discovery,
61+
issues: discovery.issues || []
62+
};
63+
}
64+
65+
export async function discoverAsteroidsRuntimeAssets(options = {}) {
66+
const loaded = await loadAsteroidsAssetManifest(options);
67+
if (loaded.status !== "ready") {
68+
return {
69+
status: "invalid",
70+
manifestPath: loaded.manifestPath,
71+
runtimeAssetSources: {},
72+
records: [],
73+
issues: loaded.issues || []
74+
};
75+
}
76+
77+
return {
78+
status: "ready",
79+
manifestPath: loaded.manifestPath,
80+
runtimeAssetSources: loaded.discovery.runtimeAssetSources,
81+
records: loaded.discovery.records,
82+
issues: []
83+
};
84+
}

0 commit comments

Comments
 (0)