Theme named Inter and JetBrains Mono, but neither was ever shipped, so every machine drew the editor in whatever it had installed. The e2e runs measured text in a different face than the user saw. - Five Latin woff2 faces live in src/ui/fonts/ next to their OFL licences: Source Sans 3 400/500/600/700 and Source Code Pro 400. - fonts.ts loads them through FontFace, and main.ts waits for them before the first widget exists, so Pixi measures the real face. - A face that fails to load is reported in the console and the system fallback in Theme takes over. - Theme is retuned by hand: 12 px body, 22 px rows, smaller gaps and padding, radius 8, and weight 500 for bold and headings. - The scene background default follows Theme.colors.graphBackground. This makes core import from ui for the first time. Findings: - The 500 file is in the folder but fonts.ts does not register it yet, so weight 500 currently falls back to the 400 face. Tests: - ./check.sh: 141 files, 2080 tests, exit 0. - e2e not run. Checks that measure widths or row positions are expected to need updating for the new metrics. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
2.6 KiB
TypeScript
71 lines
2.6 KiB
TypeScript
import { Application, Container } from 'pixi.js';
|
|
// Static imports on purpose: Pixi registers render pipes (graphics, text, sprite) as a
|
|
// module side effect, and a renderer only knows the pipes that exist when it is created.
|
|
// Lazy chunks loaded after `app.init()` would therefore fail with "unknown render pipe".
|
|
import { captureConsole } from './editor/console/log';
|
|
import { startEditor } from './editor/App';
|
|
import { mountPlayground } from './playground';
|
|
import { initRenderLoop, initUI, loadEditorFonts, Theme, VStack } from './ui';
|
|
|
|
// Before anything else: a renderer warns while it is being created, and those warnings are
|
|
// exactly the ones worth having in the panel.
|
|
captureConsole();
|
|
|
|
// `desynchronized` bypasses the compositor queue (headless click-to-paint 72 → 16 ms) but may
|
|
// tear; `?vsync` opts out. Pixi has no option for it, hence our own context.
|
|
function lowLatencyContext(): { canvas?: HTMLCanvasElement; context?: WebGL2RenderingContext } {
|
|
const canvas = document.createElement('canvas');
|
|
const context = canvas.getContext('webgl2', {
|
|
alpha: false,
|
|
antialias: true,
|
|
premultipliedAlpha: true,
|
|
stencil: true,
|
|
desynchronized: true,
|
|
});
|
|
return context ? { canvas, context } : {};
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
const params = new URLSearchParams(location.search);
|
|
const fonts = loadEditorFonts();
|
|
const app = new Application();
|
|
await app.init({
|
|
resizeTo: window,
|
|
background: Theme.colors.background,
|
|
antialias: true,
|
|
resolution: Math.min(2, window.devicePixelRatio || 1),
|
|
autoDensity: true,
|
|
preference: 'webgl',
|
|
...(params.has('vsync') ? {} : lowLatencyContext()),
|
|
});
|
|
document.body.appendChild(app.canvas);
|
|
await fonts;
|
|
|
|
const root = new VStack();
|
|
const overlay = new Container();
|
|
app.stage.addChild(root, overlay);
|
|
app.stage.eventMode = 'static';
|
|
app.stage.hitArea = app.screen;
|
|
initUI(app, root, overlay);
|
|
// From here on the picture is drawn when something changes, not sixty times a second.
|
|
initRenderLoop(app);
|
|
|
|
if (params.has('playground')) mountPlayground(app, root);
|
|
else await startEditor(app, root);
|
|
|
|
app.renderer.on('resize', () => {
|
|
app.stage.hitArea = app.screen;
|
|
root.resize(app.screen.width, app.screen.height);
|
|
});
|
|
}
|
|
|
|
window.addEventListener('error', (event) => {
|
|
const error: unknown = event.error;
|
|
console.error('[uncaught]', error instanceof Error ? error.stack : event.message);
|
|
});
|
|
|
|
main().catch((error) => {
|
|
console.error(error);
|
|
document.body.innerHTML = `<pre style="color:#e0553f;padding:16px;font:13px monospace">${String(error)}</pre>`;
|
|
});
|