Something went wrong. Try again.
inkfinite (an infinite canvas/whiteboard) monorepo ink.stormlightlabs.org
svelte rust tauri svg canvas perfect-freehand
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210// @ts-nocheckimport { execFileSync } from 'node:child_process';import { cpus, freemem, platform, release, totalmem } from 'node:os';import { writeFileSync } from 'node:fs';import { resolve } from 'node:path';import process from 'node:process';import { Store } from '../../core/dist/index.mjs';import { createRenderer } from '../../editor/dist/renderer.js';import { corpus, createEditorState, getProfile } from './performance-corpus.js';
const root = resolve(import.meta.dirname, '../../..');const outputFlagIndex = process.argv.indexOf('--output');const outputPath = outputFlagIndex >= 0 ? resolve(process.cwd(), process.argv[outputFlagIndex + 1]) : null;const profileFlagIndex = process.argv.indexOf('--profile');const requestedProfile = profileFlagIndex >= 0 ? process.argv[profileFlagIndex + 1] : null;const sizeFlagIndex = process.argv.indexOf('--size');const requestedSize = sizeFlagIndex >= 0 ? Number(process.argv[sizeFlagIndex + 1]) : null;
function commandVersion(command, args = ['--version']) { try { return execFileSync(command, args, { encoding: 'utf8' }).trim(); } catch { return 'unavailable'; }}
function duration(operation) { const start = performance.now(); operation(); return performance.now() - start;}
function median(values) { const sorted = [...values].sort((left, right) => left - right); return sorted[Math.floor(sorted.length / 2)];}
function createCanvasHarness() { const frames = []; const noop = () => {}; const context = { canvas: null, save: noop, restore: noop, transform: noop, setTransform: noop, scale: noop, translate: noop, rotate: noop, clearRect: noop, fillRect: noop, strokeRect: noop, fillText: noop, measureText: (text) => ({ width: text.length * 8 }), beginPath: noop, moveTo: noop, lineTo: noop, quadraticCurveTo: noop, bezierCurveTo: noop, arc: noop, arcTo: noop, ellipse: noop, roundRect: noop, rect: noop, closePath: noop, clip: noop, fill: noop, stroke: noop, drawImage: noop, setLineDash: noop, fillStyle: '', strokeStyle: '', lineWidth: 1, font: '', textAlign: 'start', textBaseline: 'alphabetic', globalAlpha: 1 }; const canvas = { width: corpus.viewport.width, height: corpus.viewport.height, getContext: () => context, getBoundingClientRect: () => ({ width: corpus.viewport.width, height: corpus.viewport.height, top: 0, left: 0, right: corpus.viewport.width, bottom: corpus.viewport.height }) }; context.canvas = canvas; globalThis.window = { devicePixelRatio: 1 }; globalThis.requestAnimationFrame = (callback) => { frames.push(callback); return frames.length; }; globalThis.cancelAnimationFrame = noop; return { canvas, frames };}
function renderOnce(renderer, frames) { renderer.markDirty(); const frame = frames.shift(); if (!frame) throw new Error('renderer did not schedule a frame'); return duration(() => frame(performance.now()));}
function benchmarkFixture(profileId, shapeCount) { const state = createEditorState(profileId, shapeCount); const { canvas, frames } = createCanvasHarness(); const renderer = createRenderer(canvas, new Store(state), { snapProvider: { get: () => ({ snapEnabled: false, gridEnabled: false, gridSize: 25 }) } });
// Drain the initial dirty frame before collecting samples. if (frames.length > 0) frames.shift()(performance.now()); for (let index = 0; index < corpus.warmups; index += 1) renderOnce(renderer, frames); const samples = []; for (let index = 0; index < corpus.samples; index += 1) samples.push(renderOnce(renderer, frames)); renderer.dispose();
return { profile: profileId, shapeCount, shapeRecords: Object.keys(state.doc.shapes).length, bindingRecords: Object.keys(state.doc.bindings).length, warmups: corpus.warmups, samples: corpus.samples, regressionBudget: { statistic: 'median milliseconds', maximum: median(samples) * 1.2, tolerancePercent: 20 }, milliseconds: { median: median(samples), minimum: Math.min(...samples), maximum: Math.max(...samples), all: samples } };}
const profileIds = requestedProfile ? [getProfile(requestedProfile).id] : corpus.profiles.map((profile) => profile.id);const sizes = requestedSize ? [requestedSize] : corpus.sizes;for (const size of sizes) { if (!Number.isInteger(size) || size <= 0 || !corpus.sizes.includes(size)) { throw new Error(`Size must be one of ${corpus.sizes.join(', ')}`); }}
const cpu = cpus()[0];const startedAt = new Date().toISOString();const measurements = [];for (const profileId of profileIds) { for (const shapeCount of sizes) measurements.push(benchmarkFixture(profileId, shapeCount));}
const result = { schemaVersion: 2, capturedAt: startedAt, fixture: { path: 'fixtures/native/performance/corpus.json', seed: corpus.seed, profiles: profileIds, sizes, viewport: corpus.viewport, camera: corpus.camera }, hardware: { platform: platform(), osRelease: release(), cpu: cpu?.model ?? 'unknown', logicalCpuCount: cpus().length, cpuSpeedMHz: cpu?.speed ?? null, totalMemoryBytes: totalmem(), freeMemoryBytesAtCapture: freemem() }, runtime: { node: process.version, v8: process.versions.v8, rustc: commandVersion('rustc'), cargo: commandVersion('cargo'), typescript: commandVersion(resolve(root, 'node_modules/.bin/tsc')), playwright: commandVersion(resolve(root, 'node_modules/.bin/playwright')) }, sampling: { warmups: corpus.warmups, samples: corpus.samples, statistic: 'median of post-warmup samples', clock: 'node:perf_hooks performance.now()', method: 'one scheduled production editor renderer frame per sample' }, scope: { renderer: 'packages/editor/src/renderer.ts createRenderer', canvas: 'no-op CanvasRenderingContext2D harness', measured: ['scene traversal', 'viewport culling', 'geometry dispatch', 'renderer cache work'], excluded: [ 'browser rasterization', 'paint', 'text shaping', 'compositing', 'GPU work', 'browser GC', 'real frame timing' ] }, measurements};
const serialized = `${JSON.stringify(result, null, '\t')}\n`;if (outputPath) writeFileSync(outputPath, serialized);else process.stdout.write(serialized);