Files
feuerwerk/tools/seed-demo.mjs
T
rootandClaude Fable 5.1 6ecb20cf02 Trigger colliders and Move and slide against solid colliders
- Collider property isTrigger (no blocking, still reports enter/stay/exit)
- Node 'Move and slide' with blocked x/y outputs, axis-wise resolution
- axisSeparation/axisCorrection geometry for box/box, circle/circle, box/circle
- Amber outline for trigger colliders in the viewport
- Demo mover uses Move and slide; E2E step 15b, 7 new unit tests

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-07 15:38:14 +02:00

83 lines
3.5 KiB
JavaScript

#!/usr/bin/env node
/**
* Resets the demo project to the state tools/e2e.mjs expects (the e2e run mutates it).
* Usage: PATH=/opt/node22/bin:$PATH node tools/seed-demo.mjs <projectId> [baseUrl]
*/
const projectId = process.argv[2];
const baseUrl = process.argv[3] ?? 'https://nockal.com/game-maker/';
if (!projectId) {
console.error('usage: node tools/seed-demo.mjs <projectId> [baseUrl]');
process.exit(2);
}
/**
* "Mover" behavior in five nodes: every frame, move the owner along the normalized arrow-key
* axis, scaled by the `speed` variable per second (On update's dt feeds the dt input).
* Diagonals are not faster than straight moves because Axis input normalizes the vector, and
* "Move and slide" stops the owner's solid colliders at other solid colliders.
*/
const moverGraph = {
nodes: [
{ id: 'n-update', type: 'OnUpdate', x: 0, y: 0, params: {} },
{ id: 'n-owner', type: 'Owner', x: 0, y: 120, params: {} },
{ id: 'n-axis', type: 'AxisInput', x: 0, y: 200, params: {} },
{ id: 'n-speed', type: 'GetVariable', x: 0, y: 400, params: { variable: 'speed' } },
{ id: 'n-move', type: 'MoveAndSlide', x: 340, y: 0, params: {} },
],
edges: [
{ id: 'e1', from: { node: 'n-update', port: 'exec' }, to: { node: 'n-move', port: 'exec' } },
{ id: 'e6', from: { node: 'n-update', port: 'dt' }, to: { node: 'n-move', port: 'dt' } },
{ id: 'e2', from: { node: 'n-owner', port: 'object' }, to: { node: 'n-move', port: 'object' } },
{ id: 'e3', from: { node: 'n-axis', port: 'x' }, to: { node: 'n-move', port: 'dx' } },
{ id: 'e4', from: { node: 'n-axis', port: 'y' }, to: { node: 'n-move', port: 'dy' } },
{ id: 'e5', from: { node: 'n-speed', port: 'value' }, to: { node: 'n-move', port: 'scale' } },
],
};
const project = {
formatVersion: 1,
id: projectId,
name: 'Demo project',
activeSceneId: 'scene1',
assets: [
{
id: 'scene1',
type: 'scene',
name: 'Level 1',
props: { backgroundColor: 0x22252c },
objects: [
{ id: 'o1', assetId: 'crate', name: '', position: { x: -150, y: 0, z: 0 }, overrides: {}, parentId: '' },
{ id: 'o2', assetId: 'crate', name: 'Blue crate', position: { x: 120, y: -80, z: 0 }, overrides: { width: 140, color: 0x4488ff }, parentId: '' },
{ id: 'o3', assetId: 'cam', name: '', position: { x: 0, y: 0, z: 0 }, overrides: {}, parentId: '' },
// The mover is parented to the red crate (its owner); its position is local to it.
{ id: 'o4', assetId: 'mover', name: '', position: { x: 0, y: 110, z: 0 }, overrides: {}, parentId: 'o1' },
],
},
{ id: 'crate', type: 'sprite', name: 'Crate', props: { width: 100, height: 60, color: 0xe0553f } },
{ id: 'cam', type: 'camera', name: 'Main camera', props: { width: 640, height: 360, zoom: 1 } },
{
id: 'mover',
type: 'behavior',
name: 'Mover',
props: { speed: 200 },
variables: [{ key: 'speed', label: 'speed', kind: 'number', default: 0 }],
graph: moverGraph,
},
],
};
const url = `${baseUrl}api/index.php?r=projects/${projectId}`;
const current = await fetch(url);
if (!current.ok) {
console.error(`GET failed: ${current.status}`);
process.exit(1);
}
const { revision } = await current.json();
const res = await fetch(url, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ revision, project }) });
const body = await res.json();
if (!res.ok) {
console.error('PUT failed', res.status, body);
process.exit(1);
}
console.log(`seeded ${projectId} → revision ${body.revision}`);