From 2da07599d8c298f3920889972d854cc2d6c06871 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Sun, 4 Oct 2026 19:13:58 +0200 Subject: [PATCH] Let Get position give only the local x and y Get world position now covers the world coordinates. Two nodes that both offer world x and y made it unclear which one to take. No project uses the world outputs of Get position any more. - Get position drops its world x and world y outputs and its description points to Get world position. - Old snapshots with edges on those outputs still load. The edges hang on ghost ports and the node warns about them. - The unit tests in hierarchy and raycast and the graphs in e2e 43 use Get world position where they read the world coordinates. Tests: - node-catalog, hierarchy, raycast: 3 files, 417 tests, all green - e2e 43 on melektaus-atx: ALL PASSED, 17 checks Co-Authored-By: Claude Opus 5.5 --- src/core/graph/nodes/data/GetPosition.ts | 8 +++----- tests/core/hierarchy.test.ts | 10 ++++++---- tests/core/node-catalog.test.ts | 14 +++++--------- tests/core/raycast.test.ts | 4 ++-- tools/e2e/43-queries.mjs | 16 ++++++++-------- 5 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/core/graph/nodes/data/GetPosition.ts b/src/core/graph/nodes/data/GetPosition.ts index e459a4fe..93215e70 100644 --- a/src/core/graph/nodes/data/GetPosition.ts +++ b/src/core/graph/nodes/data/GetPosition.ts @@ -1,4 +1,3 @@ -import { worldPositionOf } from '../../NodeContext'; import type { NodeDef } from '../../NodeRegistry'; import { asEntity } from '../../values'; import { num, obj } from '../shared'; @@ -7,13 +6,12 @@ export const GetPosition: NodeDef = { type: 'GetPosition', label: 'Get position', category: 'data', - description: 'The position of an object: local to its parent (x/y) and in world units (world x/y).', + description: 'The position of an object local to its parent. Get world position gives it in world units.', inputs: [obj('object')], - outputs: [num('x'), num('y'), num('worldX', 'world x'), num('worldY', 'world y')], + outputs: [num('x'), num('y')], params: [], run: (_ctx, inputs) => { const target = asEntity(inputs.object); - const world = target ? worldPositionOf(target) : { x: 0, y: 0 }; - return { outputs: { x: target?.x ?? 0, y: target?.y ?? 0, worldX: world.x, worldY: world.y } }; + return { outputs: { x: target?.x ?? 0, y: target?.y ?? 0 } }; }, }; diff --git a/tests/core/hierarchy.test.ts b/tests/core/hierarchy.test.ts index 7cbe4161..25b3dac0 100644 --- a/tests/core/hierarchy.test.ts +++ b/tests/core/hierarchy.test.ts @@ -237,7 +237,7 @@ describe('runtime hierarchy', () => { expect(world.entities).toHaveLength(0); }); - it('Get position exposes local and world coordinates, Parent walks up', () => { + it('Get position and Get world position tell local from world, Parent walks up', () => { const parent = { ...fakeEntity('p', 100), y: 20 }; const child = { ...fakeEntity('c', 5), y: 5, parent }; // On start → Log(world x of self) → Log(local x of self) → Log(world x of self's parent) @@ -245,9 +245,10 @@ describe('runtime hierarchy', () => { nodes: [ { id: 'start', type: 'OnStart', x: 0, y: 0, params: {} }, { id: 'self', type: 'Self', x: 0, y: 0, params: {} }, + { id: 'wpos', type: 'GetWorldPosition', x: 0, y: 0, params: {} }, { id: 'pos', type: 'GetPosition', x: 0, y: 0, params: {} }, { id: 'par', type: 'Parent', x: 0, y: 0, params: {} }, - { id: 'ppos', type: 'GetPosition', x: 0, y: 0, params: {} }, + { id: 'ppos', type: 'GetWorldPosition', x: 0, y: 0, params: {} }, { id: 'log1', type: 'Log', x: 0, y: 0, params: {} }, { id: 'log2', type: 'Log', x: 0, y: 0, params: {} }, { id: 'log3', type: 'Log', x: 0, y: 0, params: {} }, @@ -257,11 +258,12 @@ describe('runtime hierarchy', () => { { id: 'e2', from: { node: 'log1', port: 'exec' }, to: { node: 'log2', port: 'exec' } }, { id: 'e3', from: { node: 'log2', port: 'exec' }, to: { node: 'log3', port: 'exec' } }, { id: 'e4', from: { node: 'self', port: 'object' }, to: { node: 'pos', port: 'object' } }, + { id: 'e4b', from: { node: 'self', port: 'object' }, to: { node: 'wpos', port: 'object' } }, { id: 'e5', from: { node: 'self', port: 'object' }, to: { node: 'par', port: 'object' } }, { id: 'e6', from: { node: 'par', port: 'parent' }, to: { node: 'ppos', port: 'object' } }, - { id: 'e7', from: { node: 'pos', port: 'worldX' }, to: { node: 'log1', port: 'message' } }, + { id: 'e7', from: { node: 'wpos', port: 'x' }, to: { node: 'log1', port: 'message' } }, { id: 'e8', from: { node: 'pos', port: 'x' }, to: { node: 'log2', port: 'message' } }, - { id: 'e9', from: { node: 'ppos', port: 'worldX' }, to: { node: 'log3', port: 'message' } }, + { id: 'e9', from: { node: 'ppos', port: 'x' }, to: { node: 'log3', port: 'message' } }, ], }; const ctx = fakeContext({ self: child, owner: parent, variables: {} }); diff --git a/tests/core/node-catalog.test.ts b/tests/core/node-catalog.test.ts index fa80a379..9a758569 100644 --- a/tests/core/node-catalog.test.ts +++ b/tests/core/node-catalog.test.ts @@ -737,20 +737,16 @@ const CASES: Record = { ], GetPosition: [ { - name: 'local and world position of a top-level object are the same', + name: 'a top-level object is at its own position', inputs: { object: at('A', 10, 20) }, - outputs: { x: 10, y: 20, worldX: 10, worldY: 20 }, + outputs: { x: 10, y: 20 }, }, { - name: 'a child reports its local position and the summed world position', + name: 'a child reports its position local to the parent', inputs: { object: { ...at('child', 10, 20), parent: at('parent', 100, 200) } }, - outputs: { x: 10, y: 20, worldX: 110, worldY: 220 }, - }, - { - name: 'no object is the origin', - inputs: { object: null }, - outputs: { x: 0, y: 0, worldX: 0, worldY: 0 }, + outputs: { x: 10, y: 20 }, }, + { name: 'no object is the origin', inputs: { object: null }, outputs: { x: 0, y: 0 } }, ], GetWorldPosition: [ { diff --git a/tests/core/raycast.test.ts b/tests/core/raycast.test.ts index 1ed78ec0..18113a5e 100644 --- a/tests/core/raycast.test.ts +++ b/tests/core/raycast.test.ts @@ -483,7 +483,7 @@ describe.each(COLLISION_SYSTEMS)('$system: every hit on the line (#157)', ({ phy const logCount = edit.addNode('Log'); const logDistances = edit.addNode('Log'); const second = edit.addNode('ItemAt', { index: 1 }); - const where = edit.addNode('GetPosition'); + const where = edit.addNode('GetWorldPosition'); const logSecond = edit.addNode('Log'); edit.wire([ [update, 'exec', ray, 'exec'], @@ -494,7 +494,7 @@ describe.each(COLLISION_SYSTEMS)('$system: every hit on the line (#157)', ({ phy [ray, 'objects', second, 'list'], [second, 'item', where, 'object'], [logDistances, 'exec', logSecond, 'exec'], - [where, 'worldY', logSecond, 'message'], + [where, 'y', logSecond, 'message'], ]); const r = run(s, physics); r.frame(1 / 60); diff --git a/tools/e2e/43-queries.mjs b/tools/e2e/43-queries.mjs index aca84337..23d1fcce 100644 --- a/tools/e2e/43-queries.mjs +++ b/tools/e2e/43-queries.mjs @@ -46,14 +46,14 @@ const eyeGraph = { nodes: [ node('qe-update', 'OnUpdate', 0, 0), node('qe-owner', 'Owner', 0, 160), - node('qe-where', 'GetPosition', 250, 160), + node('qe-where', 'GetWorldPosition', 250, 160), node('qe-ray', 'Raycast', 500, 0, { dirX: 0, dirY: 1, length: 500 }), ], edges: [ edge('qe-e1', 'qe-update', 'exec', 'qe-ray', 'exec'), edge('qe-e2', 'qe-owner', 'object', 'qe-where', 'object'), - edge('qe-e3', 'qe-where', 'worldX', 'qe-ray', 'fromX'), - edge('qe-e4', 'qe-where', 'worldY', 'qe-ray', 'fromY'), + edge('qe-e3', 'qe-where', 'x', 'qe-ray', 'fromX'), + edge('qe-e4', 'qe-where', 'y', 'qe-ray', 'fromY'), ], }; @@ -81,7 +81,7 @@ const allEyeGraph = { nodes: [ node('qa-timer', 'OnTimer', 0, 320, { interval: 0.2 }), node('qa-owner', 'Owner', 0, 160), - node('qa-where', 'GetPosition', 250, 160), + node('qa-where', 'GetWorldPosition', 250, 160), node('qa-ray', 'RaycastAll', 500, 0, { dirX: 0, dirY: 1, length: 500 }), node('qa-count', 'Log', 750, 0), node('qa-distances', 'Log', 1000, 0), @@ -94,8 +94,8 @@ const allEyeGraph = { edges: [ edge('qa-e1', 'qa-timer', 'exec', 'qa-ray', 'exec'), edge('qa-e2', 'qa-owner', 'object', 'qa-where', 'object'), - edge('qa-e3', 'qa-where', 'worldX', 'qa-ray', 'fromX'), - edge('qa-e4', 'qa-where', 'worldY', 'qa-ray', 'fromY'), + edge('qa-e3', 'qa-where', 'x', 'qa-ray', 'fromX'), + edge('qa-e4', 'qa-where', 'y', 'qa-ray', 'fromY'), edge('qa-e5', 'qa-ray', 'exec', 'qa-count', 'exec'), edge('qa-e6', 'qa-ray', 'count', 'qa-count', 'message'), edge('qa-e7', 'qa-count', 'exec', 'qa-distances', 'exec'), @@ -105,8 +105,8 @@ const allEyeGraph = { edge('qa-e11', 'qa-distances', 'exec', 'qa-log-name', 'exec'), edge('qa-e12', 'qa-name', 'name', 'qa-log-name', 'message'), edge('qa-e13', 'qa-log-name', 'exec', 'qa-one', 'exec'), - edge('qa-e14', 'qa-where', 'worldX', 'qa-one', 'fromX'), - edge('qa-e15', 'qa-where', 'worldY', 'qa-one', 'fromY'), + edge('qa-e14', 'qa-where', 'x', 'qa-one', 'fromX'), + edge('qa-e15', 'qa-where', 'y', 'qa-one', 'fromY'), edge('qa-e16', 'qa-one', 'exec', 'qa-log-one', 'exec'), edge('qa-e17', 'qa-one', 'distances', 'qa-log-one', 'message'), ],