Files
feuerwerk/tools/seed-e2e.mjs
T
rootandClaude Opus 5 d54a620ebd Add ESLint and Prettier, and close the node test gaps
Tooling:
- Prettier as the single formatting authority (110 columns, single quotes,
  measured against the existing style); Markdown excluded because table-cell
  padding turns the README glossary into 1000-character lines.
- Type-aware ESLint ending in eslint-config-prettier, so a rule always means
  "this is a bug", never "this looks different".
- .editorconfig and an `npm run check` that runs typecheck, lint, format and
  tests in one go.

Findings fixed on the first run: three more duplicate imports, four
String(unknown) calls (parameter types narrowed instead of casts), two dead
initialisers, two redundant casts, a console.log for a real error. Two
warnings were false here and are disabled with a reason in place.

Tests 132 -> 269:
- node-catalog.test.ts covers every node with a run(), with a guard that fails
  when a new node has no row.
- behavior-events.test.ts covers the ten event nodes through a running World,
  checking timing rather than existence.
- Input's state machine (press/release/releaseAll) is reachable without DOM
  events now; the DOM handlers are thin adapters.

Compare fell back to == without a configured operator although the schema
default is <; aligned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:02:22 +02:00

102 lines
3.7 KiB
JavaScript

#!/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: PATH=/opt/node22/bin:$PATH 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: 1,
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);