Finish the struct and list leftovers: inline lists, list fields, item kinds

An unconnected list input is a button into the List tab instead of a number
field; a struct field can hold a list, so ListSlot carries an optional field
name and the three owner cases only say what sits at a key; and a list
variable picks its item kind in the inspector (marker doubles as the chooser),
so a list of structs no longer has to be born from a project file.

The declaration keeps the storable shapes finite: a struct field may be a list,
but that list holds primitives only, so list->struct->primitive and
struct->list->primitive are the two deepest forms.

check 674, e2e 483, jump-run 24, Tetris 19.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
rootandClaude Opus 5 committed 2026-09-10 16:36:15 +02:00
1 parent fe3c63c48c
commit 10d030376a
18 files changed
+984 -184

No files matched your search

+11 -1
View File
@@ -3,7 +3,7 @@ import type { PropertyDef } from '../properties/PropertySchema';
import type { Graph, GraphNode, PortType } from './Graph';
import type { BehaviorLookup } from './lookup';
import type { NodeContext } from './NodeContext';
import { asBoolean, asNumber, asString, type Value } from './values';
import { asBoolean, asList, asNumber, asString, type Value } from './values';
export interface PortDef {
key: string;
@@ -135,6 +135,16 @@ export function inlineInputDef(port: PortDef): PropertyDef {
case 'string':
case 'any':
return { key: port.key, label: port.label, kind: 'text', default: asString(port.default ?? '') };
// No port declares an item kind, so an inline list reads as numbers – the same default
// `+ Variable ▸ List` picks. The graph types a list as a list either way.
case 'list':
return {
key: port.key,
label: port.label,
kind: 'list',
default: asList(port.default),
items: 'number',
};
default:
return {
key: port.key,