Skip to content

Commit cf51d7b

Browse files
author
DavidQ
committed
docs: add BUILD_PR tools boot contract normalization bundle
1 parent 827e543 commit cf51d7b

File tree

12 files changed

+308
-71
lines changed

12 files changed

+308
-71
lines changed

docs/dev/CODEX_COMMANDS.md

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,17 @@ MODEL: GPT-5.4
22
REASONING: high
33

44
COMMAND:
5-
Create BUILD_PR_TOOLS_SHARED_EXTRACTION_PHASE_2
5+
Create BUILD_PR_TOOLS_BOOT_CONTRACT_NORMALIZATION
66

77
Scope:
8-
- extract shared event + command helpers
9-
- extract safe UI utilities
10-
- reuse tools/shared first
11-
- minimal changes
12-
- no theme work
13-
- no editor-state extraction
8+
- normalize tool boot/init contract
9+
- minimal adapters only
10+
- no UI/styling changes
11+
- no editor state refactor
1412

1513
Validation:
1614
- npm run test:launch-smoke -- --tools
17-
- report files changed
15+
- verify all tools launch
1816

1917
Output:
20-
<project>/tmp/BUILD_PR_TOOLS_SHARED_EXTRACTION_PHASE_2_delta.zip
18+
<project>/tmp/BUILD_PR_TOOLS_BOOT_CONTRACT_delta.zip

docs/dev/COMMIT_COMMENT.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
docs: add BUILD_PR phase 2 shared extraction bundle
1+
docs: add BUILD_PR tools boot contract normalization bundle

docs/dev/reports/launch_smoke_report.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Launch Smoke Report
22

3-
Generated: 2026-04-11T23:18:02.796Z
3+
Generated: 2026-04-11T23:25:17.535Z
44

55
Filters: games=false, samples=false, tools=true, sampleRange=all
66

tools/Asset Browser/main.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
getToolDisplayName,
55
writeSharedAssetHandoff
66
} from "../shared/assetUsageIntegration.js";
7+
import { registerToolBootContract } from "../shared/toolBootContract.js";
78

