Genetic code: sdk.media.gen1
Parent principle: repo.engineering.client_side_computation.gen1 (Tier 0)
Attached as: sdk.media.* on the AgentStackSDK instance (see sdk.ts).
Client-side media primitives that make every surface (messenger, storage explorer, dashboard, widgets, third-party integrators) fast, offline-tolerant, and cheap on server CPU. The server already has enough to do; whatever the client can compute locally from bytes it already downloaded, we compute locally.
| File | Genetic sub-tag | Responsibility |
|---|---|---|
opfsStore.ts |
sdk.media.opfs.gen1 |
Namespaced OPFS KV with LRU eviction. Feature-detected; browser-only; tests can inject a root. |
thumbnailer.ts |
sdk.media.thumbnail.gen1 |
Image + video thumbnails via createImageBitmap / OffscreenCanvas. Cache keyed by SHA-256 of source bytes. |
resumableUpload.ts |
sdk.media.resumable.gen1 |
Generic tus-lite HEAD/PATCH loop. Adapters for in-memory Blob and OPFS-staged sources. Supports storage-target routing via X-Upload-Target: storage. |
lightbox.ts |
sdk.media.lightbox.gen1 |
Headless PhotoSwipe adapter — dynamic import('photoswipe'); host imports photoswipe/style.css once (import.meta.url CSS <link> breaks under /assets/*.js). |
lightboxViewport.ts |
sdk.media.lightbox.gen1 |
getLightboxViewportSize, shouldOfferOrientationMatch — pure math + visualViewport for app lightbox rotate UX. |
probeImageNaturalSize.ts |
sdk.media.lightbox.gen1 |
Off-DOM Image probe for natural width/height (timeout, no fake dims). |
browserDownload.ts |
sdk.media.lightbox.gen1 |
sanitizeDownloadFilename, downloadUrlAsFile — fetch+blob anchor, CORS fallback window.open. |
lightboxSlideDownload.ts |
sdk.media.lightbox.gen1 |
URL + basename from LightboxSlide for download menus. |
audio/ |
sdk.media.audio.gen1 |
createAudioCapture — RNNoise worklet (denoise.ts) + HPF / gate / compressor / limiter (enhance.ts) + profiles. Lazy worklet bundle URL via worklet-url.ts. |
photo/ |
sdk.media.photo.gen1 |
compressPhoto — multi-size ladder (presets.ts), @jsquash/* encoders (dynamic import), BlurHash, OPFS cache sdk-media-photos-v1. |
index.ts |
sdk.media.gen1 |
createAgentStackMedia() aggregates all primitives into the sdk.media surface. |
The resumable loop matches agentstack-core/endpoints/files_endpoints.py (HEAD / PATCH tus-lite). Storage-target headers:
| Header | Values | Effect |
|---|---|---|
X-Upload-Target |
storage |
Finalize into 8DNA data.ecosystem.storage via storage_organelle. |
X-Upload-Folder |
docs__reports, _ (root) |
Storage folder key. |
X-Upload-Scope |
user (default) · project |
8DNA row selection. |
X-Upload-Category |
user, system, … |
Category tag on the stored card. |
X-Upload-Project-Id |
123 |
Override for X-Project-ID. |
| (missing) | Legacy behaviour — generic uploads/ category (messenger, banners). |
- Messenger:
MessengerImageLightboxProviderusessdk.media.lightboxunder the hood — pinch-zoom, swipe-close, spring animation; public API (open(src, alt)) unchanged. - Messenger (media v2):
messengerComposerMediaCapture.tswiressdk.media.audio.createCapturebehind rollout flags;MessengerPage.tsxsendFilesmay callsdk.media.photo.compressfor large images; beacons viamessengerBeacons.ts. - Storage explorer (planned / in-flight):
StorageFileInlineMediaPreviewbecomesStorageFileThumbnailbacked bysdk.media.thumbnail. Clicking the thumbnail openssdk.media.lightboxinstead of relying on a<video>/<img>tag per row. - Future: widget previews, marketplace asset screenshots, profile avatars — same
sdk.mediasurface.
- Owned: OPFS KV, thumbnail pipeline, tus-lite loop. No library earns a spot here unless writing it ourselves would be a >1-month engineering effort.
- Adopted:
photoswipe(one stylesheet at app root, e.g.import 'photoswipe/style.css'inAppImageLightboxProvider.tsx; dynamic JS import; zero core-bundle cost).
Each primitive is expected to emit an OpTrace beacon from the consumer
(frontend wiring in messengerBeacons.ts or storage telemetry):
media.thumbnail.gen_ms_p95media.thumbnail.cache_hit_ratemedia.opfs.usage_bytes(per namespace)media.resumable.recovered_bytes(bytes recovered across reloads)media.lightbox.opens- Audio v2 (histogram unless noted):
media.audio.denoise.init_ms,media.audio.denoise.frame_ms(EMA reported by the worklet every ~2s viaport.postMessage({ type: 'frame_ms', ema, samples }), forwarded throughcapture.telemetry.onDenoiseFrameMs); countersmedia.audio.denoise.fallback_used,messenger.voice.denoise.bypass_hit; histogrammedia.video_note.av_sync_ms. - Photo v2: histogram
media.photo.compress.total_ms; gaugemedia.photo.compress.bytes_saved_ratio.used(payloadbytes= ratio 0–100); countersmedia.photo.compress.cache_hit,media.photo.compress.skipped_larger,media.photo.encoder.fallback_used(tagged).- Internals: encoder modules are dynamic imports cached on first invocation; a single warmup then serves parallel encode jobs (
Promise.allover allsize×formatpairs). OPFS cache key is prefix-hashed for files ≥ 4 MiB so re-sending a large picture never reads the whole blob into memory twice. Variants whose encode grows the original are returned as-is but never written to OPFS (keeps the per-variant slot clean for the next better-compressing run).
- Internals: encoder modules are dynamic imports cached on first invocation; a single warmup then serves parallel encode jobs (
- Importing
photoswipestatically anywhere in the SDK — it must remain a dynamic import to stay tree-shaken. - Importing
@jsquash/*or the RNNoise worklet bundle from the SDK main entry — keep encoders behind dynamicimport()and the worklet behindaddModule+ copieddist/media/audio/*.bundle.jsonly. - Reading entire large files into memory for thumbnail cache keys. Use the
url_*key path when the source is a URL, or SHA-256 a streamed subset. - Creating a per-app OPFS store when
sdk.media.opfs.create({ namespace })already exists. - Extending the resumable protocol with new headers in one consumer — add the field to
ResumableUploadTargetinresumableUpload.tsso every consumer benefits. - Spinning a second
AudioContextfor metering whencreateAudioCapture({ monitor: { rafMeter: true } })already exposesmeter— reuse one graph end-to-end.
- Principle: philosophy/genes/repo.engineering.client_side_computation.gen1.md
- Backend: endpoints/files_endpoints.py, services/resumable_upload_service.py, endpoints/storage_endpoints.py (
finalize_resumable_into_storage). - Messenger precedent: frontend.social.messenger.opfs.gen1,
agentstack-frontend/src/lib/messenger/opfs/. - Navigation row:
sdk.media.gen1in docs/AI_NAVIGATION_MAP.md.