Replaces the hand-rolled inline-SVG topology with a PixiJS 8 scene graph. Why: the old renderer rebuilt all 37 nodes / 36 edges as one innerHTML string every 10s, which tore down and recreated every DOM node. That restarted CSS animations mid-flight and made dragging fight the browser's own hit-testing. The scene graph gives per-node transforms, so pan/zoom is a single container transform instead of getScreenCTM() matrix math. Changes: - static/topo_pixi.js: new self-contained renderer. Owns its Application and tears it down on tab exit so a second WebGL context cannot leak. - static/index.html: the <svg id=topoSvg> host becomes a <div id=topoHost>; the 188-line SVG renderer is replaced by a bridge to the module. - static/vendor/pixi.mjs: PixiJS 8.21.0 self-hosted (MIT). The .mjs build is required; the .js build exports no global. See vendor/README.md. - main.py: mount /static. Pages were served as inline HTMLResponse, so the directory was never mounted and the module had no URL to load from. Two real bugs found by measuring pixels rather than trusting init(): - preserveDrawingBuffer: without it WebGL clears the back buffer after compositing, so any readback or screenshot of the canvas is a coin flip depending on which frame it lands on. The graph rendered intermittently blank. Now enabled: cheap for a 2D scene, and it makes the view capturable. - Layout was centred on the SCROLLABLE width (nodes.length * 130), not the viewport, so with 37 nodes every team and challenge node landed at x=2230-2650 on a 1310px canvas: entirely off-screen. Layout now centres on the visible width and reset() frames the whole graph to fit. test_topo_pixels.js documents three wrong test designs it replaces, all of which reported false failures against a working graph: counting scene-graph children (passes on a blank canvas), diffing against the background colour (the theme is dark by design, so a perfect render measures ~0%), and diffing two Playwright screenshots (both can be captured after the scene was mutated). The check now reads the GL back buffer via readPixels in one evaluate. Verified: 37 nodes / 36 edges drawn (7.94% of frame, max channel delta 225), graph bbox [437,46,881,476] inside the 1310x520 canvas, glGetError=0, no page errors, zoom and frame-to-fit reset working. Platform unregressed: SLA 32/32.
888 B
888 B
Vendored third-party assets
pixi.mjs — PixiJS 8.21.0 (MIT)
Topology graph renderer for the admin panel. Self-hosted on purpose: the panel must not depend on a CDN at runtime (the CTF network is air-gapped during the event, and a CDN outage would take the topology view down with it).
Provenance and upgrade path:
npm pack pixi.js@8
tar xzf pixi.js-8.21.0.tgz
cp package/dist/pixi.min.mjs panel/static/vendor/pixi.mjs
Use pixi.min.mjs, not pixi.min.js. The .js bundle is an IIFE that
discards its return value and exports no global, so it cannot be loaded with a
plain <script> tag. The .mjs build has real named exports and is loaded via
await import('/static/vendor/pixi.mjs') in static/topo_pixi.js.
Loading it dynamically (rather than a <script> in every page) keeps the ~800 KB
parse cost off panel loads that never open the Topology tab.