Skip to content

Commit a7a764a

Browse files
author
DavidQ
committed
Process update to always append a commit comment in every response
1 parent 631fef5 commit a7a764a

9 files changed

Lines changed: 556 additions & 4 deletions
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BUILD_PR_LEVEL_20_1_PHASE20_TOOL_PRESET_INTEGRATION - Samples2Tools Batch 13 Summary
2+
3+
Scope: phase-01 through phase-19 Phase 3 Tilemap Studio expansion
4+
5+
Tilemap Studio mapped samples: 5
6+
- Phase 02 Sample 0221 | Tilemap System | preset: /samples/phase-02/0221/sample-0221-tile-map-editor.json
7+
- Phase 12 Sample 1208 | Tool Formatted Tiles Parallax | preset: /samples/phase-12/1208/sample-1208-tile-map-editor.json
8+
- Phase 12 Sample 1209 | Tilemap Basic Layout Preset | preset: /samples/phase-12/1209/sample-1209-tile-map-editor.json
9+
- Phase 12 Sample 1210 | Tilemap Objective Layout Preset | preset: /samples/phase-12/1210/sample-1210-tile-map-editor.json
10+
- Phase 12 Sample 1211 | Tilemap Mario Learning Layout Preset | preset: /samples/phase-12/1211/sample-1211-tile-map-editor.json
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
BUILD_PR_LEVEL_20_1_PHASE20_TOOL_PRESET_INTEGRATION - Samples2Tools Batch 13 Validation
2+
3+
[x] Tilemap Studio has 5 mapped samples (phase-01 through phase-19)
4+
[x] All 5 mapped Tilemap Studio preset wrapper files exist on disk
5+
[x] Samples index roundtrip logic includes 0221 tile-map-editor mapping
6+
[x] Sample 0221 runtime loads the same sample-0221-tile-map-editor.json lane used by Tilemap Studio preload
7+
[x] Metadata toolHints include tile-map-editor for mapped sample ids
8+
9+
Validation details
10+
- Added/validated sample id: 0221
11+
- Existing mapped sample ids retained: 1208, 1209, 1210, 1211
12+
- New files: /samples/phase-02/0221/sample-0221-tile-map-editor.json, /samples/phase-02/0221/sample-0221-tile-map-editor-document.json
13+
- Roundtrip launcher path: samples/index.render.js
14+
- Sample runtime loader path: samples/phase-02/0221/TilemapSystemScene.js
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
{
2+
"generatedAt": "2026-04-24T16:21:44.779Z",
3+
"scope": "phase-01-phase-19",
4+
"purpose": "batch-13-tilemap-studio-expansion",
5+
"links": [
6+
{
7+
"sampleId": "0221",
8+
"phase": "02",
9+
"title": "Tilemap System",
10+
"toolId": "tile-map-editor",
11+
"href": "./phase-02/0221/index.html",
12+
"presetPath": "/samples/phase-02/0221/sample-0221-tile-map-editor.json"
13+
},
14+
{
15+
"sampleId": "1208",
16+
"phase": "12",
17+
"title": "Tool Formatted Tiles Parallax",
18+
"toolId": "tile-map-editor",
19+
"href": "./phase-12/1208/index.html",
20+
"presetPath": "/samples/phase-12/1208/sample-1208-tile-map-editor.json"
21+
},
22+
{
23+
"sampleId": "1209",
24+
"phase": "12",
25+
"title": "Tilemap Basic Layout Preset",
26+
"toolId": "tile-map-editor",
27+
"href": "./phase-12/1209/index.html",
28+
"presetPath": "/samples/phase-12/1209/sample-1209-tile-map-editor.json"
29+
},
30+
{
31+
"sampleId": "1210",
32+
"phase": "12",
33+
"title": "Tilemap Objective Layout Preset",
34+
"toolId": "tile-map-editor",
35+
"href": "./phase-12/1210/index.html",
36+
"presetPath": "/samples/phase-12/1210/sample-1210-tile-map-editor.json"
37+
},
38+
{
39+
"sampleId": "1211",
40+
"phase": "12",
41+
"title": "Tilemap Mario Learning Layout Preset",
42+
"toolId": "tile-map-editor",
43+
"href": "./phase-12/1211/index.html",
44+
"presetPath": "/samples/phase-12/1211/sample-1211-tile-map-editor.json"
45+
}
46+
]
47+
}

docs/dev/roadmaps/MASTER_ROADMAP_SAMPLES2TOOLS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102

