Files
feuerwerk/src/editor/graph/beads.ts
T
rootandClaude Opus 5 656d61f187 Edit the graph during play and watch values and flow run through it
The graph was only locked by five edit-mode guards in GraphCanvas. The
running game reads the graph by reference each frame, so a new node, edge,
changed value, disconnect or undo takes effect from the next frame. Stop
discards these edits like everything else changed in play. A new On start
node does not fire for a behavior that has already started.

During play every data output shows the value it last produced, in the
highlight colour and refreshed ten times a second. Values are kept per
graph, because node ids are only unique within one; with several
instances the most recent value wins. The Variables node reads the live
variable bag, so only its own outputs are kept, as a snapshot.

Each time an exec edge fires, a bead runs along it in 0.3 s, at most one
every 0.15 s per edge, following the same curve the edge is drawn with.
Beads run on game time and freeze while paused; the game logic is
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 21:19:07 +02:00

41 lines
1.6 KiB
TypeScript

/** Seconds a bead takes from the source port to the target port. */
export const BEAD_TRAVEL = 0.3;
/** Shortest gap between two beads on one edge: an edge firing every frame shows a chain, not a solid line. */
export const BEAD_SPACING = 0.15;
/** Launch times of the beads on one edge, oldest first; drops those that have arrived. */
export function launchBead(times: number[], now: number): void {
const last = times[times.length - 1];
// The tolerance keeps a fire exactly one spacing later (nine frames at 60 fps) from rounding below it.
if (last !== undefined && now - last < BEAD_SPACING - 1e-9) return;
while (times.length > 0 && now - times[0]! > BEAD_TRAVEL) times.shift();
times.push(now);
}
/** How far each bead has come, 0 at the source and 1 at the target. */
export function beadsInFlight(times: readonly number[], now: number): number[] {
return times.map((t) => (now - t) / BEAD_TRAVEL).filter((p) => p >= 0 && p <= 1);
}
/** How far an edge's curve reaches out of its ports before it bends towards the other end. */
export function curveReach(x1: number, x2: number): number {
return Math.max(40, Math.abs(x2 - x1) * 0.5);
}
/** The point at `t` on the curve `bezier` draws from (x1, y1) to (x2, y2). */
export function curvePoint(
x1: number,
y1: number,
x2: number,
y2: number,
t: number,
): { x: number; y: number } {
const dx = curveReach(x1, x2);
const u = 1 - t;
const [a, b, c, d] = [u * u * u, 3 * u * u * t, 3 * u * t * t, t * t * t];
return {
x: a * x1 + b * (x1 + dx) + c * (x2 - dx) + d * x2,
y: a * y1 + b * y1 + c * y2 + d * y2,
};
}