task(C2int): integrate pixi renderer as overlay with lazy import

This commit is contained in:
Agent Zero
2026-08-27 10:02:05 +02:00
parent 8cde5d7f35
commit 8b1cca0324
2 changed files with 160 additions and 37 deletions
+78
View File
@@ -18,6 +18,7 @@ import { CADDocument } from '../kernel/document/CADDocument';
import { YjsDocument } from '../crdt/YjsDocument';
import { setActiveDocument, getActiveDocument } from '../kernel/document/documentService';
import { V2_TOOLS_ENABLED } from '../kernel/featureFlags';
import { PixiRenderer } from '../render/pixi/PixiRenderer';
import { pluginRegistry } from '../plugins';
const CanvasArea: React.FC<CanvasAreaProps> = ({
@@ -34,6 +35,10 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
const renderEngineRef = useRef<RenderEngine | null>(null);
const interactionRef = useRef<InteractionEngine | null>(null);
const dispatcherRef = useRef<InteractionDispatcher | null>(null);
/** Task C2: PixiJS-Canvas-Ref für V2-Elemente-Overlay. */
const pixiCanvasRef = useRef<HTMLCanvasElement>(null);
/** Task C2: Aktiver PixiJS-Renderer (für Cleanup). */
const pixiRendererRef = useRef<PixiRenderer | null>(null);
/** Bereits an onElementCreated gemeldete V2-Element-IDs (verhindert Doppelmeldung bei jedem onChanged-Frame). */
const announcedV2Ids = useRef<Set<string>>(new Set());
const spatialIndexRef = useRef<SpatialIndex | null>(null);
@@ -65,6 +70,60 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
const v2Doc = new CADDocument(ydoc);
// App-Level-Zugriffspunkt für HistoryPanel/Tastenkürzel (Task A4.11):
setActiveDocument(v2Doc);
// ── Task C2: PixiJS-Renderer parallel schalten ──
// DEFENSIV: Ein Ausfall von Pixi (z.B. WebGL im Headless-Browser)
// darf NIEMALS den kompletten Editor-Mount brechen. Im Fehlerfall
// läuft weiter ohne Overlay.
let pixi: PixiRenderer | null = null;
const pixiCanvas = pixiCanvasRef.current;
if (pixiCanvas) {
try {
pixi = new PixiRenderer();
pixiRendererRef.current = pixi;
pixi.init(pixiCanvas);
pixi.waitForReady().catch((err) => {
logger.warn('Pixi init failed — V2-Overlay deaktiviert:', err);
pixi = null;
pixiRendererRef.current = null;
});
} catch (err) {
logger.warn('Pixi init exception — V2-Overlay deaktiviert:', err);
pixi = null;
pixiRendererRef.current = null;
}
}
/** Letztes bekanntes Elementobjekt je ID (Referenzdiff statt JSON). */
const lastKnownEl = new Map<string, CADElement>();
const syncPixi = (): void => {
if (!pixi) return;
void pixi.waitForReady().then(() => {
const all = v2Doc.getAllElements();
const visibleIds = new Set<string>();
for (const el of all) {
visibleIds.add(el.id);
// Nur neu zeichnen wenn sich die OBJEKTREFERENZ geändert hat:
if (lastKnownEl.get(el.id) !== el) {
lastKnownEl.set(el.id, el);
pixi!.drawElement(el, {
id: 'layer-0', name: 'Standard', visible: true, locked: false,
color: '#ffffff', lineType: 'solid', transparency: 0,
sortOrder: 0, parentId: null,
} as never, {
color: '#ffffff', lineType: 'solid', transparency: 0, visible: true,
});
}
}
// Gelöschte IDs aus dem Renderer entfernen:
for (const knownId of lastKnownEl.keys()) {
if (!visibleIds.has(knownId)) {
lastKnownEl.delete(knownId);
pixi!.removeElement(knownId);
}
}
});
};
// Committete V2-Elemente fließen über den etablierten Kanal in UI/State:
v2Doc.onChanged(() => {
for (const el of v2Doc.getAllElements()) {
@@ -73,6 +132,7 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
onElementCreated(el);
}
}
syncPixi(); // Task C2: V2-Elemente in den PixiJS-Overlay-Renderer spiegeln
});
dispatcherRef.current = new InteractionDispatcher(canvas, {
@@ -115,6 +175,8 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
interaction.detach();
dispatcherRef.current?.destroy();
dispatcherRef.current = null;
pixiRendererRef.current?.destroy(); // Task C2: WebGL-Kontext freigeben
pixiRendererRef.current = null;
setActiveDocument(null);
zoomPanRef.current = null;
renderEngineRef.current = null;
@@ -413,6 +475,22 @@ const CanvasArea: React.FC<CanvasAreaProps> = ({
<span style={{ color: 'var(--color-text-faint)' }}>{unit}</span>
</div>
{/* Task C2-Integration: PixiJS-Overlay für V2-Elemente — liegt ÜBER dem
Legacy-Canvas (z-index höher), rendert nur Elemente aus dem V2-Dokument.
Pointer-Events gehen durch (pointerEvents:none), damit Drag/Drop weiter
auf dem Legacy-Canvas funktioniert. */}
{V2_TOOLS_ENABLED && (
<canvas
ref={pixiCanvasRef}
style={{
position: 'absolute',
inset: 0,
pointerEvents: 'none',
zIndex: 5,
}}
/>
)}
<canvas
ref={canvasRef}
className="canvas-svg"