103103
### Phase 3 - Core Editor/Workflow Tools
104104
- [x] Sprite Editor (9 candidates)
105-
- [ ] Tilemap Studio (15 candidates)
105+
- [.] Tilemap Studio (15 candidates)
106106
- [ ] Tile Model Converter (18 candidates)
107107
- [ ] Asset Browser / Import Hub (8 candidates)
108108
- [ ] Asset Pipeline Tool (10 candidates)
@@ -154,6 +154,6 @@
154154
- [x] `docs/dev/reports/samples2tools_link_map_<n>.json`
155155

156156
## Current Snapshot (from tools_used.txt)
157-
- [x] Current tagged samples across active tools: `26` (phase-01 through phase-19)
157+
- [x] Current tagged samples across active tools: `27` (phase-01 through phase-19)
158158
- [x] Candidate coverage inventory exists for all active tools
159159
- [.] Convert candidates into curated, validated sample-to-tool links

samples/index.render.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ function shouldUsePresetRoundtrip(sample, toolId) {
5454
|| (sampleId === "1205" && samplePhase === "12");
5555
}
5656
if (toolId === "tile-map-editor") {
57-
return (sampleId === "1209" && samplePhase === "12")
57+
return (sampleId === "0221" && samplePhase === "02")
58+
|| (sampleId === "1209" && samplePhase === "12")
5859
|| (sampleId === "1210" && samplePhase === "12")
5960
|| (sampleId === "1211" && samplePhase === "12");
6061
}

