Enabled switch, text assets, mouse input and the jump-and-run example game

Engine additions that the example game needed:
- `enabled` as a shared property of every placeable asset (default on, an
  override on the scene object). A switched-off object is not drawn, does not
  collide and its behavior does not run - and neither does anything parented
  below it. Disabled objects are now hidden in the scene view as well, so the
  editor shows what the game shows; they stay in the hierarchy panel, which is
  where they are selected and switched back on.
- Asset type `text` (text, fontSize, color, align), rendered in scene and game.
- Pointer input in the game view: `On click`, `Mouse position`, `Mouse button`,
  `Is hovered`, hit-tested against colliders, else sprite/text footprints.
- New nodes: Set/Is enabled, Set text, Is asset, Name of, Equals, To text,
  Join text, Floor/Ceil/Round, Modulo, Random, Time, Restart game.

Tooling: shared CDP harness (tools/harness.mjs), central project registry with
a guard that keeps destructive scripts off the playground (tools/projects.mjs),
plus smoke suites for the demo scene and the jump-and-run game.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-07 20:52:10 +02:00
1 parent 4900d7bbf6
commit 76aa441dce
33 files changed
+1905 -301

No files matched your search

+3 -3
View File
@@ -133,8 +133,8 @@ describe('runtime hierarchy', () => {
});
it('Get position exposes local and world coordinates, Parent walks up', () => {
const parent = { id: 'p', name: 'p', x: 100, y: 20, z: 0, props: {}, parent: null };
const child = { id: 'c', name: 'c', x: 5, y: 5, z: 0, props: {}, parent };
const parent = { id: 'p', assetId: 'a-p', name: 'p', x: 100, y: 20, z: 0, props: {}, parent: null };
const child = { id: 'c', assetId: 'a-c', name: 'c', x: 5, y: 5, z: 0, props: {}, parent };
const graph = { nodes: [
{ id: 'start', type: 'OnStart', x: 0, y: 0, params: {} },
{ id: 'self', type: 'Self', x: 0, y: 0, params: {} },
@@ -156,7 +156,7 @@ describe('runtime hierarchy', () => {
{ id: 'e9', from: { node: 'ppos', port: 'worldX' }, to: { node: 'log3', port: 'message' } },
] };
const logs: string[] = [];
const ctx: NodeContext = { self: child, owner: parent, variables: {}, time: 0, dt: 0, findByName: () => null, isKeyDown: () => false, isTouching: () => false, moveAndSlide: () => ({ blockedX: false, blockedY: false }), log: (m) => logs.push(m), spawn: () => null, destroy: () => {}, stop: () => {} };
const ctx: NodeContext = { self: child, owner: parent, variables: {}, time: 0, dt: 0, findByName: () => null, isKeyDown: () => false, pointer: { x: 0, y: 0, inside: false, down: false, pressed: false, released: false }, hitTest: () => false, isTouching: () => false, moveAndSlide: () => ({ blockedX: false, blockedY: false }), log: (m) => logs.push(m), spawn: () => null, destroy: () => {}, stop: () => {}, restart: () => {} };
new GraphInterpreter(graph).fire('OnStart', ctx);
expect(logs).toEqual(['105', '5', '100']);
});