From 526b1da7f4a9c26d2643aa2cd9173260f5298a40 Mon Sep 17 00:00:00 2001 From: MelekTaus Date: Sun, 4 Oct 2026 18:44:04 +0200 Subject: [PATCH] Add a Get world position node with just the world x and y Get position hands out four numbers, local and world. A graph that only needs where an object is in the world had to pick the two world ports out of four and leave the local ones dangling. - Get world position has one object input and the outputs x and y. It reads the same worldPositionOf as Get position, so a child adds every parent's position in. - Without an object it reports the origin, like Get position. Tests: - Node catalog: a top-level object, a child under a parent and no object (3 cases). - node-catalog and hierarchy: 2 files, 378 tests, all green. The full gate was not run for this commit, CI covers it. Co-Authored-By: Claude Opus 5.5 --- src/core/graph/nodes/data/GetWorldPosition.ts | 19 +++++++++++++++++++ src/core/graph/nodes/index.ts | 2 ++ tests/core/node-catalog.test.ts | 13 +++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 src/core/graph/nodes/data/GetWorldPosition.ts diff --git a/src/core/graph/nodes/data/GetWorldPosition.ts b/src/core/graph/nodes/data/GetWorldPosition.ts new file mode 100644 index 00000000..a2a9cbd0 --- /dev/null +++ b/src/core/graph/nodes/data/GetWorldPosition.ts @@ -0,0 +1,19 @@ +import { worldPositionOf } from '../../NodeContext'; +import type { NodeDef } from '../../NodeRegistry'; +import { asEntity } from '../../values'; +import { num, obj } from '../shared'; + +export const GetWorldPosition: NodeDef = { + type: 'GetWorldPosition', + label: 'Get world position', + category: 'data', + description: 'The position of an object in world units, with every parent added in.', + inputs: [obj('object')], + 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: world.x, y: world.y } }; + }, +}; diff --git a/src/core/graph/nodes/index.ts b/src/core/graph/nodes/index.ts index 7e2754b1..216b1ebe 100644 --- a/src/core/graph/nodes/index.ts +++ b/src/core/graph/nodes/index.ts @@ -44,6 +44,7 @@ import { FindText } from './data/FindText'; import { FirstNotEmpty } from './data/FirstNotEmpty'; import { Floor } from './data/Floor'; import { GetPosition } from './data/GetPosition'; +import { GetWorldPosition } from './data/GetWorldPosition'; import { GetZ } from './data/GetZ'; import { ChildByName } from './data/ChildByName'; import { Children } from './data/Children'; @@ -201,6 +202,7 @@ export const BUILT_IN_NODES: readonly NodeDef[] = [ IsEnabled, Properties, GetPosition, + GetWorldPosition, GetZ, TextureSize, AnimationPlaying, diff --git a/tests/core/node-catalog.test.ts b/tests/core/node-catalog.test.ts index da103638..fa80a379 100644 --- a/tests/core/node-catalog.test.ts +++ b/tests/core/node-catalog.test.ts @@ -752,6 +752,19 @@ const CASES: Record = { outputs: { x: 0, y: 0, worldX: 0, worldY: 0 }, }, ], + GetWorldPosition: [ + { + name: 'a top-level object is at its own position', + inputs: { object: at('A', 10, 20) }, + outputs: { x: 10, y: 20 }, + }, + { + name: 'a child is at the summed position of its parents', + inputs: { object: { ...at('child', 10, 20), parent: at('parent', 100, 200) } }, + outputs: { x: 110, y: 220 }, + }, + { name: 'no object is the origin', inputs: { object: null }, outputs: { x: 0, y: 0 } }, + ], GetZ: [ { name: 'a child reports its own z and the z summed up with its parents',