Files
feuerwerk/tools
adminandClaude Opus 5.5 38e0f656be
game-maker / gate (push) Successful in 3m32s
game-maker / suite (push) Successful in 10m45s
Split a struct output into one pin per field (#256)
Reading one field of a struct needed its own Expand node, even where
the graph already knows the struct type. A split output shows the
fields directly on the node, so a Find … Match test becomes a single
Equals and the wires keep running left to right.

- Right-clicking an output pin offers "Split into <Type> fields" when
  the type is known and "Split as …" for every other struct asset.
  The output is replaced by one pin per field with the field's kind.
- The type is known for typed struct variables, typed Pack/Expand,
  fields of another split and item of For each, Find, Match and Item
  at over a typed list (portSplits.ts).
- Right-clicking a field pin offers "Recombine". Splitting drops the
  edges of the whole output, recombining drops the field edges. One
  undo step brings them back.
- The split is stored as GraphNode.splits and saved with the graph.
  Copy and paste carry it along.
- Field pins follow the struct asset like a typed Expand. A new field
  gets a pin, a removed field loses pin and edge, a renamed field keeps
  its edge. Deleting the asset keeps the last fields. The delete dialog
  counts splits, so it now says "node(s)" instead of "Pack/Expand
  node(s)".
- Renaming a variable carries its split and the field edges along.
- At run time the node still produces the whole value. A field pin
  reads its field like Expand, a missing field reads as empty.
- Limits: outputs only, one level, behavior graphs only.

Tests:
- ./check.sh: 185 files, 2706 tests, CHECK EXIT 0
- e2e GM_STEPS=1-6,54,55: ALL PASSED, 303 checks
- New port-splits.test.ts with 12 tests. e2e 6z-vi with 3 checks
  using a real mouse: split Find.item, wire item.Name into the test
  and Match.item.Amount into the log (logs 7), recombine.
- Counter-checks: without field reads in the interpreter, without
  rename in the split, without moving edges on rename and without
  cleanup on field removal one unit test fails each. In the browser,
  without field reads nothing is logged and without type inference
  the split entry is missing.
- Check total in README: 1520.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-28 11:33:38 +02:00
..
Plugins belong to the project, and they load before it: the project file gained the field plugins: ["demo-plugin.js"] (default empty, no formatVersion bump), the Plugins tab's switch writes into it as an ordinary undo step (SetPluginActiveCommand) instead of into a server-wide plugins.json, and the start order is turned around - startPlugins only fetches the list of files, then editor.boot() runs and ProjectStore.load(id, prepare) hands the raw JSON through before it is deserialized, where pluginsOf(raw) reads the list and PluginManager.syncTo() activates exactly those; that is the point of the issue, because what a plugin registers has to stand there before normalizeGraph would throw it away as unknown (#126, #127), a project switch first stops what the new project does not name and then starts what it does, a file the server does not have is passed over silently, and after signing out the manager is dead so a late event cannot start anything in a torn-down session; on the server plugins.json, PluginStore::setActive, isActive, the route PUT ?r=plugins/{file} and the 403 for inactive modules are gone and GET ?r=plugins only answers {file,bytes,updatedAt}, which makes every plugin file fetchable - the consequence accepted in #117, written down in the wiki for #115 and #116; publishPlugins(root) only copies files now, the seeder switches the demo plugin on in the fixture project, and the Plugins tab carries a puzzle piece as its icon while only a plugin's own tab still goes without one (the knob and the socket are cubic curves, not arcs, which Pixi's parser draws as a spike after an L); 3 new e2e checks in module 38 and 5 new unit tests cover the project as the owner of the switch, its undo, the order, pluginsOf against crude input and an unknown file name (#119)
2026-09-20 14:24:27 +02:00