diff --git a/apps/benchmarks/src/renderer/mtsdf-cpu-reference.test.ts b/apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.test.ts similarity index 99% rename from apps/benchmarks/src/renderer/mtsdf-cpu-reference.test.ts rename to apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.test.ts index fe4ddddd..71eb7c5d 100644 --- a/apps/benchmarks/src/renderer/mtsdf-cpu-reference.test.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'; import { compareRgba8Coverage, renderFlatMtsdfCpuReference } from './mtsdf-cpu-reference'; -describe('RGBA8 coverage comparison', () => { +describe('CPU RGBA8 coverage comparison', () => { it('uses red for extra candidate coverage and cyan for extra reference coverage', () => { const comparison = compareRgba8Coverage( Uint8Array.from([20, 20, 20, 255, 10, 10, 10, 255, 7, 7, 7, 255]), diff --git a/apps/benchmarks/src/renderer/mtsdf-cpu-reference.ts b/apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.ts similarity index 99% rename from apps/benchmarks/src/renderer/mtsdf-cpu-reference.ts rename to apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.ts index e7d419e3..c0bed834 100644 --- a/apps/benchmarks/src/renderer/mtsdf-cpu-reference.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/mtsdf-cpu-reference.ts @@ -30,7 +30,7 @@ export interface Rgba8CoverageDifference { } /** - * Compares opaque grayscale coverage frames. Red marks candidate-only coverage, + * Pure-CPU comparison of opaque grayscale coverage frames. Red marks candidate-only coverage, * cyan marks reference-only coverage, and black marks agreement. */ export function compareRgba8Coverage( diff --git a/apps/benchmarks/src/renderer/slug-cpu-reference.test.ts b/apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.test.ts similarity index 99% rename from apps/benchmarks/src/renderer/slug-cpu-reference.test.ts rename to apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.test.ts index f0cc2874..429dda5f 100644 --- a/apps/benchmarks/src/renderer/slug-cpu-reference.test.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.test.ts @@ -5,7 +5,7 @@ import { describe, expect, it } from 'vitest'; import { renderFlatSlugCpuReference } from './slug-cpu-reference'; -describe('flat Slug CPU reference', () => { +describe('conformance flat Slug CPU reference', () => { it('reconstructs an exact quadratic square at physical pixel centers', () => { const result = renderFlatSlugCpuReference(squareResource(), specimenLayout(), { width: 4, diff --git a/apps/benchmarks/src/renderer/slug-cpu-reference.ts b/apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.ts similarity index 99% rename from apps/benchmarks/src/renderer/slug-cpu-reference.ts rename to apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.ts index edd57f7e..5dccaf16 100644 --- a/apps/benchmarks/src/renderer/slug-cpu-reference.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/slug-cpu-reference.ts @@ -35,7 +35,7 @@ export interface FlatSlugCpuReferenceOptions { } /** - * Reconstruct the fixed flat Slug specimen from exact decoded curve, header, + * Reconstruct the fixed flat Slug specimen on the CPU from exact decoded curve, header, * and reference resources without invoking Three.js, TSL, or browser fonts. */ export function renderFlatSlugCpuReference( diff --git a/apps/benchmarks/src/renderer/source-outline-reference.test.ts b/apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.test.ts similarity index 90% rename from apps/benchmarks/src/renderer/source-outline-reference.test.ts rename to apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.test.ts index da9d09b9..1ef6711a 100644 --- a/apps/benchmarks/src/renderer/source-outline-reference.test.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'; import { assertSourceOutlineTransform } from './source-outline-reference'; -describe('source-outline transform validation', () => { +describe('conformance source-outline transform validation', () => { it('accepts a finite invertible affine transform', () => { expect(() => assertSourceOutlineTransform({ a: 2, b: 0.5, c: -0.25, d: 3, e: 12, f: -8 })).not.toThrow(); }); diff --git a/apps/benchmarks/src/renderer/source-outline-reference.ts b/apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.ts similarity index 85% rename from apps/benchmarks/src/renderer/source-outline-reference.ts rename to apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.ts index d0df8b14..fa5ffc86 100644 --- a/apps/benchmarks/src/renderer/source-outline-reference.ts +++ b/apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.ts @@ -1,14 +1,14 @@ import type { ParagraphLayout } from '@pmndrs/text'; -import amiriSourceUrl from '../../fixtures/fonts/amiri-1.002/Amiri-Regular.ttf?url'; -import dancingScriptSourceUrl from '../../fixtures/fonts/dancing-script-3.000/DancingScript-Regular.otf?url'; -import dotGothicSourceUrl from '../../fixtures/fonts/dot-gothic-16/DotGothic16-Regular.ttf?url'; -import fontAwesomeSourceUrl from '../../fixtures/fonts/font-awesome-free-6.7.2/fa-solid-900.ttf?url'; -import interSourceUrl from '../../fixtures/fonts/inter-v4.1/Inter-Regular.ttf?url'; -import notoCjkSourceUrl from '../../fixtures/fonts/noto-sans-cjk-showcase-v0/NotoSansCJKjp-Showcase.otf?url'; -import devanagariSourceUrl from '../../fixtures/fonts/noto-sans-devanagari/NotoSansDevanagari.ttf?url'; -import sourceSerifSourceUrl from '../../fixtures/fonts/source-serif-4.005/SourceSerif4-Regular.ttf?url'; -import type { BenchmarkFontFixture } from '../benchmark/font-fixtures'; +import amiriSourceUrl from '../../../../fixtures/fonts/amiri-1.002/Amiri-Regular.ttf?url'; +import dancingScriptSourceUrl from '../../../../fixtures/fonts/dancing-script-3.000/DancingScript-Regular.otf?url'; +import dotGothicSourceUrl from '../../../../fixtures/fonts/dot-gothic-16/DotGothic16-Regular.ttf?url'; +import fontAwesomeSourceUrl from '../../../../fixtures/fonts/font-awesome-free-6.7.2/fa-solid-900.ttf?url'; +import interSourceUrl from '../../../../fixtures/fonts/inter-v4.1/Inter-Regular.ttf?url'; +import notoCjkSourceUrl from '../../../../fixtures/fonts/noto-sans-cjk-showcase-v0/NotoSansCJKjp-Showcase.otf?url'; +import devanagariSourceUrl from '../../../../fixtures/fonts/noto-sans-devanagari/NotoSansDevanagari.ttf?url'; +import sourceSerifSourceUrl from '../../../../fixtures/fonts/source-serif-4.005/SourceSerif4-Regular.ttf?url'; +import type { BenchmarkFontFixture } from '../../font-fixtures'; import { compareRgba8Coverage } from './mtsdf-cpu-reference'; const sourceFontUrls: Readonly> = { diff --git a/apps/benchmarks/src/benchmark/target-boundary.test.ts b/apps/benchmarks/src/benchmark/target-boundary.test.ts index a7c03cd0..b6757353 100644 --- a/apps/benchmarks/src/benchmark/target-boundary.test.ts +++ b/apps/benchmarks/src/benchmark/target-boundary.test.ts @@ -7,6 +7,7 @@ import { createProductTargets } from './targets/product'; import { registeredTargetIds } from './targets/registry'; const benchmarkDirectory = fileURLToPath(new URL('.', import.meta.url)); +const rendererDirectory = fileURLToPath(new URL('../renderer', import.meta.url)); const directWasmDependencyModule = 'targets/shared/direct-wasm.ts'; async function sourceFiles(directory: string): Promise { @@ -35,10 +36,22 @@ describe('benchmark target boundaries', () => { expect(offenders.filter((file): file is string => file !== undefined)).toEqual([directWasmDependencyModule]); }); + it('keeps low-level targets downstream from renderer infrastructure', async () => { + const files = await sourceFiles(rendererDirectory); + const offenders = await Promise.all( + files.map(async (file) => { + const source = await readFile(file, 'utf8'); + return /benchmark\/targets/.test(source) ? file.slice(rendererDirectory.length + 1) : undefined; + }), + ); + expect(offenders.filter((file): file is string => file !== undefined)).toEqual([]); + }); + it('resolves targets through the lazy group registry without importing the monolithic implementation facade', async () => { const registry = await readFile(new URL('./targets/registry.ts', import.meta.url), 'utf8'); const execution = await readFile(new URL('./execution.ts', import.meta.url), 'utf8'); const conformance = await readFile(new URL('./targets/conformance/index.ts', import.meta.url), 'utf8'); + const product = await readFile(new URL('./targets/product/index.ts', import.meta.url), 'utf8'); const mtsdfAdapter = await readFile(new URL('./targets/conformance/raster/mtsdf.ts', import.meta.url), 'utf8'); const slugAdapter = await readFile(new URL('./targets/conformance/raster/slug.ts', import.meta.url), 'utf8'); @@ -47,9 +60,13 @@ describe('benchmark target boundaries', () => { expect(registry).toContain("import('./conformance')"); expect(execution).toContain('await loadRegisteredTarget(request.targetId)'); expect(conformance).toContain("import('./advanced-shaping')"); + expect(conformance).toContain("import('./raster/runtime-fallback')"); expect(conformance).not.toContain('renderer/advanced-shaping-conformance'); - expect(conformance).not.toContain("import('../../../renderer/mtsdf-text')"); - expect(conformance).not.toContain("import('../../../renderer/slug-text')"); + expect(conformance).not.toContain('renderer/runtime-fallback-conformance'); + expect(product).toContain("import('./external-raster-proof')"); + expect(product).toContain("import('./react-text')"); + expect(product).not.toContain('renderer/external-raster-proof'); + expect(product).not.toContain('renderer/react-text'); expect(mtsdfAdapter).toContain("import('../../../../renderer/mtsdf-text')"); expect(slugAdapter).toContain("import('../../../../renderer/slug-text')"); const { createAdvancedShapingConformanceTarget } = await import('./targets/conformance/advanced-shaping'); diff --git a/apps/benchmarks/src/benchmark/targets/conformance/index.ts b/apps/benchmarks/src/benchmark/targets/conformance/index.ts index 6a816f6e..c0eb8dbe 100644 --- a/apps/benchmarks/src/benchmark/targets/conformance/index.ts +++ b/apps/benchmarks/src/benchmark/targets/conformance/index.ts @@ -126,7 +126,7 @@ function runtimeFallbackTarget(technique: Technique, backend: Backend): Benchmar load: async () => undefined, run: async (input, _sampleIndex, controls, context) => { const fontFixture = selectableFontFixture(input.fontFixture ?? configuredInput.fontFixture ?? 'inter'); - const { captureRuntimeFallbackConformance } = await import('../../../renderer/runtime-fallback-conformance'); + const { captureRuntimeFallbackConformance } = await import('./raster/runtime-fallback'); const capture = await captureRuntimeFallbackConformance({ backend, dpr: controls.dpr, diff --git a/apps/benchmarks/src/renderer/raster-technique-compare.test.ts b/apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.test.ts similarity index 98% rename from apps/benchmarks/src/renderer/raster-technique-compare.test.ts rename to apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.test.ts index 43d5c851..3372e392 100644 --- a/apps/benchmarks/src/renderer/raster-technique-compare.test.ts +++ b/apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.test.ts @@ -1,8 +1,11 @@ import * as THREE from 'three/webgpu'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import type { PersistentRenderSceneContext, PersistentRenderSceneRenderer } from './persistent-render-host'; -import { createRasterTechniqueComparisonPersistentScene } from './raster-technique-compare'; +import type { + PersistentRenderSceneContext, + PersistentRenderSceneRenderer, +} from '../../../../renderer/persistent-render-host'; +import { createRasterTechniqueComparisonPersistentScene } from './comparison-scene'; const mocks = vi.hoisted(() => ({ fontDisposals: [] as string[], @@ -72,7 +75,7 @@ vi.mock('@pmndrs/text', async () => { return { Text: MockText }; }); -vi.mock('./mtsdf-text', () => ({ +vi.mock('../../../../renderer/mtsdf-text', () => ({ loadMtsdfFont: async (signal?: AbortSignal) => { signal?.throwIfAborted(); return { @@ -82,7 +85,7 @@ vi.mock('./mtsdf-text', () => ({ }, })); -vi.mock('./slug-text', () => ({ +vi.mock('../../../../renderer/slug-text', () => ({ loadSlugFont: async (signal?: AbortSignal) => { signal?.throwIfAborted(); return { diff --git a/apps/benchmarks/src/renderer/raster-technique-compare.ts b/apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.ts similarity index 98% rename from apps/benchmarks/src/renderer/raster-technique-compare.ts rename to apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.ts index d40a98e0..086fe80b 100644 --- a/apps/benchmarks/src/renderer/raster-technique-compare.ts +++ b/apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.ts @@ -3,17 +3,17 @@ import type { Node } from 'three/webgpu'; import * as THREE from 'three/webgpu'; import { mul, saturate, sub, texture, vec4 } from 'three/tsl'; -import { rasterConformanceSpecimen, type SelectableFontFixture } from '../benchmark/font-fixtures'; -import { loadMtsdfFont } from './mtsdf-text'; +import { rasterConformanceSpecimen, type SelectableFontFixture } from '../../../font-fixtures'; +import { loadMtsdfFont } from '../../../../renderer/mtsdf-text'; import { createPersistentRenderHost, type PersistentRenderScene, type PersistentRenderSceneContext, type PersistentRenderSceneRenderer, type PersistentRenderViewport, -} from './persistent-render-host'; -import { loadSlugFont } from './slug-text'; -import type { RendererBackend } from './webgpu-renderer'; +} from '../../../../renderer/persistent-render-host'; +import { loadSlugFont } from '../../../../renderer/slug-text'; +import type { RendererBackend } from '../../../../renderer/webgpu-renderer'; const BACKGROUND = 0x070709; const BASE_PHYSICAL_PPEM = 64; diff --git a/apps/benchmarks/src/renderer/runtime-fallback-conformance.ts b/apps/benchmarks/src/benchmark/targets/conformance/raster/runtime-fallback.ts similarity index 87% rename from apps/benchmarks/src/renderer/runtime-fallback-conformance.ts rename to apps/benchmarks/src/benchmark/targets/conformance/raster/runtime-fallback.ts index e2d607a7..03d6db1c 100644 --- a/apps/benchmarks/src/renderer/runtime-fallback-conformance.ts +++ b/apps/benchmarks/src/benchmark/targets/conformance/raster/runtime-fallback.ts @@ -1,9 +1,9 @@ -import type { BenchmarkFontFixture } from '../benchmark/font-fixtures'; -import type { RasterTechnique } from '../benchmark/url-state'; -import { captureBitmapTextConformance } from './bitmap-text'; -import { captureMtsdfTextConformance } from './mtsdf-text'; -import type { PersistentRenderSceneRenderer } from './persistent-render-host'; -import type { RendererBackend } from './webgpu-renderer'; +import type { BenchmarkFontFixture } from '../../../font-fixtures'; +import type { RasterTechnique } from '../../../url-state'; +import { captureBitmapTextConformance } from '../../../../renderer/bitmap-text'; +import { captureMtsdfTextConformance } from '../../../../renderer/mtsdf-text'; +import type { PersistentRenderSceneRenderer } from '../../../../renderer/persistent-render-host'; +import type { RendererBackend } from '../../../../renderer/webgpu-renderer'; export interface RuntimeFallbackCapture { readonly width: number; @@ -78,7 +78,7 @@ async function captureSlug(options: { readonly renderer?: PersistentRenderSceneRenderer; readonly signal?: AbortSignal; }) { - const { captureSlugTextConformance } = await import('./slug-text'); + const { captureSlugTextConformance } = await import('../../../../renderer/slug-text'); return captureSlugTextConformance(options); } diff --git a/apps/benchmarks/src/renderer/external-raster-proof.ts b/apps/benchmarks/src/benchmark/targets/product/external-raster-proof.ts similarity index 93% rename from apps/benchmarks/src/renderer/external-raster-proof.ts rename to apps/benchmarks/src/benchmark/targets/product/external-raster-proof.ts index 6d668eeb..fb9abb7b 100644 --- a/apps/benchmarks/src/renderer/external-raster-proof.ts +++ b/apps/benchmarks/src/benchmark/targets/product/external-raster-proof.ts @@ -2,12 +2,16 @@ import { FontRegistry, Text } from '@pmndrs/text'; import { glyphExample } from '@pmndrs/text-glyph-example-raster'; import * as THREE from 'three/webgpu'; -import type { BenchmarkTarget, TargetRunOutput } from '../benchmark/contracts'; -import { compactRgba8Readback } from './tsl-baseline'; -import { loadBenchmarkFontAsset } from '../workloads/font-assets'; -import type { PersistentRenderSceneRenderer } from './persistent-render-host'; -import { withRendererStateRestored } from './renderer-state-transaction'; -import { createConfiguredRenderer, disposeConfiguredRenderer, type RendererBackend } from './webgpu-renderer'; +import type { BenchmarkTarget, TargetRunOutput } from '../../contracts'; +import { compactRgba8Readback } from '../../../renderer/tsl-baseline'; +import { loadBenchmarkFontAsset } from '../../../workloads/font-assets'; +import type { PersistentRenderSceneRenderer } from '../../../renderer/persistent-render-host'; +import { withRendererStateRestored } from '../../../renderer/renderer-state-transaction'; +import { + createConfiguredRenderer, + disposeConfiguredRenderer, + type RendererBackend, +} from '../../../renderer/webgpu-renderer'; const WIDTH = 384; const HEIGHT = 128; diff --git a/apps/benchmarks/src/benchmark/targets/product/index.ts b/apps/benchmarks/src/benchmark/targets/product/index.ts index 324a137b..29a46845 100644 --- a/apps/benchmarks/src/benchmark/targets/product/index.ts +++ b/apps/benchmarks/src/benchmark/targets/product/index.ts @@ -84,7 +84,7 @@ function externalRasterProofTarget(backend: Backend): BenchmarkTarget { capabilities: rasterCapabilities, status: () => 'ready', }, - async () => (await import('../../../renderer/external-raster-proof')).createExternalRasterProofTarget(backend), + async () => (await import('./external-raster-proof')).createExternalRasterProofTarget(backend), ); } @@ -98,7 +98,7 @@ const reactTextTarget = () => capabilities: new Set(['deterministic', 'loader', 'shaping', 'paragraph', 'raster']), status: () => 'ready', }, - async () => (await import('../../../renderer/react-text')).createReactTextTarget(), + async () => (await import('./react-text')).createReactTextTarget(), ); export function createProductTargets(): readonly BenchmarkTarget[] { diff --git a/apps/benchmarks/src/renderer/react-text.ts b/apps/benchmarks/src/benchmark/targets/product/react-text.ts similarity index 96% rename from apps/benchmarks/src/renderer/react-text.ts rename to apps/benchmarks/src/benchmark/targets/product/react-text.ts index d9e69de7..9261fc17 100644 --- a/apps/benchmarks/src/renderer/react-text.ts +++ b/apps/benchmarks/src/benchmark/targets/product/react-text.ts @@ -6,11 +6,11 @@ import { Text as CoreText, defineFont, type ParagraphLayout } from '@pmndrs/text import { Text, useFont } from '@pmndrs/text/react'; import { bitmap } from '@pmndrs/text/raster/bitmap'; -import canonicalParagraphLayout from '../../fixtures/contracts/paragraph-layout-v0.json'; -import bitmapFontUrl from '../../fixtures/rendering/inter-bitmap-16.font.glb?url'; -import type { BenchmarkTarget, TargetRunOutput } from '../benchmark/contracts'; -import { hashParagraphLayout } from '../benchmark/paragraph-layout-digest'; -import { createConfiguredRenderer, disposeConfiguredRenderer } from './webgpu-renderer'; +import canonicalParagraphLayout from '../../../../fixtures/contracts/paragraph-layout-v0.json'; +import bitmapFontUrl from '../../../../fixtures/rendering/inter-bitmap-16.font.glb?url'; +import type { BenchmarkTarget, TargetRunOutput } from '../../contracts'; +import { hashParagraphLayout } from '../../paragraph-layout-digest'; +import { createConfiguredRenderer, disposeConfiguredRenderer } from '../../../renderer/webgpu-renderer'; const FRAME_WIDTH = 384; const FRAME_HEIGHT = 128; diff --git a/apps/benchmarks/src/renderer/bitmap-text.ts b/apps/benchmarks/src/renderer/bitmap-text.ts index e4c85978..3d24dd21 100644 --- a/apps/benchmarks/src/renderer/bitmap-text.ts +++ b/apps/benchmarks/src/renderer/bitmap-text.ts @@ -39,7 +39,10 @@ import { liveTextPosition, type LiveTextAnchor, } from '../workloads/shared/text-style'; -import { captureSourceOutlineFidelity, type SourceOutlineFidelityCapture } from './source-outline-reference'; +import { + captureSourceOutlineFidelity, + type SourceOutlineFidelityCapture, +} from '../benchmark/low-level/raster/source-outline-reference'; import { createConfiguredRenderer, disposeConfiguredRenderer, diff --git a/apps/benchmarks/src/renderer/mtsdf-text.ts b/apps/benchmarks/src/renderer/mtsdf-text.ts index 7be057fc..5f3260a7 100644 --- a/apps/benchmarks/src/renderer/mtsdf-text.ts +++ b/apps/benchmarks/src/renderer/mtsdf-text.ts @@ -22,8 +22,11 @@ import { liveTextPosition, type LiveTextAnchor, } from '../workloads/shared/text-style'; -import { compareRgba8Coverage, renderFlatMtsdfCpuReference } from './mtsdf-cpu-reference'; -import { captureSourceOutlineFidelity, type SourceOutlineFidelityCapture } from './source-outline-reference'; +import { compareRgba8Coverage, renderFlatMtsdfCpuReference } from '../benchmark/low-level/raster/mtsdf-cpu-reference'; +import { + captureSourceOutlineFidelity, + type SourceOutlineFidelityCapture, +} from '../benchmark/low-level/raster/source-outline-reference'; import { compactRgba8Readback } from './tsl-baseline'; import { createConfiguredRenderer, disposeConfiguredRenderer, type RendererBackend } from './webgpu-renderer'; import { diff --git a/apps/benchmarks/src/renderer/slug-text.ts b/apps/benchmarks/src/renderer/slug-text.ts index e4ff62ec..952518bb 100644 --- a/apps/benchmarks/src/renderer/slug-text.ts +++ b/apps/benchmarks/src/renderer/slug-text.ts @@ -28,7 +28,7 @@ import { type LiveTextAnchor, } from '../workloads/shared/text-style'; import { createTextUpdateTelemetry, type TextUpdateTimingSummary } from './text-update-telemetry'; -import { compareRgba8Coverage } from './mtsdf-cpu-reference'; +import { compareRgba8Coverage } from '../benchmark/low-level/raster/mtsdf-cpu-reference'; import { createPersistentRenderHost, type PersistentRenderScene, @@ -42,13 +42,16 @@ import { type LiveFontFixtureUpdate, type RetainedFontFixtureController, } from './retained-font-fixture'; -import { renderFlatSlugCpuReference } from './slug-cpu-reference'; +import { renderFlatSlugCpuReference } from '../benchmark/low-level/raster/slug-cpu-reference'; import type { SlugAffineRoleSceneDefinition, SlugProjectionZoomSceneDefinition, SlugRoleSceneDefinition, } from './slug-role-scenes'; -import { captureSourceOutlineFidelity, type SourceOutlineFidelityCapture } from './source-outline-reference'; +import { + captureSourceOutlineFidelity, + type SourceOutlineFidelityCapture, +} from '../benchmark/low-level/raster/source-outline-reference'; import { compactRgba8Readback } from './tsl-baseline'; import { createConfiguredRenderer, diff --git a/apps/benchmarks/src/surfaces/conformance/capture.ts b/apps/benchmarks/src/surfaces/conformance/capture.ts index acad1da8..4901b796 100644 --- a/apps/benchmarks/src/surfaces/conformance/capture.ts +++ b/apps/benchmarks/src/surfaces/conformance/capture.ts @@ -5,8 +5,8 @@ import type { BitmapTextConformanceCapture } from '../../renderer/bitmap-text'; import type { MtsdfTextConformanceCapture } from '../../renderer/mtsdf-text'; import type { PersistentRenderSceneRenderer } from '../../renderer/persistent-render-host'; import type { SlugTextConformanceCapture } from '../../renderer/slug-text'; -import type { SourceOutlineFidelityCapture } from '../../renderer/source-outline-reference'; -import type { RuntimeFallbackCapture } from '../../renderer/runtime-fallback-conformance'; +import type { SourceOutlineFidelityCapture } from '../../benchmark/low-level/raster/source-outline-reference'; +import type { RuntimeFallbackCapture } from '../../benchmark/targets/conformance/raster/runtime-fallback'; export type FiniteConformanceCapture = | { readonly kind: 'bitmap'; readonly value: BitmapTextConformanceCapture } @@ -38,7 +38,7 @@ function loadSlugTextRenderer() { } function loadRuntimeFallbackConformance() { - return import('../../renderer/runtime-fallback-conformance'); + return import('../../benchmark/targets/conformance/raster/runtime-fallback'); } /** Captures through the caller-provided persistent host renderer; this module never owns a second renderer. */ diff --git a/apps/benchmarks/src/surfaces/conformance/finite-conformance-surface.tsx b/apps/benchmarks/src/surfaces/conformance/finite-conformance-surface.tsx index b77fe868..1f2a85f6 100644 --- a/apps/benchmarks/src/surfaces/conformance/finite-conformance-surface.tsx +++ b/apps/benchmarks/src/surfaces/conformance/finite-conformance-surface.tsx @@ -11,8 +11,8 @@ import type { BitmapTextConformanceCapture } from '../../renderer/bitmap-text'; import type { MtsdfTextConformanceCapture } from '../../renderer/mtsdf-text'; import { usePersistentRenderHost } from '../../renderer/persistent-render-host-context'; import type { SlugTextConformanceCapture } from '../../renderer/slug-text'; -import type { RuntimeFallbackCapture } from '../../renderer/runtime-fallback-conformance'; -import type { SourceOutlineFidelityCapture } from '../../renderer/source-outline-reference'; +import type { RuntimeFallbackCapture } from '../../benchmark/targets/conformance/raster/runtime-fallback'; +import type { SourceOutlineFidelityCapture } from '../../benchmark/low-level/raster/source-outline-reference'; import type { ConformanceView } from '../../components/render-controls'; import { Metric } from '../../components/ui'; import { captureFiniteConformance, type FiniteConformanceCapture } from './capture'; diff --git a/apps/benchmarks/src/surfaces/conformance/raster-technique-comparison-surface.tsx b/apps/benchmarks/src/surfaces/conformance/raster-technique-comparison-surface.tsx index a9ac934e..c2dad26d 100644 --- a/apps/benchmarks/src/surfaces/conformance/raster-technique-comparison-surface.tsx +++ b/apps/benchmarks/src/surfaces/conformance/raster-technique-comparison-surface.tsx @@ -2,11 +2,11 @@ import { useEffect, useEffectEvent, useRef, useState } from 'react'; import { Metric } from '../../components/ui'; import { usePersistentRenderHost } from '../../renderer/persistent-render-host-context'; -import type { RasterTechniqueComparisonPersistentScene } from '../../renderer/raster-technique-compare'; +import type { RasterTechniqueComparisonPersistentScene } from '../../benchmark/targets/conformance/raster/comparison-scene'; import type { ConformanceSurfaceProps } from './types'; function loadRasterTechniqueComparison() { - return import('../../renderer/raster-technique-compare'); + return import('../../benchmark/targets/conformance/raster/comparison-scene'); } async function reportInitializationFailure( diff --git a/docs/log.md b/docs/log.md index 692599c4..9ccfdcfa 100644 --- a/docs/log.md +++ b/docs/log.md @@ -2,6 +2,7 @@ ## 2026-08-03 +- **Explicit low-level target hierarchy** — Moved the external raster and React reconciliation product proofs under `benchmark/targets/product`; moved the realtime MTSDF/Slug comparison, runtime fallback, and their target tests under `benchmark/targets/conformance/raster`; and placed shared CPU raster/source-outline oracles under `benchmark/low-level/raster`. Conformance surfaces retain literal lazy target imports, while a boundary regression rejects renderer imports of executable targets. The complete 311-test benchmark gate and production build passed, all 19 isolated headless scenarios remained deterministic, and the moved realtime comparison and external raster proof recovered on both WebGPU and forced WebGL2. - **Canonical benchmark font assets** — Moved source-font selection, baked fixture URLs, authenticated gzip transport, public `FontLoader` runtime fallback, raster requests, progress, and delivery metrics from renderer-owned files into `workloads/font-assets`. One discriminated adapter selects Bitmap, MTSDF, or Slug through literal dynamic imports; workload code cannot reach direct baker or Wasm URLs, while renderer modules retain live GPU lifecycle and compatibility delegates. Review restored post-registration abort checks and corrected runtime source-font selection. The complete 310-test benchmark gate, production chunk build, React Doctor, all 42 dual-backend Presentation workload cells, both timed demos at 60.02/60.47 Icon Grid FPS, all 19 headless conformance scenarios, and the dual-backend external raster proof passed. - **Canonical single-paragraph scenes** — Added one workload-owned `LiveTextScene` contract and registry so Benchmark Ipsum and Advanced Shaping project their complete public `Text` inputs beside their authored content instead of relying on a route-local workload switch. Advanced Shaping now derives its fixture from the selected authored case, while Benchmark Ipsum keeps its exact 1,151-glyph assertion scoped to Inter. Renderer adapters add only runtime font size and retain technique-specific lifecycle ownership. Exact projection, registry, and renderer-boundary tests passed within the complete 307-test benchmark gate. - **Persistent viewport hierarchy** — Moved the Bitmap, MTSDF, and Slug live-text viewport controllers, their warm update queues, loading chrome, telemetry attributes, and shared contracts from the route coordinator into `surfaces/benchmark`. Review caught mixed type imports collapsing the lazy renderer boundaries; explicit `import type` declarations restored separate Bitmap, MTSDF, and Slug production chunks. The complete deterministic benchmark check and React Doctor remained clean, all 42 retained-scene cells passed with visible pixels and one renderer, and both 60-second timed demos traversed Advanced Shaping and returned to Off-axis / 3D with one renderer at 60.02 WebGPU and 60.36 forced-WebGL2 Icon Grid FPS. diff --git a/docs/packages/benchmarks.md b/docs/packages/benchmarks.md index 0d1715ba..41d59fb2 100644 --- a/docs/packages/benchmarks.md +++ b/docs/packages/benchmarks.md @@ -5,7 +5,7 @@ description: Provides the shared interactive and automated benchmark product sur resource: ../../apps/benchmarks workspace_package: '@pmndrs/text-benchmarks' documentation_type: reference -source_digest: 'sha256:a3249a57a4127fb5db7c88691b593af378c36902a26b22e43c6ea3cb6292c00d' +source_digest: 'sha256:904d2b6f17edd76cb888c1b4f81e133837792b9b163d67247159b6feb3344cf2' tags: [package, benchmarks, react, vite, product-e2e] sources: - id: manifest @@ -60,8 +60,17 @@ sources: resource: ../../apps/benchmarks/fixtures/results/icon-grid-retained-evidence-chromium149.json title: Retained complete icon-grid traversal evidence - id: raster-technique-compare - resource: ../../apps/benchmarks/src/renderer/raster-technique-compare.ts - title: Realtime MSDF and Slug GPU comparison + resource: ../../apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.ts + title: Target-owned realtime MSDF and Slug GPU comparison + - id: low-level-raster-reference + resource: ../../apps/benchmarks/src/benchmark/low-level/raster/source-outline-reference.ts + title: Shared low-level source-outline oracle + - id: external-raster-product-target + resource: ../../apps/benchmarks/src/benchmark/targets/product/external-raster-proof.ts + title: External raster public-API product proof + - id: react-text-product-target + resource: ../../apps/benchmarks/src/benchmark/targets/product/react-text.ts + title: React Text reconciliation product target - id: renderer-lifecycle resource: ../../apps/benchmarks/src/renderer/webgpu-renderer.ts title: Shared renderer creation and disposal lifecycle @@ -103,7 +112,7 @@ sources: title: Realtime comparison product probe generated: by: openai-codex/gpt-5.6 - at: '2026-08-03T10:33:55Z' + at: '2026-08-03T10:48:46Z' --- # Package reference: `@pmndrs/text-benchmarks` @@ -141,7 +150,7 @@ Main and Presentation are exclusive URL-selected root presentations. Presentatio Every live benchmark identity resolves through one typed catalog under `apps/benchmarks/src/workloads/`. The catalog owns labels, descriptions, exact Main and Presentation defaults, font policy, controls and ranges, pan/zoom capability, preload policy, and surface kind; URL parsing normalizes an unknown workload inside its selected mode before font or control policy executes. Main and Presentation derive scene descriptions, amount labels, font selection, preload grouping, and pan/zoom capability from that authority rather than repeating workload-ID switches. Benchmark Ipsum and Advanced Shaping keep their authored corpus and timeline in the same workload hierarchy as Text Ladder, Zoom Text, Icon Grid, Off-axis / 3D, Dynamic Layout, Paragraph Stress, and Paint & Effects. They project their complete anchor, direction, feature, fixture, language, measure, text, alignment, glyph expectation, and timeline intent through the small `LiveTextScene` contract; the route only supplies runtime font size and selects a technique adapter. Advanced Shaping derives the font fixture from the authored case itself, preventing the displayed script and fixture from drifting. The seven retained comparison definitions own construction, layout, animation, and retained configuration hooks; no workload-specific dispatch switch remains for those phases. Icon Grid additionally owns one per-mount instance containing virtual-window epochs, pool assignment and recycling, scroll and auto-pan state, frame smoothing, refresh suspension, visibility, and metrics. The host exposes only generic cold pool resize/readiness, scene attachment, and disposal; renderer, canvas, RAF, GPU timer, font transactions, and telemetry history remain route infrastructure. Each workload mount explicitly initializes the shared scene transform, preventing Text Ladder's authored offscreen exit or Icon Grid pan from polluting the next workload. Their technique-invariant content-width, text-style, and color-cycle utilities live below `workloads/shared`; a source-boundary test rejects static or dynamic imports from any workload module back into renderer implementation files. -Main and Presentation composition lives in `components/harness-layout.tsx`, runtime control binding in `components/runtime-controls.tsx`, and benchmark surface/bake status in `surfaces/benchmark`; the root application remains the route coordinator rather than the sole component hierarchy. The three persistent Bitmap, MTSDF, and Slug live-text viewport controllers also live under `surfaces/benchmark`, keeping their host lease, warm update queue, loading state, telemetry, and probe contract beside the rendered surface. Their renderer imports remain literal dynamic boundaries: type-only references use `import type`, so the production build retains separate technique chunks rather than pulling renderer implementations into the route entry. Authored scenes load fixtures through `workloads/font-assets`: one discriminated adapter selects only the requested Bitmap, MTSDF, or Slug lane through literal dynamic imports, while each lane uses the public `FontLoader`, `FontRegistry`, raster request, and `@pmndrs/text/runtime-bake` entrypoint. The adapter owns source-font URLs, baked transport URLs, gzip and SHA-256 authentication, runtime progress and delivery metrics, and bounded default registries; renderer modules retain only live GPU lifecycle, configuration, statistics, and compatibility delegates. Direct font-baker imports and Wasm URLs remain prohibited from this workload-facing path. Conformance React composition lives under `surfaces/conformance`: both the retained comparison and finite captures can receive only the host-owned renderer, while finite low-level dispatch stays below `benchmark/targets/conformance` and `benchmark/targets/measurement`. Advanced Shaping lives in that target hierarchy behind the registry's literal selected-target dynamic import. MTSDF and Slug sampling plus source-outline targets share a target-owned raster conformance session that preserves warm `load → run → dispose` reuse and forwards the borrowed renderer and abort signal unchanged; renderer-private capture resources remain inside their adapters. The targets share the explicitly named `targets/shared/direct-wasm.ts` dependency adapter only after target selection. The public missing-sibling loader Worker is conformance because it proves authenticated Worker bytes and loader fallback behavior; it is not a rendering product target. Boundary tests reject workload imports back into renderer implementation, isolate renderer imports to the raster adapters, authenticate the literal Advanced Shaping target import, preserve selected-technique asset chunks, and reject direct font-baker or Wasm URL imports outside the shared adapter, preventing raw tooling from leaking into the normal Presentation module graph. +Main and Presentation composition lives in `components/harness-layout.tsx`, runtime control binding in `components/runtime-controls.tsx`, and benchmark surface/bake status in `surfaces/benchmark`; the root application remains the route coordinator rather than the sole component hierarchy. The three persistent Bitmap, MTSDF, and Slug live-text viewport controllers also live under `surfaces/benchmark`, keeping their host lease, warm update queue, loading state, telemetry, and probe contract beside the rendered surface. Their renderer imports remain literal dynamic boundaries: type-only references use `import type`, so the production build retains separate technique chunks rather than pulling renderer implementations into the route entry. Authored scenes load fixtures through `workloads/font-assets`: one discriminated adapter selects only the requested Bitmap, MTSDF, or Slug lane through literal dynamic imports, while each lane uses the public `FontLoader`, `FontRegistry`, raster request, and `@pmndrs/text/runtime-bake` entrypoint. The adapter owns source-font URLs, baked transport URLs, gzip and SHA-256 authentication, runtime progress and delivery metrics, and bounded default registries; renderer modules retain only live GPU lifecycle, configuration, statistics, and compatibility delegates. Direct font-baker imports and Wasm URLs remain prohibited from this workload-facing path. Conformance React composition lives under `surfaces/conformance`: both the retained comparison and finite captures can receive only the host-owned renderer, while executable low-level work lives below `benchmark/targets/conformance`, `benchmark/targets/product`, and `benchmark/targets/measurement`. The realtime MTSDF/Slug comparison, runtime-fallback capture, external raster proof, and React reconciliation target are owned by those explicit target trees rather than `renderer`. Pure CPU raster and source-outline oracles live separately under `benchmark/low-level/raster`, so renderer-adjacent finite capture code can share primitives without importing executable targets; a source-boundary regression prohibits renderer-to-target dependencies. Advanced Shaping lives in the conformance target hierarchy behind the registry's literal selected-target dynamic import. MTSDF and Slug sampling plus source-outline targets share a target-owned raster conformance session that preserves warm `load → run → dispose` reuse and forwards the borrowed renderer and abort signal unchanged; renderer-private capture resources remain inside their adapters. The targets share the explicitly named `targets/shared/direct-wasm.ts` dependency adapter only after target selection. The public missing-sibling loader Worker is conformance because it proves authenticated Worker bytes and loader fallback behavior; it is not a rendering product target. Boundary tests reject workload imports back into renderer implementation, isolate renderer imports to the raster adapters, authenticate literal selected-target imports, preserve selected-technique asset chunks, and reject direct font-baker or Wasm URL imports outside the shared adapter, preventing raw tooling from leaking into the normal Presentation module graph. Timed playback compares each frame with the latest requested location rather than the last committed scene, so an in-flight preload receives exactly one request and cannot be superseded by a duplicate transition that skips workload-default initialization. Presentation captures Space at the window capture boundary to start or stop timed playback even while a button, switch, slider, select, or combobox owns focus; matching key-up activation is suppressed, while inputs, textareas, and editable text retain ordinary space entry. Arrow navigation remains disabled on interactive controls. diff --git a/docs/planning/api-shapes.md b/docs/planning/api-shapes.md index 9952215b..75514e0e 100644 --- a/docs/planning/api-shapes.md +++ b/docs/planning/api-shapes.md @@ -20,7 +20,7 @@ sources: resource: '../../apps/benchmarks/src/workloads/catalog.ts' title: 'Typed benchmark workload catalog' - id: 'raster-technique-comparison' - resource: '../../apps/benchmarks/src/renderer/raster-technique-compare.ts' + resource: '../../apps/benchmarks/src/benchmark/targets/conformance/raster/comparison-scene.ts' title: 'Retained MSDF and Slug comparison scene' generated: