Two compilers that walk a graph the same way walk it through one emitter (#85)
Refactoring round two: the particle and shader compilers share emitGraph.ts (cycle detection, duplicate names, emit order) and keep only their rules. FontLibrary and TextureLibrary sit on FileLibrary (base URL, loading/failed bookkeeping, listeners); SoundLibrary keeps its own contract. The three Create*Command share ImportFileCommand, the three renames share RenameCommand - class names stay. bandBounds() in framing.ts and portNameField() in portSection.ts replace in-file clones, and three comments that told history now state the rule. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
bf0be66c9d
commit
d3563897d8
16 files changed
+376
-379
No files matched your search
@@ -1143,6 +1143,21 @@ export class GraphCanvas extends Widget {
|
||||
}
|
||||
}
|
||||
|
||||
private launchBeads(assetId: string, trace: Trace | null): void {
|
||||
if (!trace || assetId !== this.beadAsset) {
|
||||
this.beadTimes.clear();
|
||||
this.beadFired.clear();
|
||||
this.beadAsset = assetId;
|
||||
}
|
||||
for (const [id, time] of trace?.edges ?? []) {
|
||||
if (this.beadFired.get(id) === time) continue;
|
||||
this.beadFired.set(id, time);
|
||||
const times = this.beadTimes.get(id) ?? [];
|
||||
this.beadTimes.set(id, times);
|
||||
launchBead(times, time);
|
||||
}
|
||||
}
|
||||
|
||||
/** A port's centre in graph coordinates. */
|
||||
private anchorPoint(side: PortSide | null): { x: number; y: number } | null {
|
||||
if (!side) return null;
|
||||
@@ -1170,9 +1185,7 @@ export class GraphCanvas extends Widget {
|
||||
portGlobal(nodeId: string, port: string, isOutput: boolean): { x: number; y: number } | null {
|
||||
const view = this.views.get(nodeId);
|
||||
const p = view?.portPosition(port, isOutput);
|
||||
if (!view || !p) return null;
|
||||
const g = view.toGlobal({ x: p.x, y: p.y });
|
||||
return { x: g.x, y: g.y };
|
||||
return view && p ? globalPoint(view, p) : null;
|
||||
}
|
||||
|
||||
/** The port a running edge drag would connect to, or null when the drop would do nothing. */
|
||||
@@ -1222,8 +1235,7 @@ export class GraphCanvas extends Widget {
|
||||
.drawnMarks()
|
||||
.find((m) => m.edgeIds.includes(edgeId) && m.isOutput === isOutput);
|
||||
if (!mark) return null;
|
||||
const g = this.canvas.toGlobal({ x: mark.x, y: mark.y });
|
||||
return { x: g.x, y: g.y, links: mark.edgeIds.length, label: mark.text };
|
||||
return { ...globalPoint(this.canvas, mark), links: mark.edgeIds.length, label: mark.text };
|
||||
}
|
||||
|
||||
nodeRect(nodeId: string): Rect | null {
|
||||
@@ -1272,21 +1284,6 @@ export class GraphCanvas extends Widget {
|
||||
return this.views.get(nodeId)?.inputLines ?? null;
|
||||
}
|
||||
|
||||
private launchBeads(assetId: string, trace: Trace | null): void {
|
||||
if (!trace || assetId !== this.beadAsset) {
|
||||
this.beadTimes.clear();
|
||||
this.beadFired.clear();
|
||||
this.beadAsset = assetId;
|
||||
}
|
||||
for (const [id, time] of trace?.edges ?? []) {
|
||||
if (this.beadFired.get(id) === time) continue;
|
||||
this.beadFired.set(id, time);
|
||||
const times = this.beadTimes.get(id) ?? [];
|
||||
this.beadTimes.set(id, times);
|
||||
launchBead(times, time);
|
||||
}
|
||||
}
|
||||
|
||||
beadsDrawn(): readonly { edgeId: string; progress: number; x: number; y: number }[] {
|
||||
return this.edgeLayer.drawnBeads();
|
||||
}
|
||||
@@ -1298,9 +1295,7 @@ export class GraphCanvas extends Widget {
|
||||
/** Global screen position of a node's title bar centre. */
|
||||
nodeGlobal(nodeId: string): { x: number; y: number } | null {
|
||||
const view = this.views.get(nodeId);
|
||||
if (!view) return null;
|
||||
const g = view.toGlobal({ x: view.w / 2, y: TITLE_HEIGHT / 2 });
|
||||
return { x: g.x, y: g.y };
|
||||
return view ? globalPoint(view, { x: view.w / 2, y: TITLE_HEIGHT / 2 }) : null;
|
||||
}
|
||||
|
||||
/** Every group and comment as it is drawn: the box, the text on it, and both its colours. */
|
||||
@@ -1334,8 +1329,7 @@ export class GraphCanvas extends Widget {
|
||||
const local = corner
|
||||
? { x: view.w - RESIZE_HANDLE / 2, y: view.h - RESIZE_HANDLE / 2 }
|
||||
: { x: view.w / 2, y: ANNOTATION_TITLE_HEIGHT / 2 };
|
||||
const g = view.toGlobal(local);
|
||||
return { x: g.x, y: g.y };
|
||||
return globalPoint(view, local);
|
||||
}
|
||||
|
||||
/** The rectangle a box is drawn as, on screen – what a fit has to bring into view. */
|
||||
@@ -1352,6 +1346,11 @@ export class GraphCanvas extends Widget {
|
||||
|
||||
type Rect = { x: number; y: number; w: number; h: number };
|
||||
|
||||
function globalPoint(target: Container, local: { x: number; y: number }): { x: number; y: number } {
|
||||
const g = target.toGlobal({ x: local.x, y: local.y });
|
||||
return { x: g.x, y: g.y };
|
||||
}
|
||||
|
||||
function globalRect(target: Container, w: number, h: number): Rect {
|
||||
const topLeft = target.toGlobal({ x: 0, y: 0 });
|
||||
const bottomRight = target.toGlobal({ x: w, y: h });
|
||||
|
||||
Reference in new issue
Block a user