Title a collapsed Variables or Properties node by what it does

Collapsed, the node reads "Set 2 variables", "Get width" or "No properties";
expanded it is always "Variables" / "Properties". The Properties node shows
its object type (and behavior) as a line under the title instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-11 19:53:43 +02:00
1 parent 58f19a3451
commit 0376ae175d
11 files changed
+182 -69

No files matched your search

+52 -7
View File
@@ -186,7 +186,53 @@ export async function variableNodes(t) {
await sleep(300);
check('and undo points it back', (await portsOf('vp-get'))[0].key === 'vx');
// 23f. A Pack keeps declaring its own fields, but a variable that already carries the shape can
// 23f. Collapsed, the ports are out of sight, so the title says what the node does – and only then.
const titleOf = (id) => json(`__gm.graph.nodeLabel(${JSON.stringify(id)})`);
const toggle = async (id) => {
const chevron = await json(`__gm.graph.chevronAt(${JSON.stringify(id)})`);
await click(chevron.x, chevron.y);
await sleep(250);
};
/** `locate` matches exactly, so a title cut short by a too-narrow node is not found. */
const drawnWhole = async (text) => {
const canvas = await json('__gm.graph.canvasRect()');
const hits = await json(`__gm.locateAll(${JSON.stringify(text)})`);
return hits.some((p) => p.x > canvas.x && p.x < canvas.x + canvas.w);
};
await toggle('vp-set');
await toggle('vp-get');
const shut = { set: await titleOf('vp-set'), get: await titleOf('vp-get') };
check(
'collapsed, a node writing two variables says so, and one only reading two says that',
shut.set === 'Set 2 variables' &&
shut.get === 'Get 2 variables' &&
(await drawnWhole('Set 2 variables')) &&
(await drawnWhole('Get 2 variables')),
JSON.stringify(shut),
);
await shot('02b-collapsed-titles');
const narrow = (await json(`__gm.graph.nodeRect('vp-get')`)).w;
await clickLastSet();
const switched = await titleOf('vp-get');
check(
'switching one to Set while collapsed retitles it and resizes it to the new title',
switched === 'Set vy' &&
(await drawnWhole('Set vy')) &&
(await json(`__gm.graph.nodeRect('vp-get')`)).w < narrow,
JSON.stringify({ switched, narrow }),
);
await undo();
await sleep(300);
await toggle('vp-set');
await toggle('vp-get');
const open = [await titleOf('vp-set'), await titleOf('vp-get')];
check(
'expanded again, both are plain Variables nodes',
open.join() === 'Variables,Variables',
JSON.stringify(open),
);
// 23g. A Pack keeps declaring its own fields, but a variable that already carries the shape can
// hand it over. A color field arrives as a number port – the graph has no colors.
await mutate(`
const a = __gm.state.project.assets.find((x) => x.id === 'vp-logic');
@@ -232,7 +278,7 @@ export async function variableNodes(t) {
await sleep(300);
check('one undo takes all of them back', (await portsOf('vp-pack')).length === 0);
// 23g. A list of structs declares the shape of its items, which is the bundle a Pack builds for it.
// 23h. A list of structs declares the shape of its items, which is the bundle a Pack builds for it.
await click(from.x, from.y);
await sleep(200);
await clickLast('shapes (item)');
@@ -246,7 +292,7 @@ export async function variableNodes(t) {
await undo();
await sleep(300);
// 23h. A behavior's own inputs are not fields of a bundle, so the helper stays out of that section.
// 23i. A behavior's own inputs are not fields of a bundle, so the helper stays out of that section.
await mutate(`
__gm.state.project.assets.find((x) => x.id === 'vp-logic').graph.nodes.push(
${JSON.stringify(node('vp-start', 'BehaviorStart', 560, 600))},
@@ -262,7 +308,7 @@ export async function variableNodes(t) {
JSON.stringify(helper),
);
// 23i. From the palette the node comes empty; picking a variable titles it, and switched to Set
// 23j. From the palette the node comes empty; picking a variable keeps its title, and switched to Set
// it runs `vz = vz + 1` once a frame – its own output feeding its input via Add.
const nodeIds = async () => (await asset('vp-logic')).graph.nodes.map((n) => n.id);
const idsBefore = await nodeIds();
@@ -278,7 +324,6 @@ export async function variableNodes(t) {
const added = (await asset('vp-logic')).graph.nodes.find((n) => !idsBefore.includes(n.id));
check('the palette offers the Variables node', added?.type === 'Variables', JSON.stringify(added));
const variableId = added?.id ?? '';
const titleOf = (id) => json(`__gm.graph.nodeLabel(${JSON.stringify(id)})`);
const untitled = await titleOf(variableId);
const bare = !(await portAt(variableId, 'exec', false));
await clickLast('+ Variable');
@@ -286,8 +331,8 @@ export async function variableNodes(t) {
await sleep(300);
await clickLastSet();
check(
'it starts without pins, and picking its variable makes that the title',
untitled === 'Variables' && bare && (await titleOf(variableId)) === 'vz',
'it starts without pins, and picking its variable leaves the title Variables',
untitled === 'Variables' && bare && (await titleOf(variableId)) === 'Variables',
JSON.stringify({ untitled, bare, titled: await titleOf(variableId) }),
);
check('switched to Set it grows its flow pins', Boolean(await portAt(variableId, 'exec', false)));