Plugins in data/plugins are loaded at startup and can add a tab with a read-only node board, and the demo plugin shows every asset as a node (#113)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
2a390e52ff
commit
57a97ba94f
22 files changed
+1153
-57
No files matched your search
@@ -47,10 +47,8 @@ import { type Trace, TRACE_FADE } from '../../runtime/systems/BehaviorSystem';
|
||||
import { beadsInFlight, launchBead } from './beads';
|
||||
import {
|
||||
activeDrag,
|
||||
clamp,
|
||||
type DragPayload,
|
||||
drawBand,
|
||||
drawGrid,
|
||||
endDrag,
|
||||
onDragChange,
|
||||
pressCount,
|
||||
@@ -91,6 +89,7 @@ import { openAnnotationMenu, openLinkMenu, openNodeMenu } from './graphMenus';
|
||||
import { NodePalette, type PaletteAction } from './NodePalette';
|
||||
import { type PaletteEntry, paletteEntries } from './paletteEntries';
|
||||
import { NODE_WIDTH, NodeView, TITLE_HEIGHT } from './NodeView';
|
||||
import { drawGraphGrid, FIT_MARGIN, GRID_STEP, ZOOM_LIMITS, zoomedAbout } from './graphView';
|
||||
|
||||
/** One running instance's answer for a machine: which state it holds, and whose instance it is. */
|
||||
export interface LiveMachineState {
|
||||
@@ -100,16 +99,8 @@ export interface LiveMachineState {
|
||||
ownerId: string;
|
||||
}
|
||||
|
||||
/** Spacing of the background grid – and, with snapping on, of the positions a drag can leave. */
|
||||
const GRID_STEP = 24;
|
||||
/** Below this on-screen spacing the grid is noise rather than orientation, so it is dropped. */
|
||||
const MIN_GRID_STEP = 8;
|
||||
const MIN_ZOOM = 0.25;
|
||||
const MAX_ZOOM = 2.5;
|
||||
/** Stand-in node height for a node with no view yet – real nodes vary with their port count. */
|
||||
const NODE_HEIGHT_ESTIMATE = 80;
|
||||
/** Breathing room around the framed graph, so nodes do not touch the edge. */
|
||||
const FIT_MARGIN = 24;
|
||||
/** Pointer travel (screen pixels) before a press turns into a drag rather than a click. */
|
||||
const DRAG_THRESHOLD = 3;
|
||||
/** Live values change every frame; ten updates a second are still readable and cost far less text layout. */
|
||||
@@ -209,12 +200,11 @@ export class GraphCanvas extends Widget {
|
||||
this.on('pointerup', (e: FederatedPointerEvent) => this.onPointerUp(e));
|
||||
this.on('pointerupoutside', (e: FederatedPointerEvent) => this.onPointerUp(e));
|
||||
this.on('wheel', (e: FederatedWheelEvent) => {
|
||||
const local = this.toLocal(e.global);
|
||||
const before = this.screenToGraph(local.x, local.y);
|
||||
this.zoom = clamp(this.zoom * zoomFactor(e.deltaY), MIN_ZOOM, MAX_ZOOM);
|
||||
const after = this.screenToGraph(local.x, local.y);
|
||||
this.pan.x += (after.x - before.x) * this.zoom;
|
||||
this.pan.y += (after.y - before.y) * this.zoom;
|
||||
({ pan: this.pan, zoom: this.zoom } = zoomedAbout(
|
||||
{ pan: this.pan, zoom: this.zoom },
|
||||
this.toLocal(e.global),
|
||||
zoomFactor(e.deltaY),
|
||||
));
|
||||
this.applyView();
|
||||
e.preventDefault();
|
||||
});
|
||||
@@ -514,10 +504,7 @@ export class GraphCanvas extends Widget {
|
||||
this.applyView();
|
||||
return;
|
||||
}
|
||||
const framing = frameBoxes(boxes, { w: this.w, h: this.h }, FIT_MARGIN, {
|
||||
min: MIN_ZOOM,
|
||||
max: MAX_ZOOM,
|
||||
});
|
||||
const framing = frameBoxes(boxes, { w: this.w, h: this.h }, FIT_MARGIN, ZOOM_LIMITS);
|
||||
this.zoom = framing.zoom;
|
||||
this.pan = { x: framing.panX, y: framing.panY };
|
||||
this.applyView();
|
||||
@@ -1167,18 +1154,7 @@ export class GraphCanvas extends Widget {
|
||||
}
|
||||
|
||||
private syncGrid(): void {
|
||||
this.grid.clear();
|
||||
const step = GRID_STEP * this.zoom;
|
||||
if (step < MIN_GRID_STEP) return;
|
||||
// `pan` is where the graph origin sits on screen, but no axis lines: it marks nothing.
|
||||
drawGrid(this.grid, {
|
||||
originX: this.pan.x,
|
||||
originY: this.pan.y,
|
||||
step,
|
||||
w: this.w,
|
||||
h: this.h,
|
||||
alpha: 0.04,
|
||||
});
|
||||
drawGraphGrid(this.grid, { pan: this.pan, zoom: this.zoom }, this.w, this.h);
|
||||
}
|
||||
|
||||
/** Global screen position of a port (tests drive connections with it). */
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import type { Graphics } from 'pixi.js';
|
||||
import { clamp, drawGrid } from '../../ui';
|
||||
import type { Point } from '../framing';
|
||||
|
||||
/**
|
||||
* What every surface that shows nodes shares with the graph editor: how far it zooms, how the grid
|
||||
* is drawn and how the wheel zooms about the pointer. The graph editor and a plugin's node board
|
||||
* look and move the same because they both come through here.
|
||||
*/
|
||||
|
||||
/** Spacing of the background grid – and, with snapping on, of the positions a drag can leave. */
|
||||
export const GRID_STEP = 24;
|
||||
export const ZOOM_LIMITS = { min: 0.25, max: 2.5 };
|
||||
/** Breathing room around the framed nodes, so they do not touch the edge. */
|
||||
export const FIT_MARGIN = 24;
|
||||
/** Below this on-screen spacing the grid is noise rather than orientation, so it is dropped. */
|
||||
const MIN_GRID_STEP = 8;
|
||||
|
||||
export interface GraphView {
|
||||
/** Where the graph origin sits on screen. */
|
||||
pan: Point;
|
||||
/** Screen pixels per graph unit. */
|
||||
zoom: number;
|
||||
}
|
||||
|
||||
/** The view after zooming by `factor` about a screen point, which keeps the graph point under it. */
|
||||
export function zoomedAbout(view: GraphView, at: Point, factor: number): GraphView {
|
||||
const zoom = clamp(view.zoom * factor, ZOOM_LIMITS.min, ZOOM_LIMITS.max);
|
||||
const graphX = (at.x - view.pan.x) / view.zoom;
|
||||
const graphY = (at.y - view.pan.y) / view.zoom;
|
||||
return { pan: { x: at.x - graphX * zoom, y: at.y - graphY * zoom }, zoom };
|
||||
}
|
||||
|
||||
export function drawGraphGrid(g: Graphics, view: GraphView, w: number, h: number): void {
|
||||
g.clear();
|
||||
const step = GRID_STEP * view.zoom;
|
||||
if (step < MIN_GRID_STEP) return;
|
||||
// `pan` is where the graph origin sits on screen, but no axis lines: it marks nothing.
|
||||
drawGrid(g, { originX: view.pan.x, originY: view.pan.y, step, w, h, alpha: 0.04 });
|
||||
}
|
||||
Reference in new issue
Block a user