Commit Graph
6 Commits
Author SHA1 Message Date
rootandClaude Opus 5 7c63c884ef Replace the five variable nodes with one Variables node
A single node now lists any number of variables. Every entry is an output
that reads the current value whenever it is pulled; an entry switched to
Set is also an input and is written when the flow arrives. Exec pins only
exist while at least one entry writes, and all inputs are read before any
write, so one node can swap two variables.

Get/Set variable, Get/Set variables and Variable are gone. Old project
files are converted on load: each old node becomes a Variables node with
the same variables, edges and typed values.

A written port without a typed value now shows the zero of its kind on
the node body, matching what the inspector shows and what the run writes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 16:56:24 +02:00
root 3c76106fd2 Let a Sequence grow an output as you connect the last one
The Outputs setting is gone. A Sequence now keeps one free output below the
last connected one: nothing plugged in is one output, connecting the spare
grows a new one, unplugging the bottom edge shrinks it back.

It counts the last *connected* port rather than the number of edges, so
unplugging a middle one leaves a gap instead of silently dropping an edge.

Removing the setting also removes a bug it caused. Typing in the Outputs field
did nothing and the arrow keys did nothing, while dragging the value worked:
onInput fires per keystroke, the preview writes into node.params, that emits
'project', and Inspector.refreshValues() sees the node's signature change --
the port list is part of it -- so it rebuilds and destroys the row being typed
in. A drag survives because it keeps receiving globalpointermove on the old
widget. refreshValues() has no focus guard where refreshLive() does; the trap
is still there for the next typed field that changes a node's shape.

Ports that depend on the edges around a node mean derivePorts needs the graph,
not just the params, so resolveDef and portSignature take it too. And a node
whose ports are derived cannot know how many it has from its type, so run is
handed the definition resolved for it.
2026-09-10 08:32:14 +02:00
root 2cf788eedd Let a value be a bundle of named fields
PropertyValue was number | string | boolean | list. A struct joins it, which
costs two things the typechecker found rather than I did.

An object on a data edge used to mean a live entity, so asEntity would have
taken a struct for one and asString would have read .name off it. EntityHandle
now carries a symbol brand – a symbol so no field name can impersonate it, and
it never serializes, which suits a thing that exists only while the game runs.
It is built in exactly one place.

String(value) would have written a struct as [object Object] at 39 call sites.
They go through textOf(), which is identical for primitives.

normalizeGraph dropped everything but primitives from node params, so the List
node lost its value on every save ([3,1,4] round-tripped to undefined).
Variables were spared: they have a schema, params have none.
2026-09-10 08:14:18 +02:00
rootandClaude Opus 5 ead649eec3 Resolve container content from the template instead of copying it
A scene now stores only the container object; its content is resolved from
the template on every read, with deviations kept as sparse instanceEdits on
the container object. This drops the propagation bookkeeping entirely --
templateSync.ts is gone and the three structural gaps (add, remove, reparent)
cannot diverge any more.

Values stay editable on an instance, structure does not; Unpack writes the
content into the scene, keeping ids. Play mode bakes containers into the
throwaway copy before entities are built. No migration: formatVersion is 2
and the seeders write the new format.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 21:09:53 +02:00
rootandClaude Opus 5 d54a620ebd Add ESLint and Prettier, and close the node test gaps
Tooling:
- Prettier as the single formatting authority (110 columns, single quotes,
  measured against the existing style); Markdown excluded because table-cell
  padding turns the README glossary into 1000-character lines.
- Type-aware ESLint ending in eslint-config-prettier, so a rule always means
  "this is a bug", never "this looks different".
- .editorconfig and an `npm run check` that runs typecheck, lint, format and
  tests in one go.

Findings fixed on the first run: three more duplicate imports, four
String(unknown) calls (parameter types narrowed instead of casts), two dead
initialisers, two redundant casts, a console.log for a real error. Two
warnings were false here and are disabled with a reason in place.

Tests 132 -> 269:
- node-catalog.test.ts covers every node with a run(), with a guard that fails
  when a new node has no row.
- behavior-events.test.ts covers the ten event nodes through a running World,
  checking timing rather than existence.
- Input's state machine (press/release/releaseAll) is reachable without DOM
  events now; the DOM handlers are thin adapters.

Compare fell back to == without a configured operator although the schema
default is <; aligned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 10:02:22 +02:00
rootandClaude Fable 5.1 1eb28314cf Refactoring: one file per node, consistent comments, shared helpers, split large modules
- Graph: nodes.ts split into nodes/<category>/<Type>.ts (62 files) with
  shared.ts factories and index.ts registry; NodeContext/values/NodeRegistry
  separated, writeTyped() replaces duplicated typed writes
- Comments: one style (JSDoc on non-obvious exports, // for decisions and
  traps), wrong/stale comments fixed or removed, ids.ts now real 10 base-36 chars
- Core: chainOf, shared worldPosition/editorPosition core, commands/require.ts,
  commands/naming.ts, util/list.ts, setBagValue/toPosition/propDef; dead code
  removed (isBehaviorAsset, SCENE_OBJECT_SCHEMA, CommandStack.subscribe,
  Input.axis, setMode, titleText, World.worldPosition, unused ctor params)
- Editor: Inspector split into inspector/ sections, App.ts into Editor.ts +
  debugHook.ts + shortcuts.ts, Viewport into items.ts + symbols.ts, shared
  "Add collider" action, unified type labels/swatches
- UI toolkit: Widget.trackHover/onPointerRelease, drawControlBox, math helpers,
  Popup.openBelow, Menu/Dialog/ColorPicker/ListRow in own files, named Theme sizes
- Tools: seed-demo/smoke-demo and demo-check project removed, tools/lib
  (harness, projects, builders), e2e.mjs as runner over tools/e2e/*.mjs sections
- Tests: tests/helpers.ts replaces copied fixtures and NodeContext doubles

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-08 08:37:22 +02:00