Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ The compiled scene renderer is excluded from both Solar builds.
- `src/engine/frame-patches.ts` owns scalar coalescing and covering presentation
receipts; commands and structure keep their ordered execution.
- `src/engine/vision-frames.ts` owns one combined state/media submission in flight
through MessageChannel. `vision-media-bridge.ts` captures the supported WASM
engine dependency for upload before that same submission. Fixed-window cadence
through MessageChannel. The presenter stages camera pixels inside its serialized
Rust/WASM request queue before the same submission. Fixed-window cadence
and encoded pixels are qualified in `docs/development/render-cadence.md`.
- `src/internal/native-tree.ts` owns draft2 Merkle hashing, checked against the
byte-pinned upstream vectors and the real native server.
Expand Down
8 changes: 4 additions & 4 deletions docs/development/code-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ Entries: `src/index.ts`, `src/server/index.ts`, `src/dev-entry.ts`, `src/host-en
| [src/engine/sound/graph.ts](../../src/engine/sound/graph.ts) | [src/engine/sound/README.md](../../src/engine/sound/README.md) | `SoundBus`, `SoundGraph`, `createSoundGraph` | src/engine/sound/catalogue.ts | src/engine/sound/automation.ts, src/engine/sound/controller.ts, src/engine/sound/offline.ts, src/engine/sound/voice.ts | tests/unit/sound.test.ts |
| [src/engine/sound/offline.ts](../../src/engine/sound/offline.ts) | [src/engine/sound/README.md](../../src/engine/sound/README.md) | `renderSound` | src/engine/sound/assets.ts, src/engine/sound/catalogue.ts, src/engine/sound/graph.ts, src/engine/sound/voice.ts, src/scenes/native-document.ts | src/engine/native-lsdp-runtime.ts | via consuming boundary |
| [src/engine/sound/voice.ts](../../src/engine/sound/voice.ts) | [src/engine/sound/README.md](../../src/engine/sound/README.md) | `startVoice` | src/engine/sound/catalogue.ts, src/engine/sound/graph.ts | src/engine/sound/controller.ts, src/engine/sound/offline.ts | tests/unit/sound.test.ts |
| [src/engine/vision-composition-frame.ts](../../src/engine/vision-composition-frame.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionCompositionOwner`, `VisionCompositionCapture`, `VisionCompositionSurface`, `VisionCompositionCoverageSurface`, `VisionCompositionFrame`, `appearance`, `nullableFields`, `framing`, `invalid`, `acceptVisionCompositionFrame` | none | src/engine/vision-contracts.ts, src/engine/vision-media-bridge.ts, src/engine/vision-presenter.ts, src/scenes/native-composition.ts | tests/bench/native-composition-capture-translation.bench.ts, tests/helpers/vision-composition-coverage.ts, tests/helpers/vision-composition-frame.ts, tests/unit/native-composition-coverage.test.ts, tests/unit/native-composition.test.ts, tests/unit/vision-composition-frame.test.ts |
| [src/engine/vision-contracts.ts](../../src/engine/vision-contracts.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionLiveMediaSource`, `VisionPresenterMessage`, `VisionMediaSubmitReceipt`, `VisionSceneHandle`, `VisionRenderPackage` | src/engine/vision-composition-frame.ts, src/scenes/verified-font.ts | src/engine/live-media-metrics.ts, src/engine/native-composition-session.ts, src/engine/vision-frames.ts, src/engine/vision-media-bridge.ts, src/engine/vision-presenter.ts | tests/unit/native-composition-session.test.ts, tests/unit/vision-session.test.ts |
| [src/engine/vision-composition-frame.ts](../../src/engine/vision-composition-frame.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionCompositionOwner`, `VisionCompositionCapture`, `VisionCompositionSurface`, `VisionCompositionCoverageSurface`, `VisionCompositionFrame`, `appearance`, `nullableFields`, `framing`, `invalid`, `acceptVisionCompositionFrame` | none | src/engine/vision-contracts.ts, src/engine/vision-media-sources.ts, src/engine/vision-presenter.ts, src/scenes/native-composition.ts | tests/bench/native-composition-capture-translation.bench.ts, tests/helpers/vision-composition-coverage.ts, tests/helpers/vision-composition-frame.ts, tests/unit/native-composition-coverage.test.ts, tests/unit/native-composition.test.ts, tests/unit/vision-composition-frame.test.ts |
| [src/engine/vision-contracts.ts](../../src/engine/vision-contracts.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionLiveMediaSource`, `VisionPresenterMessage`, `VisionMediaSubmitReceipt`, `VisionSceneHandle`, `VisionRenderPackage` | src/engine/vision-composition-frame.ts, src/scenes/verified-font.ts | src/engine/live-media-metrics.ts, src/engine/native-composition-session.ts, src/engine/vision-frames.ts, src/engine/vision-media-sources.ts, src/engine/vision-presenter.ts | tests/unit/native-composition-session.test.ts, tests/unit/vision-session.test.ts |
| [src/engine/vision-font-assets.ts](../../src/engine/vision-font-assets.ts) | [src/engine/README.md](../../src/engine/README.md) | `loadHostFonts`, `visionFontResponse` | src/scenes/verified-font.ts | src/engine/vision-presenter.ts | via consuming boundary |
| [src/engine/vision-frames.ts](../../src/engine/vision-frames.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionFrame`, `VisionFrames`, `VisionFrames.addPatch`, `VisionFrames.addMedia`, `VisionFrames.pending`, `VisionFrames.schedule`, `VisionFrames.flush`, `VisionFrames.close` | src/engine/vision-contracts.ts | src/engine/vision-presenter.ts | tests/unit/vision-frames.test.ts |
| [src/engine/vision-media-bridge.ts](../../src/engine/vision-media-bridge.ts) | [src/engine/README.md](../../src/engine/README.md) | `MediaEngine`, `EngineFactory`, `VisionMediaBridge`, `VisionMediaBridge.module`, `VisionMediaBridge.upload`, `VisionMediaSources`, `VisionMediaSources.filterOwned`, `VisionMediaSources.update`, `VisionMediaSources.accept`, `VisionMediaSources.publish` | src/engine/vision-composition-frame.ts, src/engine/vision-contracts.ts | src/engine/vision-presenter.ts | tests/unit/vision-media-bridge.test.ts, tests/unit/vision-session.test.ts |
| [src/engine/vision-presenter.ts](../../src/engine/vision-presenter.ts) | [src/engine/README.md](../../src/engine/README.md) | `PresenterEvent`, `VisionPresenter`, `PresenterModule`, `PersistentVisionSession`, `PersistentVisionLifetime`, `visionMaxTextureSize`, `disconnectedError`, `lifetimeFor`, `isCurrentLifetime`, `assertCurrentLifetime`, `awaitLifetime`, `createSessionPresenter`, `listenToSession`, `disconnectVisionSession`, `mountVisionScene`, `prewarmVisionSession`, `mountVisionSceneNow`, `activateVisionScene`, `visibleState`, `mediaSubmitReceipt` | src/engine/canvas-presentation.ts, src/engine/vision-composition-frame.ts, src/engine/vision-contracts.ts, src/engine/vision-font-assets.ts, src/engine/vision-frames.ts, src/engine/vision-media-bridge.ts, src/scenes/native-document.ts, src/scenes/types.ts, src/scenes/verified-font.ts | src/engine/live-media.ts, src/engine/native-lsdp-runtime.ts, src/engine/native-scene-frames.ts | tests/unit/instance-sources.test.ts, tests/unit/live-media.test.ts, tests/unit/vision-session.test.ts |
| [src/engine/vision-media-sources.ts](../../src/engine/vision-media-sources.ts) | [src/engine/README.md](../../src/engine/README.md) | `VisionMediaSources`, `VisionMediaSources.filterOwned`, `VisionMediaSources.update`, `VisionMediaSources.accept`, `VisionMediaSources.publish` | src/engine/vision-composition-frame.ts, src/engine/vision-contracts.ts | src/engine/vision-presenter.ts | via consuming boundary |
| [src/engine/vision-presenter.ts](../../src/engine/vision-presenter.ts) | [src/engine/README.md](../../src/engine/README.md) | `PresenterEvent`, `VisionPresenter`, `PresenterModule`, `PersistentVisionSession`, `PersistentVisionLifetime`, `visionMaxTextureSize`, `disconnectedError`, `lifetimeFor`, `isCurrentLifetime`, `assertCurrentLifetime`, `awaitLifetime`, `createSessionPresenter`, `listenToSession`, `disconnectVisionSession`, `mountVisionScene`, `prewarmVisionSession`, `mountVisionSceneNow`, `activateVisionScene`, `visibleState`, `mediaSubmitReceipt` | src/engine/canvas-presentation.ts, src/engine/vision-composition-frame.ts, src/engine/vision-contracts.ts, src/engine/vision-font-assets.ts, src/engine/vision-frames.ts, src/engine/vision-media-sources.ts, src/scenes/native-document.ts, src/scenes/types.ts, src/scenes/verified-font.ts | src/engine/live-media.ts, src/engine/native-lsdp-runtime.ts, src/engine/native-scene-frames.ts | tests/unit/instance-sources.test.ts, tests/unit/live-media.test.ts, tests/unit/vision-session.test.ts |
| [src/host-entry.ts](../../src/host-entry.ts) | [README.md](../../README.md) | `SolarHostConfig`, `localFonts` | src/mount.ts, src/scenes/canvas.ts, src/scenes/installation-fonts.ts, src/scenes/local-images.ts, src/scenes/local-library.ts, src/scenes/verified-font.ts, src/types/index.ts | declared entry | via consuming boundary |
| [src/index.ts](../../src/index.ts) | [README.md](../../README.md) | entry | src/mount.ts, src/scenes/browser-store.ts, src/scenes/cache.ts, src/scenes/canvas.ts, src/scenes/startup.ts, src/scenes/types.ts, src/types/index.ts | declared entry | tests/unit/mount.test.ts, tests/unit/scene-source.test.ts |
| [src/internal/native-digest.ts](../../src/internal/native-digest.ts) | [src/internal/README.md](../../src/internal/README.md) | `workerDigest` | @noble/hashes/sha256 | src/engine/native-worker.ts | tests/unit/native-digest.test.ts |
Expand Down
5 changes: 3 additions & 2 deletions docs/development/render-cadence.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ a browser RAF heartbeat counts as a new rendered mutation state.
scalar values through a microtask. `src/engine/vision-frames.ts` owns one actual
submission in flight, scheduled by MessageChannel rather than a 60 Hz RAF.
Camera-only work schedules the same immediate MessageChannel task as state.
Arrivals before that task share a submission without a fixed timer delay. `vision-media-bridge.ts` uploads the latest owned
camera image before the same state submission. Errors reject the covered callers;
Arrivals before that task share a submission without a fixed timer delay. The
presenter stages the latest owned camera image inside its serialized Vision
queue before the same state submission. Errors reject the covered callers;
scene transitions and ordered commands drain pending presentation first.

Vision retains glyph tessellation (1024 entries, 8 MiB), byte-identical shader
Expand Down
2 changes: 1 addition & 1 deletion docs/development/scene-feature-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ does not resolve or compile a RenderBundle.
| Active exact-version child LSML graph, package asset verification, bounded HTTP image localization and Vision transfer | `src/scenes/instances.ts`, `src/scenes/instance-images.ts`, `src/scenes/native-document.ts`, `src/scenes/cache.ts`, `src/scenes/local-library.ts`, `src/engine/native-scene-frames.ts` | `tests/unit/instance-sources.test.ts`, `tests/unit/scene-source.test.ts`, `tests/unit/scene-cache.test.ts`, `tests/unit/scene-library.test.ts`; private Chrome/Vision WASM qualification; separated Canvas package assets remain pinned SHA-256 paths |
| Native binary WebSocket snapshots, exact selectors, source fetch and distinct reception/presentation receipts | `src/engine/native-lsdp-runtime.ts`, `vendor/lsdp-native-browser/` | `tests/unit/native-lsdp-runtime.test.ts`; `scripts/test-native-lsdp.mjs` |
| Scalar coalescing with every mutation retained in covering presentation receipts | `src/engine/frame-patches.ts` | `tests/unit/frame-patches.test.ts`; blocked-frame native subscriber proof |
| Combined state/camera submission without a RAF cap, immediate coalesced task and owned bitmap lifecycle | `src/engine/vision-frames.ts`, `src/engine/vision-media-bridge.ts` | `tests/unit/vision-frames.test.ts`, `tests/unit/vision-media-bridge.test.ts`; fixed-window CEF cadence and encoded counter |
| Combined state/camera submission without a RAF cap, immediate coalesced task and owned bitmap lifecycle | `src/engine/vision-frames.ts`, `src/engine/vision-media-sources.ts` | `tests/unit/vision-frames.test.ts`, `tests/unit/vision-session.test.ts`; fixed-window CEF cadence and encoded counter |
| Atomic LSML operations, text-value projection and temporary render packages with pinned assets/provenance | `src/scenes/native-document.ts` | `tests/unit/native-document.test.ts` |
| Native draft2 Merkle hashes and portable JSON conformance | `src/internal/native-tree.ts` | upstream vectors in `tests/unit/native-document.test.ts`; Rust interoperability |
| Atomic path copies and incremental native integrity without full-scene rehash per leaf | `src/internal/native-state.ts`, `src/internal/native-tree.ts` | `tests/unit/native-state.test.ts`; runtime and reception consumers |
Expand Down
22 changes: 15 additions & 7 deletions public/vision/ui/mainpresenter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ export function createMainThreadPresenter(canvas, dependencies = {}) {
const applyStartedAt = clock.now();
let rawMetadata;
try {
if (request.frames !== undefined) await stageLiveFrames(request.frames, ticket);
await registerPatchImages(request.images, ticket);
rawMetadata = await engine.apply_patch(request.patchJson);
ensureActive(ticket);
Expand All @@ -500,6 +501,8 @@ export function createMainThreadPresenter(canvas, dependencies = {}) {
engine.prune_unreferenced_image_assets?.();
syncUploadedAssets(engine);
throw withContext(error, "patch", { ...receipt, engineApplyCallMs: elapsedSince(applyStartedAt) });
} finally {
for (const frame of request.frames ?? []) frame?.bitmap?.close?.();
}

const engineApplyCallMs = elapsedSince(applyStartedAt);
Expand Down Expand Up @@ -536,13 +539,7 @@ export function createMainThreadPresenter(canvas, dependencies = {}) {
throw withContext(new Error("A live media update must contain at least one frame."), "media-frames", receipt);
}
try {
for (const frame of request.frames) {
if (!frame || typeof frame.path !== "string" || !frame.bitmap || typeof frame.bitmap.close !== "function") {
throw new Error("A live media frame needs a path and an owned ImageBitmap.");
}
await engine.update_live_image(frame.path, frame.bitmap);
ensureActive(ticket);
}
await stageLiveFrames(request.frames, ticket);
if (latestSize) await submit(request.seq, latestSize, receipt, ticket);
lastAppliedSequence = request.seq;
emit({ type: "media-applied", seq: request.seq, mediaSources: readMediaSources(engine), timing: receipt });
Expand All @@ -553,6 +550,17 @@ export function createMainThreadPresenter(canvas, dependencies = {}) {
}
}

async function stageLiveFrames(frames, ticket) {
if (!Array.isArray(frames)) throw new Error("Live media frames must be an array.");
for (const frame of frames) {
if (!frame || typeof frame.path !== "string" || !frame.bitmap || typeof frame.bitmap.close !== "function") {
throw new Error("A live media frame needs a path and an owned ImageBitmap.");
}
await engine.update_live_image(frame.path, frame.bitmap);
ensureActive(ticket);
}
}

async function clearLiveFrames(request, receipt, ticket) {
if (!Array.isArray(request.paths) || request.paths.some((path) => typeof path !== "string" || path.length === 0)) {
throw withContext(new Error("A live media clear must contain valid image paths."), "media-clear", receipt);
Expand Down
Loading
Loading