From eb8d6231c543c8df90e2fd85f0c52ea0c6331c9f Mon Sep 17 00:00:00 2001 From: Agent Zero Date: Thu, 27 Aug 2026 12:58:36 +0200 Subject: [PATCH] task(C4): use_pixi_renderer flag on by default with e2e proof --- .../playwright-tests/phase-a-verify.test.ts | 18 ++++++++++++++++++ frontend/src/components/CanvasArea.tsx | 14 ++++++++++---- frontend/src/kernel/featureFlags.ts | 8 ++++++++ frontend/src/render/pixi/PixiRenderer.ts | 15 +++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/frontend/playwright-tests/phase-a-verify.test.ts b/frontend/playwright-tests/phase-a-verify.test.ts index 1bade7c..7833005 100644 --- a/frontend/playwright-tests/phase-a-verify.test.ts +++ b/frontend/playwright-tests/phase-a-verify.test.ts @@ -88,6 +88,24 @@ test('Phase-A: V2-Pfad end-to-end (Ribbon-Sektion, Toolwechsel, Zeichnen+Undo cr await page.keyboard.press('Control+y'); await page.waitForTimeout(300); + // ── 4b) Task C4: PixiRenderer hat die Elemente im Cache ── + const pixiInfo = await page.evaluate(() => { + const debug = (window as unknown as { __v2Debug?: { info(): { cachedElements: number; ready: boolean } | null } }).__v2Debug; + return debug?.info() ?? null; + }); + expect(pixiInfo).not.toBeNull(); + expect(pixiInfo!.ready).toBe(true); + expect(pixiInfo!.cachedElements).toBeGreaterThanOrEqual(1); + + // Nach Undo muss der Cache leer sein (Referenzdiff synchronisiert) + await page.keyboard.press('Control+z'); + await page.waitForTimeout(300); + const pixiInfoAfterUndo = await page.evaluate(() => { + const debug = (window as unknown as { __v2Debug?: { info(): { cachedElements: number; ready: boolean } | null } }).__v2Debug; + return debug?.info() ?? null; + }); + expect(pixiInfoAfterUndo!.cachedElements).toBe(0); + // Kein Seitenfehler durch den gesamten V2-Ablauf: expect(pageErrors).toEqual([]); // Konsolenfehler nur tolerieren, wenn sie nichts mit dem V2-Pfad zu tun haben: diff --git a/frontend/src/components/CanvasArea.tsx b/frontend/src/components/CanvasArea.tsx index e55c481..9b43e36 100644 --- a/frontend/src/components/CanvasArea.tsx +++ b/frontend/src/components/CanvasArea.tsx @@ -17,7 +17,7 @@ import { logger } from '../utils/logger'; 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 { V2_TOOLS_ENABLED, USE_PIXI_RENDERER } from '../kernel/featureFlags'; import { PixiRenderer } from '../render/pixi/PixiRenderer'; import { pluginRegistry } from '../plugins'; @@ -71,18 +71,24 @@ const CanvasArea: React.FC = ({ // App-Level-Zugriffspunkt für HistoryPanel/Tastenkürzel (Task A4.11): setActiveDocument(v2Doc); - // ── Task C2: PixiJS-Renderer parallel schalten ── + // ── Task C2/C4: 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) { + if (pixiCanvas && USE_PIXI_RENDERER) { try { pixi = new PixiRenderer(); pixiRendererRef.current = pixi; pixi.init(pixiCanvas); - pixi.waitForReady().catch((err) => { + pixi.waitForReady().then(() => { + // Task C4: Debug-Hook für Playwright-E2E-Assertions + (window as unknown as { __v2Debug: unknown }).__v2Debug = { + renderer: pixi, + info: () => pixiRendererRef.current?.getDebugInfo() ?? null, + }; + }).catch((err) => { logger.warn('Pixi init failed — V2-Overlay deaktiviert:', err); pixi = null; pixiRendererRef.current = null; diff --git a/frontend/src/kernel/featureFlags.ts b/frontend/src/kernel/featureFlags.ts index 8bac384..03f7b72 100644 --- a/frontend/src/kernel/featureFlags.ts +++ b/frontend/src/kernel/featureFlags.ts @@ -13,3 +13,11 @@ /** Ist der V2-Werkzeugpfad (Dispatcher/CADDocument) aktiv? Default: ja. */ export const V2_TOOLS_ENABLED: boolean = import.meta.env.VITE_TOOL_DISPATCHER !== 'legacy'; + +/** + * Task C4: Pixi als Primär-Renderer für V2-Elemente (Overlay über Legacy). + * Default: ja (durch phase-a-verify E2E abgesichert). + * Opt-out: VITE_USE_PIXI=false. + */ +export const USE_PIXI_RENDERER: boolean = + import.meta.env.VITE_USE_PIXI !== 'false'; diff --git a/frontend/src/render/pixi/PixiRenderer.ts b/frontend/src/render/pixi/PixiRenderer.ts index 9544a05..e0e2e35 100644 --- a/frontend/src/render/pixi/PixiRenderer.ts +++ b/frontend/src/render/pixi/PixiRenderer.ts @@ -48,6 +48,9 @@ export class PixiRenderer implements RenderAdapter { await this.ready; } + /** Task C4: true sobald setupApp fertig ist (via readyResolve gesetzt). */ + private initialized = false; + // ── Lifecycle ──────────────────────────────────────────── init(canvas: HTMLCanvasElement): void { @@ -89,6 +92,7 @@ export class PixiRenderer implements RenderAdapter { this.overlayLayer = overlay; this.app.stage.addChild(overlay); this.applyViewportTransform(); + this.initialized = true; // Task C4: fuer getDebugInfo }); } @@ -252,6 +256,17 @@ export class PixiRenderer implements RenderAdapter { return null; } + /** + * Task C4: Debug-Info für Playwright-E2E-Assertions. + * Ermöglicht Testabfragen wie 'wie viele Elemente sind gerendert?' + */ + getDebugInfo(): { cachedElements: number; ready: boolean } { + return { + cachedElements: this.graphicsCache.size, + ready: this.initialized, + }; + } + // ── Internes ───────────────────────────────────────────── private applyViewportTransform(): void {