89
const APPROVED_DESTINATIONS = Object.freeze({
910
"Vector Assets": "games/<project>/platform/assets/vectors/",
@@ -409,8 +410,9 @@ function init() {
409410
bindEvents();
410411
}
411412

412-
init();
413-
window.assetBrowserApp = {
413+
let initialized = false;
414+
415+
const assetBrowserApi = {
414416
captureProjectState() {
415417
return {
416418
selectedCategory: state.selectedCategory,
@@ -437,3 +439,24 @@ window.assetBrowserApp = {
437439
return true;
438440
}
439441
};
442+
443+
function bootAssetBrowser() {
444+
if (!initialized) {
445+
init();
446+
initialized = true;
447+
}
448+
window.assetBrowserApp = assetBrowserApi;
449+
return assetBrowserApi;
450+
}
451+
452+
registerToolBootContract("asset-browser", {
453+
init: bootAssetBrowser,
454+
destroy() {
455+
return true;
456+
},
457+
getApi() {
458+
return window.assetBrowserApp || null;
459+
}
460+
});
461+
462+
bootAssetBrowser();

tools/Palette Browser/main.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
getToolDisplayName,
66
writeSharedPaletteHandoff
77
} from "../shared/assetUsageIntegration.js";
8+
import { registerToolBootContract } from "../shared/toolBootContract.js";
89

910
const CUSTOM_PALETTES_STORAGE_KEY = "toolboxaid.paletteBrowser.customPalettes";
1011

@@ -388,8 +389,9 @@ function init() {
388389
bindEvents();
389390
}
390391

391-
init();
392-
window.paletteBrowserApp = {
392+
let initialized = false;
393+
394+
const paletteBrowserApi = {
393395
captureProjectState() {
394396
return {
395397
search: state.search,
@@ -411,3 +413,24 @@ window.paletteBrowserApp = {
411413
return true;
412414
}
413415
};
416+
417+
function bootPaletteBrowser() {
418+
if (!initialized) {
419+
init();
420+
initialized = true;
421+
}
422+
window.paletteBrowserApp = paletteBrowserApi;
423+
return paletteBrowserApi;
424+
}
425+
426+
registerToolBootContract("palette-browser", {
427+
init: bootPaletteBrowser,
428+
destroy() {
429+
return true;
430+
},
431+
getApi() {
432+
return window.paletteBrowserApp || null;
433+
}
434+
});
435+
436+
bootPaletteBrowser();

tools/Parallax Scene Studio/main.js

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
import { buildProjectPackage, summarizeProjectPackaging } from "../shared/projectPackaging.js";
3030
import { buildEditorExperienceLayer, summarizeEditorExperienceLayer } from "../shared/editorExperienceLayer.js";
3131
import { buildDebugVisualizationLayer, summarizeDebugVisualizationLayer } from "../shared/debugVisualizationLayer.js";
32+
import { registerToolBootContract } from "../shared/toolBootContract.js";
3233

3334
const SAMPLE_DIRECTORY_PATH = "./samples/";
3435
const SAMPLE_MANIFEST_PATH = "./samples/sample-manifest.json";
@@ -1836,24 +1837,47 @@ class ParallaxEditorApp {
18361837
}
18371838
}
18381839

1839-
const initialDocument = createInitialParallaxDocument();
1840-
const app = new ParallaxEditorApp(initialDocument);
1841-
app.init(document);
1842-
app.applyProjectSystemState = function applyProjectSystemState(snapshot) {
1843-
const nextDocument = sanitizeParallaxDocument(snapshot?.documentModel);
1844-
this.documentModel = nextDocument;
1845-
this.assetRegistry = snapshot?.assetRegistry && typeof snapshot.assetRegistry === "object"
1846-
? sanitizeAssetRegistry(snapshot.assetRegistry)
1847-
: createAssetRegistry({ projectId: nextDocument?.map?.name || "parallax-project" });
1848-
this.selectedLayerId = typeof snapshot?.selectedLayerId === "string" && nextDocument.layers.some((layer) => layer.id === snapshot.selectedLayerId)
1849-
? snapshot.selectedLayerId
1850-
: nextDocument.layers[0]?.id || "";
1851-
this.cameraX = Number.isFinite(Number(snapshot?.cameraX)) ? Number(snapshot.cameraX) : 0;
1852-
this.cameraY = Number.isFinite(Number(snapshot?.cameraY)) ? Number(snapshot.cameraY) : 0;
1853-
this.resolveAssetRefsFromRegistry();
1854-
this.invalidateImageCache();
1855-
this.syncInputsFromDocument();
1856-
this.renderAll();
1857-
this.updateStatus(`Project state loaded for ${this.documentModel.map.name}.`);
1858-
};
1859-
window.parallaxSceneStudioApp = app;
1840+
let parallaxSceneStudioApp = null;
1841+
1842+
function bootParallaxSceneStudio() {
1843+
if (parallaxSceneStudioApp) {
1844+
window.parallaxSceneStudioApp = parallaxSceneStudioApp;
1845+
return parallaxSceneStudioApp;
1846+
}
1847+
1848+
const initialDocument = createInitialParallaxDocument();
1849+
const app = new ParallaxEditorApp(initialDocument);
1850+
app.init(document);
1851+
app.applyProjectSystemState = function applyProjectSystemState(snapshot) {
1852+
const nextDocument = sanitizeParallaxDocument(snapshot?.documentModel);
1853+
this.documentModel = nextDocument;
1854+
this.assetRegistry = snapshot?.assetRegistry && typeof snapshot.assetRegistry === "object"
1855+
? sanitizeAssetRegistry(snapshot.assetRegistry)
1856+
: createAssetRegistry({ projectId: nextDocument?.map?.name || "parallax-project" });
1857+
this.selectedLayerId = typeof snapshot?.selectedLayerId === "string" && nextDocument.layers.some((layer) => layer.id === snapshot.selectedLayerId)
1858+
? snapshot.selectedLayerId
1859+
: nextDocument.layers[0]?.id || "";
1860+
this.cameraX = Number.isFinite(Number(snapshot?.cameraX)) ? Number(snapshot.cameraX) : 0;
1861+
this.cameraY = Number.isFinite(Number(snapshot?.cameraY)) ? Number(snapshot.cameraY) : 0;
1862+
this.resolveAssetRefsFromRegistry();
1863+
this.invalidateImageCache();
1864+
this.syncInputsFromDocument();
1865+
this.renderAll();
1866+
this.updateStatus(`Project state loaded for ${this.documentModel.map.name}.`);
1867+
};
1868+
parallaxSceneStudioApp = app;
1869+
window.parallaxSceneStudioApp = parallaxSceneStudioApp;
1870+
return parallaxSceneStudioApp;
1871+
}
1872+
1873+
registerToolBootContract("parallax-editor", {
1874+
init: bootParallaxSceneStudio,
1875+
destroy() {
1876+
return true;
1877+
},
1878+
getApi() {
1879+
return window.parallaxSceneStudioApp || null;
1880+
}
1881+
});
1882+
1883+
bootParallaxSceneStudio();

tools/Sprite Editor/main.js

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,37 @@ David Quesenberry
55
main.js
66
*/
77
import { initializeSpriteEditorApp } from "./modules/spriteEditorApp.js";
8+
import { registerToolBootContract } from "../shared/toolBootContract.js";
89

9-
const spriteEditorApp = initializeSpriteEditorApp();
10-
window.spriteEditorApp = {
11-
state: spriteEditorApp,
10+
let spriteEditorApp = null;
11+
12+
const spriteEditorApi = {
13+
get state() {
14+
return spriteEditorApp;
15+
},
1216
applyProjectSystemState(snapshot) {
13-
spriteEditorApp.applyProjectSystemState(snapshot);
17+
if (spriteEditorApp && typeof spriteEditorApp.applyProjectSystemState === "function") {
18+
spriteEditorApp.applyProjectSystemState(snapshot);
19+
}
1420
}
1521
};
22+
23+
function bootSpriteEditor() {
24+
if (!spriteEditorApp) {
25+
spriteEditorApp = initializeSpriteEditorApp();
26+
}
27+
window.spriteEditorApp = spriteEditorApi;
28+
return spriteEditorApi;
29+
}
30+
31+
registerToolBootContract("sprite-editor", {
32+
init: bootSpriteEditor,
33+
destroy() {
34+
return true;
35+
},
36+
getApi() {
37+
return window.spriteEditorApp || null;
38+
}
39+
});
40+
41+
bootSpriteEditor();

tools/Tilemap Studio/main.js

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
import { buildProjectPackage, summarizeProjectPackaging } from "../shared/projectPackaging.js";
3030
import { buildEditorExperienceLayer, summarizeEditorExperienceLayer } from "../shared/editorExperienceLayer.js";
3131
import { buildDebugVisualizationLayer, summarizeDebugVisualizationLayer } from "../shared/debugVisualizationLayer.js";
32+
import { registerToolBootContract } from "../shared/toolBootContract.js";
3233

3334
const DEFAULT_TILESET = [
3435
{ id: 0, name: "Empty", color: "transparent" },
@@ -2646,23 +2647,46 @@ class TileMapEditorApp {
26462647
}
26472648
}
26482649

2649-
const initialDocument = createInitialDocument();
2650-
const app = new TileMapEditorApp(initialDocument);
2651-
app.init(document);
2652-
app.applyProjectSystemState = function applyProjectSystemState(snapshot) {
2653-
const nextDocument = sanitizeDocument(snapshot?.documentModel);
2654-
this.documentModel = nextDocument;
2655-
this.assetRegistry = snapshot?.assetRegistry && typeof snapshot.assetRegistry === "object"
2656-
? sanitizeAssetRegistry(snapshot.assetRegistry)
2657-
: createAssetRegistry({ projectId: nextDocument?.map?.name || "tilemap-project" });
2658-
this.selectedLayerId = typeof snapshot?.selectedLayerId === "string" && nextDocument.layers.some((layer) => layer.id === snapshot.selectedLayerId)
2659-
? snapshot.selectedLayerId
2660-
: nextDocument.layers[0]?.id || "";
2661-
this.selectedMarkerId = typeof snapshot?.selectedMarkerId === "string" ? snapshot.selectedMarkerId : "";
2662-
this.activeTileId = Number.isInteger(snapshot?.activeTileId) ? snapshot.activeTileId : 1;
2663-
this.resolveAssetRefsFromRegistry();
2664-
this.syncInputsFromDocument();
2665-
this.renderAll();
2666-
this.updateStatus(`Project state loaded for ${this.documentModel.map.name}.`);
2667-
};
2668-
window.tileMapStudioApp = app;
2650+
let tileMapStudioApp = null;
2651+
2652+
function bootTileMapStudio() {
2653+
if (tileMapStudioApp) {
2654+
window.tileMapStudioApp = tileMapStudioApp;
2655+
return tileMapStudioApp;
2656+
}
2657+
2658+
const initialDocument = createInitialDocument();
2659+
const app = new TileMapEditorApp(initialDocument);
2660+
app.init(document);
2661+
app.applyProjectSystemState = function applyProjectSystemState(snapshot) {
2662+
const nextDocument = sanitizeDocument(snapshot?.documentModel);
2663+
this.documentModel = nextDocument;
2664+
this.assetRegistry = snapshot?.assetRegistry && typeof snapshot.assetRegistry === "object"
2665+
? sanitizeAssetRegistry(snapshot.assetRegistry)
2666+
: createAssetRegistry({ projectId: nextDocument?.map?.name || "tilemap-project" });
2667+
this.selectedLayerId = typeof snapshot?.selectedLayerId === "string" && nextDocument.layers.some((layer) => layer.id === snapshot.selectedLayerId)
2668+
? snapshot.selectedLayerId
2669+
: nextDocument.layers[0]?.id || "";
2670+
this.selectedMarkerId = typeof snapshot?.selectedMarkerId === "string" ? snapshot.selectedMarkerId : "";
2671+
this.activeTileId = Number.isInteger(snapshot?.activeTileId) ? snapshot.activeTileId : 1;
2672+
this.resolveAssetRefsFromRegistry();
2673+
this.syncInputsFromDocument();
2674+
this.renderAll();
2675+
this.updateStatus(`Project state loaded for ${this.documentModel.map.name}.`);
2676+
};
2677+
tileMapStudioApp = app;
2678+
window.tileMapStudioApp = tileMapStudioApp;
2679+
return tileMapStudioApp;
2680+
}
2681+
2682+
registerToolBootContract("tile-map-editor", {
2683+
init: bootTileMapStudio,
2684+
destroy() {
2685+
return true;
2686+
},
2687+
getApi() {
2688+
return window.tileMapStudioApp || null;
2689+
}
2690+
});
2691+
2692+
bootTileMapStudio();

tools/Vector Asset Studio/main.js

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ David Quesenberry
44
03/30/2026
55
main.js
66
*/
7+
import { registerToolBootContract } from "../shared/toolBootContract.js";
78

89
const SVG_NS = "http://www.w3.org/2000/svg";
910
const SAMPLE_MANIFEST_PATH = "./samples/sample-manifest.json";
@@ -2734,8 +2735,7 @@ async function initialize() {
27342735
setStatus("Vector Asset Studio ready.");
27352736
}
27362737

2737-
initialize();
2738-
window.vectorAssetStudioApp = {
2738+
const vectorAssetStudioApi = {
27392739
getProjectName() {
27402740
return state.documentName || "untitled-background";
27412741
},
@@ -2784,3 +2784,26 @@ window.vectorAssetStudioApp = {
27842784
};
27852785
}
27862786
};
2787+
2788+
let vectorAssetStudioBooted = false;
2789+
2790+
function bootVectorAssetStudio() {
2791+
if (!vectorAssetStudioBooted) {
2792+
vectorAssetStudioBooted = true;
2793+
void initialize();
2794+
}
2795+
window.vectorAssetStudioApp = vectorAssetStudioApi;
2796+
return vectorAssetStudioApi;
2797+
}
2798+
2799+
registerToolBootContract("vector-asset-studio", {
2800+
init: bootVectorAssetStudio,
2801+
destroy() {
2802+
return true;
2803+
},
2804+
getApi() {
2805+
return window.vectorAssetStudioApp || null;
2806+
}
2807+
});
2808+
2809+
bootVectorAssetStudio();

0 commit comments

Comments
 (0)