samples/metadata/samples.index.metadata.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,9 @@
18481848
"engine/tilemap/index/resolveRectVsTilemap",
18491849
"engine/tilemap/index/Tilemap",
18501850
"engine/utils/index/clamp"
1851+
],
1852+
"toolHints": [
1853+
"tile-map-editor"
18511854
]
18521855
},
18531856
{

samples/phase-02/0221/TilemapSystemScene.js

Lines changed: 132 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ import { drawFrame, drawPanel } from '/src/engine/debug/index.js';
1111
import { Tilemap, renderTilemap, resolveRectVsTilemap } from '/src/engine/tilemap/index.js';
1212

1313
const theme = new Theme(ThemeTokens);
14+
const TILEMAP_PRESET_PATH = '/samples/phase-02/0221/sample-0221-tile-map-editor.json';
1415

1516
export default class TilemapSystemScene extends Scene {
1617
constructor() {
1718
super();
1819
this.offset = { x: 160, y: 180 };
20+
this.sampleStatus = 'Loading shared tilemap preset...';
21+
this.sampleError = '';
1922
this.tilemap = new Tilemap({
2023
tileSize: 48,
2124
tiles: [
@@ -39,6 +42,133 @@ export default class TilemapSystemScene extends Scene {
3942
speed: 220,
4043
};
4144
this.lastCollision = 'none';
45+
void this.loadTilemapPreset();
46+
}
47+
48+
extractTileMapDocumentFromSamplePreset(rawPreset) {
49+
if (!rawPreset || typeof rawPreset !== 'object') {
50+
return null;
51+
}
52+
53+
const payload = rawPreset.payload;
54+
if (payload && typeof payload === 'object') {
55+
if (payload.tilemapDocument && typeof payload.tilemapDocument === 'object') {
56+
return payload.tilemapDocument;
57+
}
58+
if (payload.tileMapDocument && typeof payload.tileMapDocument === 'object') {
59+
return payload.tileMapDocument;
60+
}
61+
if (payload.tilemap && typeof payload.tilemap === 'object') {
62+
return payload.tilemap;
63+
}
64+
if (payload.tileMap && typeof payload.tileMap === 'object') {
65+
return payload.tileMap;
66+
}
67+
if (typeof payload.tilemapDocumentPath === 'string' && payload.tilemapDocumentPath.trim()) {
68+
return payload.tilemapDocumentPath.trim();
69+
}
70+
if (typeof payload.tileMapDocumentPath === 'string' && payload.tileMapDocumentPath.trim()) {
71+
return payload.tileMapDocumentPath.trim();
72+
}
73+
}
74+
return null;
75+
}
76+
77+
applyTilemapDocument(documentModel) {
78+
if (!documentModel || typeof documentModel !== 'object') {
79+
throw new Error('Tilemap document is missing.');
80+
}
81+
82+
const map = documentModel.map || {};
83+
const tileSize = Number(map.tileSize) > 0 ? Number(map.tileSize) : 48;
84+
const layers = Array.isArray(documentModel.layers) ? documentModel.layers : [];
85+
const renderLayer = layers.find((layer) => layer && layer.kind === 'tile') || layers[0] || null;
86+
const collisionLayer = layers.find((layer) => layer && layer.kind === 'collision') || null;
87+
88+
if (!renderLayer || !Array.isArray(renderLayer.data) || renderLayer.data.length === 0) {
89+
throw new Error('Tilemap document did not include a render layer.');
90+
}
91+
92+
const rows = renderLayer.data.map((row) => Array.isArray(row) ? row.map((value) => Number.parseInt(value, 10) || 0) : []);
93+
const tilesetEntries = Array.isArray(documentModel.tileset) ? documentModel.tileset : [];
94+
const palette = {};
95+
tilesetEntries.forEach((entry) => {
96+
const id = Number.parseInt(entry?.id, 10);
97+
const color = typeof entry?.color === 'string' ? entry.color : '';
98+
if (Number.isInteger(id) && color) {
99+
palette[id] = color;
100+
}
101+
});
102+
if (!palette[0]) {
103+
palette[0] = '#1f2937';
104+
}
105+
106+
const definitions = {};
107+
if (collisionLayer && Array.isArray(collisionLayer.data)) {
108+
collisionLayer.data.forEach((row, rowIndex) => {
109+
if (!Array.isArray(row)) {
110+
return;
111+
}
112+
row.forEach((cell, colIndex) => {
113+
if (Number(cell) === 1) {
114+
const tileId = Number(rows[rowIndex]?.[colIndex]) || 0;
115+
if (!definitions[tileId]) {
116+
definitions[tileId] = {
117+
solid: true,
118+
color: palette[tileId] || '#6366f1',
119+
label: `tile-${tileId}`
120+
};
121+
} else {
122+
definitions[tileId].solid = true;
123+
}
124+
}
125+
});
126+
});
127+
}
128+
129+
this.tilemap = new Tilemap({
130+
tileSize,
131+
tiles: rows,
132+
palette,
133+
definitions
134+
});
135+
136+
this.player.x = this.offset.x + 60;
137+
this.player.y = this.offset.y + 60;
138+
}
139+
140+
async loadTilemapPreset() {
141+
try {
142+
const presetResponse = await fetch(TILEMAP_PRESET_PATH, { cache: 'no-store' });
143+
if (!presetResponse.ok) {
144+
throw new Error(`Preset request failed (${presetResponse.status}).`);
145+
}
146+
147+
const samplePreset = await presetResponse.json();
148+
const extracted = this.extractTileMapDocumentFromSamplePreset(samplePreset);
149+
let documentModel = null;
150+
151+
if (typeof extracted === 'string' && extracted.trim()) {
152+
const documentResponse = await fetch(extracted.trim(), { cache: 'no-store' });
153+
if (!documentResponse.ok) {
154+
throw new Error(`Tilemap document request failed (${documentResponse.status}).`);
155+
}
156+
documentModel = await documentResponse.json();
157+
} else if (extracted && typeof extracted === 'object') {
158+
documentModel = extracted;
159+
}
160+
161+
if (!documentModel) {
162+
throw new Error('Preset payload did not include a tilemap document.');
163+
}
164+
165+
this.applyTilemapDocument(documentModel);
166+
this.sampleStatus = 'Loaded tilemap preset from sample-0221-tile-map-editor.json';
167+
this.sampleError = '';
168+
} catch (error) {
169+
this.sampleStatus = 'Using fallback in-scene tilemap.';
170+
this.sampleError = error instanceof Error ? error.message : String(error);
171+
}
42172
}
43173

44174
update(dt, engine) {
@@ -67,9 +197,10 @@ export default class TilemapSystemScene extends Scene {
67197
drawFrame(renderer, theme, [
68198
'Engine Sample 0221',
69199
'Demonstrates tilemap rendering and tile-based collision',
200+
'This sample and Tilemap Studio load the same sample-0221-tile-map-editor.json source',
70201
'Use Arrow keys to move through the open tiles',
71202
`Collision: ${this.lastCollision}`,
72-
'This sample provides the first map-driven gameplay foundation',
203+
this.sampleError ? `${this.sampleStatus} (${this.sampleError})` : this.sampleStatus,
73204
]);
74205

75206
renderTilemap(renderer, this.tilemap, this.offset);

0 commit comments

Comments
 (0)