Files
feuerwerk/tools/lib
adminandClaude Opus 5.5 f9428c5bc2 Let a game take a song's automation lane over and give it back (#338)
A game should be able to steer a lane of a song, the filter of the
pads in a fight, the pan of a track when the player turns, and later
hand it back to the curve the composer drew. Set song lane holds a
lane of a track at a value, Release song lane glides it back.

- Set song lane takes playback, track ("Song / Track"), lane, value,
  fade and quantize (Next bar by default). lane is volume, pan or a
  parameter name, with or without "param:".
- From where the lane stands it goes over fade to value and stays.
  The value is clamped to the lane's range. It replaces the lane and
  is not mixed with it (decision 10).
- Release song lane glides over fade back to the curve, to where the
  curve stands at the end of the fade. Then the lane follows the
  curve again.
- The override sits in the Scheduler, where the lane marks are made.
  Volume, pan and parameters go one way. The maths is pure functions
  in the new module laneHolds.ts.
- Notes that start during a parameter hold get the held value. A
  Switch song to the same song keeps the holds.
- The holds are a list per lane. The running one holds until the next
  one lands. A key held down fires the node on every beat, and with a
  single hold per lane the new call replaced the running one before it
  landed, so the lane fell back to the curve. e2e 65 found this.
- A track without that lane and a baked song write a line to the log
  (with a hint at "live tracks").
- The test harness knows the keys l and r.

Tests:
- Unit: 24 new (lane-holds 14, song-play 5, sound-library 2, node
  catalog 3), affected groups 748/748.
- Counter-probes: 12 bends, all red.
- e2e 65 on atx: ALL PASSED, 76 checks. New 65k5: the hold landed on
  the bar line, curve until 0.02 s before, -40 dB 0.14 s after, no
  values between. It stood 1.8 s. The release began at -39.8 dB and
  followed the curve again from 0.55 s on. With one hold per lane
  65k5 is red.
- Gate on atx: CHECK EXIT 0, 335 files, 5176 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 07:22:12 +01: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
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