#!/usr/bin/env node /** * Writes the fixture scene tools/e2e.mjs asserts against: two top-level crates with a collider * child each, a camera, the Mover behavior owning the red crate and a Spawner. The objects are * uniquely named and positioned exactly where the checks expect them. * * Usage: node tools/seed-e2e.mjs [projectId] [baseUrl] */ import { edge, node, sceneObject, variable } from './lib/builders.mjs'; import { PROJECTS, cliArgs, writeProject } from './lib/projects.mjs'; const { projectId, baseUrl } = cliArgs('seed-e2e.mjs', PROJECTS.fixture); /** * "Mover" 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). "Collide with * solids" stops the owner's solid colliders at other solid colliders. */ const moverGraph = { nodes: [ node('n-update', 'OnUpdate', 0, 0), node('n-owner', 'Owner', 0, 120), node('n-axis', 'AxisInput', 0, 200), node('n-speed', 'GetVariable', 0, 400, { variable: 'speed' }), node('n-move', 'Move', 340, 0, { collide: true }), ], edges: [ edge('e1', 'n-update', 'exec', 'n-move', 'exec'), edge('e6', 'n-update', 'dt', 'n-move', 'dt'), edge('e2', 'n-owner', 'object', 'n-move', 'object'), edge('e3', 'n-axis', 'x', 'n-move', 'dx'), edge('e4', 'n-axis', 'y', 'n-move', 'dy'), edge('e5', 'n-speed', 'value', 'n-move', 'scale'), ], }; /** "Spawner": pressing Space places a new Crate at world (0, 150) and logs its name. */ const spawnerGraph = { nodes: [ node('s-key', 'OnKeyDown', 0, 0, { key: ' ' }), node('s-spawn', 'Spawn', 260, 0, { asset: 'crate', y: 150 }), node('s-log', 'Log', 520, 0), ], edges: [ edge('s-e1', 's-key', 'exec', 's-spawn', 'exec'), edge('s-e2', 's-spawn', 'exec', 's-log', 'exec'), edge('s-e3', 's-spawn', 'object', 's-log', 'message'), ], }; const project = { formatVersion: 2, id: projectId, name: 'E2E fixture', activeSceneId: 'scene1', assets: [ { id: 'scene1', type: 'scene', name: 'Level 1', props: { backgroundColor: 0x22252c }, objects: [ sceneObject('o1', 'crate', { x: -150 }), sceneObject('o2', 'crate', { name: 'Blue crate', x: 120, y: -80, overrides: { width: 140, color: 0x4488ff }, }), sceneObject('o3', 'cam'), // The Mover is parented to the red crate (its owner); its position is local to it. sceneObject('o4', 'mover', { y: 110, parentId: 'o1' }), // Both crates carry the shared collider as a centred child; the blue one is widened to // match its 140-wide sprite override. sceneObject('oc1', 'collider', { parentId: 'o1' }), sceneObject('oc2', 'collider', { parentId: 'o2', overrides: { width: 140 } }), // Top-level spawner (no owner) left of the red crate: Space spawns a crate. sceneObject('o5', 'spawner', { x: -300 }), ], }, { 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: 'collider', type: 'collider', name: 'Crate collider', props: { shape: 'box', width: 100, height: 60, radius: 50, isTrigger: false }, }, { id: 'mover', type: 'behavior', name: 'Mover', props: { speed: 200 }, variables: [variable('speed', 'number', 0)], graph: moverGraph, }, { id: 'spawner', type: 'behavior', name: 'Spawner', props: {}, variables: [], graph: spawnerGraph }, ], }; await writeProject(projectId, baseUrl, project);