Make texture and colour full kinds and drop the load-time migrations

- `Texture` and `Color` can be picked as a variable kind, a struct field
  kind and a declared port kind; a new `Texture` node hands a picture id
  into the graph. Declared, a texture is its bare id – the `$texture` tag
  stays a list-only thing.
- The `String` node is labelled "Text" like its kind; the type id stays.
- Whole-number inputs (`Item at`, `Set item`, `Sub list`, `Fill`,
  `Repeat`, `Substring`, `To text`) show no decimals (`int()` in shared.ts).
- All server projects are reseeded, so `legacyNodes.ts`,
  `migrateDeclaredLists` and the `ownerId` fallback go, with their tests.
- Note `reseed-because-of-list` moved to done/; new note `refactor-types`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-12 14:06:14 +02:00
1 parent 11c900c998
commit 8a7185948d
39 files changed
+378 -765

No files matched your search

+38 -1
View File
@@ -46,7 +46,7 @@ const logicGraph = (walkId) => ({
node('an-add', 'Add', 300, 200, { b: 1 }),
node('an-owner', 'Owner', 300, 360),
node('an-wear', 'Properties', 600, 0, { ...propertiesOf('sprite'), texture: 'an-run' }, [
written('texture', 'text'),
written('texture', 'texture'),
]),
],
edges: [
@@ -398,6 +398,43 @@ export async function animation(t) {
JSON.stringify({ texture: worn?.props.texture, clock: worn?.animation, after }),
);
// 25l'. A picture is a kind of its own: the Texture node hands one into the graph, and a
// variable may be one. Both are picked, never typed.
const pickPicture = async (label, name) => {
const field = await json(`__gm.inspectorField(${JSON.stringify(label)}, true)`);
await click(field.x, field.y);
await sleep(200);
await typeText(name);
await sleep(150);
await press('Enter');
await sleep(300);
};
await mutate(`
const logic = __gm.state.project.assets.find((a) => a.id === 'an-logic');
logic.graph.nodes.push(${JSON.stringify(node('an-pic', 'Texture', 600, 300))});
logic.variables.push(${JSON.stringify(variable('pic', 'texture', ''))});
logic.props.pic = '';
__gm.state.select({ kind: 'node', assetId: 'an-logic', nodeId: 'an-pic', nodeIds: ['an-pic'] });
`);
await sleep(400);
await pickPicture('Value', walk.name);
const picNode = (await t.asset('an-logic')).graph.nodes.find((n) => n.id === 'an-pic');
const picRows = (await json("__gm.graph.nodeSettings('an-pic')")) ?? [];
check(
'the Texture node picks its picture and shows it by name',
picNode?.params.value === walk.id && picRows.some((r) => r.includes(walk.name)),
JSON.stringify({ params: picNode?.params, rows: picRows }),
);
await evaluate("__gm.state.select({ kind: 'asset', assetId: 'an-logic' })");
await sleep(400);
await pickPicture('pic', walk.name);
check(
'a texture variable is picked with the same picker',
(await t.asset('an-logic')).props.pic === walk.id,
JSON.stringify((await t.asset('an-logic')).props),
);
await shot('04b-texture-kind');
// 25m. Deleting the texture counts the animations that play its frames.
const again = await json(`__gm.assetRow(${JSON.stringify(strip)})`);
await click(again.x, again.y, 'right');