-Cutmark is a browser-based video editor for trimming clips and polishing them with optional scene detection and captions. Set precise in and out points, review the result, and export an MP4.
+Cutmark is a local browser-based video editor for precise trims, joined ranges, named clips and small multi-source assemblies. Correct captions, reframe footage, adjust audio, add titles/logos, and export a reviewed MP4.
**Try it live:** [cutmark.dev](https://cutmark.dev)
@@ -12,10 +12,25 @@ Cutmark is a browser-based video editor for trimming clips and polishing them wi
- Import MP4, MOV, WebM, and MKV videos.
- Set an exact trim range by dragging the timeline or entering timecodes.
-- Preview the selected range and jump to detected scene changes.
-- Export clips as MP4.
-- Optionally detect scene changes and generate editable captions.
-- Reopen recent projects saved in the current browser.
+- Review decoded source thumbnails and audio peaks, zoom the timeline, and navigate long footage.
+- Preview and loop a selection, review cut context, step decoded frames, and change preview speed/volume.
+- Keep, split, remove and reorder source sections with exact video/sample timing.
+- Export named clips sequentially with independent captured formats and safe cancellation.
+- Assemble up to four local sources, including mixed dimensions/frame rates and missing-media relinking.
+- Reframe landscape, square and portrait versions with fit/fill, drag/scale, rotation/flips and preview-only guides.
+- Adjust exported gain/mute/fades separately from listening volume; review measured pause suggestions.
+- Add timed titles/lower thirds and transparent local image/logo layers.
+- Capture source/composed PNGs and download a timecoded edit report.
+- Scan source or selected footage with recorded coverage, sensitivity and frame refinement; confirm, move or dismiss scene candidates safely.
+- Add searchable named source markers with color and notes, independent of scene detection.
+- Independently transcribe English captions for the selection or full source.
+- Correct, search, split, merge, shift and replace captions with undo and readability guidance.
+- Import/export reviewed SRT/VTT, style captions, and choose actual burned-in MP4 captions or subtitle files.
+- Save portable project files/source-inclusive bundles and reusable output/naming presets.
+- Autosave unfinished projects and reopen them in the current browser.
+- Undo and redo range, caption, marker, framing, audio, title/image and assembly decisions.
+- Inspect actual source frames, enter hour timecodes, and cancel processing safely.
+- Keep previous exports downloadable while revising or retrying.
- Keep video processing on the device; source clips are not uploaded to an application server.
## Technologies
@@ -31,7 +46,7 @@ Cutmark is a browser-based video editor for trimming clips and polishing them wi
I built Cutmark as a static Next.js app so the editor can run without a video-processing backend. The browser uses WebCodecs when available and falls back to FFmpeg WebAssembly for trimming and encoding. Scene detection and speech transcription are optional steps, so the basic export workflow can stay lightweight.
-Recent projects are stored in IndexedDB in the browser. New projects keep the source clip and edit settings so they can be reopened and edited later. The source clip stays on the user's device; the English speech model is downloaded from Hugging Face the first time captions are generated. Repeated word sequences are limited to prevent speech recognition loops from filling the transcript.
+Unfinished drafts and exports are stored separately in IndexedDB in the browser. Projects keep source media, editable captions, scene cuts, selections, and the last successful output. Projects remain until explicitly deleted; browser storage is not a backup. The source clip stays on the user's device; the English speech model is downloaded from Hugging Face the first time captions are generated. Caption corrections remain in source time across trims and exports. Recognition text is preserved for review rather than automatically deleting repeated words.
For deployment, the site is exported as static files and served from a private S3 bucket through CloudFront. GitHub Actions builds the frontend and deploys it when changes reach `main`.
@@ -62,3 +77,24 @@ Caption generation downloads the Whisper Tiny English model on first use. It tra
## License
MIT. See [LICENSE](LICENSE).
+
+
+## Implementation verification and backlog
+
+See the [Phase 1 safety checklist](docs/phase-1.md), [Phase 2 visual-editing checklist](docs/phase-2.md), [Phase 3 caption-delivery checklist](docs/phase-3.md), [Phase 3 export-settings checklist](docs/phase-3-export.md), the [Phase 3 recovery/storage checklist](docs/phase-3-recovery.md), [Phase 4 repurposing checklist](docs/phase-4.md), [Phase 5 workflow checklist](docs/phase-5.md), and [complete item-status matrix](docs/backlog.md) for implemented, verified and deferred work.
+
+Frontend checks: `npm test`, `npm run lint`, and `npm run build`. Builds and development use Next.js Webpack because the default bundler emitted the processing workers as TypeScript assets rather than executable JavaScript.
+
+The browser suite at `frontend/tests/browser.mjs` generates local fixtures with FFmpeg and exercises the production export in Edge. It requires Playwright, an installed Edge browser, FFmpeg/ffprobe on PATH, and a local static server. Set `CUTMARK_TEST_URL` to that server, `CUTMARK_PLAYWRIGHT_PATH` to an installed Playwright package if it is not available normally, and optionally `CUTMARK_ARTIFACTS` to a folder for fixtures, outputs, and screenshots; then run `node tests/browser.mjs` from `frontend`.
+
+The Phase 2 suite at frontend/tests/phase2.mjs exercises decoded thumbnails/waveforms, native transport, source-based transcript operations and adaptive layout. It uses the Phase 1 fixture directory via CUTMARK_ARTIFACTS. The real-English speech suite also verifies cached recognition and full-source transcription before export.
+
+The scene-tools suite at frontend/tests/scenes.mjs verifies recorded/refined scene analysis, preserved cut corrections, marker notes, interrupted scans and a long source-timed transcript follow/browse workflow. It reuses CUTMARK_ARTIFACTS from the other browser suites.
+
+The caption-delivery suite at frontend/tests/caption-delivery.mjs verifies reviewed SRT/VTT import, persistent styles, actual burned-in MP4 captions, native/compatible paths, portrait wrapping and recovery after cancellation/font/overflow failures. It reuses CUTMARK_ARTIFACTS and requires FFmpeg/ffprobe. Export presets and actual resolution/quality/audio controls are now implemented; portable project backups/relinking, project titles/duplication and targeted cache management are now implemented in Phase 3C.
+
+The export-settings suite at frontend/tests/export-settings.mjs measures native/compatible quality and file-size changes, output dimensions/audio, target-sized caption parity, preset undo/reopening and persisted measured output metadata. It uses the same test environment and writes artifacts under export-settings.
+
+The project-backups and storage-tools suites verify fresh-profile portable recovery, exact-media relinking, shared-media duplication/deletion, version-2 migration, quota rollback, protected downloads and scoped model-cache cleanup. See docs/phase-3-recovery.md for the portable format and completed Phase 3 scope. The Phase 4/5 flows are now implemented; the item-status matrix separates completed core flows from conditional extensions and manual verification gaps.
+
+The new suites are frontend/tests/sequences.mjs, assembly.mjs, framing.mjs, finishing.mjs, images.mjs and join-precision.mjs. They verify actual joins, continuous audio, framing/layer pixels, per-job recovery, multi-asset backups and 100 off-grid VFR ranges without accumulated drift. Build once before starting browser tests; replacing frontend/out while pages load hashed chunks invalidates a run. Exact composed/joined exports require a supported browser video encoder; compatible preparation adapts source codecs locally. See the current checklists for limits rather than assuming all 100 conditional backlog ideas or all browsers are supported.
diff --git a/docs/backlog.md b/docs/backlog.md
new file mode 100644
index 0000000..ee2f358
--- /dev/null
+++ b/docs/backlog.md
@@ -0,0 +1,52 @@
+# Cutmark implementation checklist
+
+The five recommended phases have working core user flows in the local build. This is a product backlog: completion of those phases does not mean every conditional/P3 extension or every device has been implemented or verified. The distinctions below are intentional; deferred controls are not exposed as working features.
+
+## Phase status
+
+| Phase | Delivered scope | Status |
+| --- | --- | --- |
+| 1 — Trust/revision safety | Independent drafts/artifacts, preserved wording, named undo, consistent timing, actual frame inspection, validation, cancellation, autosave/quota safety and legacy recovery | Implemented; regression coverage retained |
+| 2 — Everyday usability | Real thumbnails/waveform, zoom/navigation, transport/shortcuts/context, transcription and transcript tools, scenes/notes, adaptive and keyboard-accessible workspace | Implemented; regression coverage retained |
+| 3 — Deliverable quality | Shared caption burn-in/style, SRT/VTT import/export, real output settings/validation, names/duplicates/backups/relinking and scoped storage tools | Implemented; regression coverage retained |
+| 4 — Repurposing/richer edits | Exact ordered ranges, split/remove, named clip extraction, static reframing/aspect versions, gain/mute/fades/meters, reviewed pauses, titles/logos and frame capture | Implemented; see [Phase 4](phase-4.md) |
+| 5 — Advanced workflow | Small multi-source assembly, linked/independent source corrections, transcript proposals, clip queue/presets/naming and local review/handoff artifacts | Implemented selected P3 flows; see [Phase 5](phase-5.md) |
+
+## Item coverage
+
+| Items | Status and limits |
+| --- | --- |
+| 1–10 | Implemented: revision safety, timing, named/coalesced undo, previous downloads, strict boundaries and decoded frame navigation. |
+| 11–20 | Implemented core timeline/transport/shortcuts/context/synchronization. J/K/L shuttle is conditional and not exposed. |
+| 21–29 | Implemented transcription/editor operations/readability and caption/subtitle delivery. Native accessibility preview is an explicitly separate source view. |
+| 30 | Deferred: animated word emphasis requires trustworthy editable word timings. Segment timestamps are not presented as word timing. |
+| 31–32 | Implemented supported English/local-download/cache workflow. Additional languages/larger models await measured compatibility/performance; none are advertised. |
+| 33–40 | Implemented repetition preservation, no-audio/silence/cancel/retry, recorded scene workflow, candidate correction and editorial notes. Scene scans remain reviewable estimates, not guaranteed editorial truth. |
+| 41–44 | Implemented kept ranges, split/remove/reorder, named clips and explicit source/sequence mappings. Ripple closes gaps; no gap-retaining mode. |
+| 45 | Hard cuts implemented. Optional dissolves/crossfades deferred. |
+| 46–49 | Implemented ratios, fit/fill/solid background, drag/scale/keyboard/numeric placement/reset and non-exported adjustable guides. Blurred backgrounds deferred. |
+| 50 | Deferred: crop keyframes and automatic tracking. Static reframing is complete. |
+| 51–54 | Implemented listening/export distinction, gain/mute/fades, sample-meter/peak feedback and reviewable padded pause removal. No standards-compliant loudness/true-peak claim. |
+| 55 | Deferred: optional local music and ducking. |
+| 56–58 | Implemented timed titles/lower thirds, real transparent raster overlays, orientation/flip/reset/undo and asset recovery. |
+| 59 | Deferred: grading/white balance pending separately verified color/performance behavior. Unverified HDR/wide-color re-encoding is blocked. |
+| 60–65 | Implemented source/composed PNGs, output-oriented rendering, useful quality/resolution/audio/framing settings, presets and actual result metadata. Encoding intent is shared, not a promise of identical codec output bytes. |
+| 66–70 | Implemented cancellation/stale guards/stage progress, relevant failure/retry messages and actual output checks. No invented ETA or success from a bare worker-complete message. |
+| 71–80 | Implemented drafts, names/duplicates, portable references/bundles, exact-source relinking, versioned legacy recovery, explicit retention, shared assets, quota safety and requested durable storage. Browser retention remains a policy decision, not a backup guarantee. |
+| 81–84 | Implemented media/capability checks, special-source guards and bounded native processing/resource cleanup. FFmpeg preparation and final in-memory MP4s still have real device limits. |
+| 85 | Deferred conditional proxy/resource modes; no fake “light preview” switch. Rendered previews explicitly use export settings. |
+| 86–95 | Implemented adaptive/progressive workspace, relevant guidance, keyboard/text alternatives, coarse-pointer sizing and reduced motion. Real screen-reader/touch-hardware and broader-device audits remain manual. |
+| 96 | Implemented up to four sources, explicit IDs/joins, common framing, source captions and missing-video/image recovery. Verified representative mixed dimensions/rates; not a universal codec/device guarantee. |
+| 97–98 | Implemented review-before-apply transcript passage edits and measured pause/peak suggestions. Automated filler/black-frame analysis remains optional future work. |
+| 99 | Implemented sequential primary-source clip jobs, individual cancellation/failure recovery and local reusable style/output/naming presets. Not a crash-resumable background publishing queue. |
+| 100 | Implemented local source/composed images and actual timecoded JSON edit/marker report. Professional interchange formats await target-app verification. |
+
+## Verification record
+
+The current test inventory is 50 unit tests and fourteen production-browser scripts. Tests inspect actual media frames, timestamps, dimensions, tracks, audio gain/fades, text/logo pixels, saved state, cancellations, quota rollback and recovery. The 100-range VFR case detects cumulative join drift rather than relying on approximate total duration alone.
+
+Run npm test, npm run lint and npm run build in frontend. Serve the completed frontend/out directory, then run the browser scripts listed in Phase 5 using CUTMARK_TEST_URL, CUTMARK_PLAYWRIGHT_PATH and CUTMARK_ARTIFACTS. The speech suite also uses CUTMARK_SPEECH_FIXTURE. Do not rebuild the static directory while tests are loading hashed browser chunks.
+
+Available target: Windows Edge. Firefox/Safari, actual phone rotation metadata/touch hardware, screen readers, other-script font fallback, multi-gigabyte/high-resolution sources and sustained heap/GPU profiling remain explicitly unverified. No universal compatibility, unlimited-file-size or error-free guarantee is made.
+
+Final local run: **50 unit tests and all 14 browser suites passed**, with lint, TypeScript and production build successful. See the [dated verification record](verification-2026-10-14.md) for scope and limits.
diff --git a/docs/phase-1.md b/docs/phase-1.md
new file mode 100644
index 0000000..d5b1f76
--- /dev/null
+++ b/docs/phase-1.md
@@ -0,0 +1,103 @@
+# Phase 1 — trust and revision safety
+
+Historical phase checkpoint: the current implementation and verification inventory are tracked in [the complete checklist](backlog.md), [Phase 4](phase-4.md) and [Phase 5](phase-5.md). Portable versions 1–3 and database version 7 supersede the earlier format/storage versions described below.
+
+Implemented locally on main, October 14, 2026. The active checkout was relocated to Desktop/School Notes/Self made Projects/splice; the older workspace path no longer exists. The unrelated pre-existing untracked binary_ninja_lockdownbrowser_dll_functions.md was preserved. No hosting or infrastructure changes are included.
+
+## Editor-visible result
+
+- Export keeps the source, selection, editable captions and scene cuts available for revisions.
+- A prior successful MP4 stays downloadable during an export, cancellation, failure or storage error. Each artifact captures its own revision, range, subtitle snapshot and output settings.
+- Drafts autosave before export. Source and output assets are separate from project metadata. Saving no longer evicts projects beyond five.
+- Caption text is controlled and saved as edit decisions, including intentionally blank text. Exported subtitles are derived separately; trimming never rewrites source cues.
+- Named undo/redo covers trim commits, caption typing/timing/add/remove, scene cut edits and analysis settings. Typing coalesces within 800 ms; a drag commits once. History is bounded to 100 actions and is session-local.
+- Shared timecodes accept seconds, MM:SS and HH:MM:SS with decimal seconds; invalid fields explain the error without changing the project. Escape discards the draft.
+- Frame inspection uses decoded presentation timestamps, including fractional and variable rates. Unsupported decoders fall back to a clearly labeled approximate step.
+- Export, scene scans, model setup and transcription can be cancelled. Stale jobs cannot replace the current project or output.
+- English transcription is an independent action. Regeneration requires an explicit replacement choice; old corrections remain until success and can be restored with undo.
+- Storage failures retain live decisions and downloads. Retry saving, source download and targeted deletion of other saved projects are accessible without leaving the editor.
+- HDR/wide-color metadata is detected. Unverified trimming/re-encoding is blocked; source download remains available.
+
+## Checklist
+
+“Verified” below describes the available Windows Edge test environment, not every browser/device.
+
+| Backlog items | Implementation | Verification / limits |
+| --- | --- | --- |
+| 1–2: project/output separation and caption preservation | Implemented | Export, caption correction, trim, undo/redo, reload, regeneration/undo and repeated export passed. Blank edits and Unicode/multiline cues survive reopening. Existing caption style controls were absent; styling belongs to Phase 3. |
+| 3: explicit timing | Implemented | Source cues/markers remain source-relative. Shared source/sequence conversion and cue clipping tested. Export boundaries tested with real decoded first/last frames. Multi-range joins are not exposed yet. |
+| 4: undo/redo | Implemented for existing controls | Caption coalescing, trim drag commit, marker changes and keyboard undo verified. Crop/audio/range-list controls do not exist yet. Undo stacks are not persisted across reloads. |
+| 5: revision-aware outputs | Implemented | Earlier output labeling, immutable subtitle/settings snapshots and retention through failure/cancellation passed. |
+| 6–7: timecodes and boundaries | Implemented | Invalid/extra components, hours, rounding carry, finite bounds and short media passed. CFR selections require one measured source frame or the whole source if shorter. VFR uses representable timestamp precision instead of a fictitious fixed frame rate. |
+| 8–9: frame stepping and out convention | Implemented | Decoded timestamp stepping/out inspection passed for fractional, VFR, portrait and hour-long fixtures. Approximate decoder fallback is explicitly labeled. |
+| 10: snapping | Implemented | Threshold is ten rendered pixels mapped to source time. Shift bypasses snapping; text entry is independent. Code inspected; a dedicated automated snap-target test remains a verification gap. Timeline zoom is Phase 2. |
+| 61: export wording | Implemented | Output name, selection duration, dimensions, audio and separate subtitle delivery are shown. Processing completion no longer implies a video exists after caption-only work. |
+| 66–68: cancellation, stale jobs, progress | Implemented for existing long operations | Export/scan/transcription cancellation and retained edits passed. Encoding reports measured progress; setup/transcription/validation remain indeterminate with stage/elapsed time. No ETA is fabricated. Waveform creation does not exist yet. |
+| 69–70: failure and valid output | Implemented | FFmpeg exit codes, empty output, tracks, dimensions, duration and browser decodability are checked. Corrupt worker completion is rejected; retry and prior file retention passed. Failure messages retain useful detail and recovery actions. |
+| 71: autosave | Implemented | Draft before export, revisions, reload, real IndexedDB put quota failure and saving retry passed. Changes waiting to save, saving, saved and failed states are distinct. Browser storage remains best-effort. |
+| 75: legacy records | Implemented | Transactional IndexedDB v1→v2 migration passed with seven legacy records. Source-relative conversion and export-only limitations are verified. Creation dates and retained media are preserved. |
+| 76, 78–79: critical storage | Implemented | No automatic eviction; metadata-only listing; asset reads on reopen; unchanged media not rewritten per keystroke; atomic saving; quota safety; deletion of another project while keeping the active project passed. |
+| 77: storage information/cleanup | Partially implemented | Site usage/quota estimate and per-project deletion are available. Per-asset categories and model/cache-only cleanup are deferred to Phase 3. |
+| 81–84: critical compatibility/resources | Implemented foundations | Actual container/tracks/duration/dimensions are probed. Conversion verifies utilized tracks and falls back to FFmpeg. Decoded frames, input readers, workers, object URLs, scene listeners/timers and temporary files have cleanup paths. Detailed memory profiling remains unverified. |
+
+No implementation item above is blocked. Verification on unavailable browsers/devices remains open.
+
+## Timing and persistence contract
+
+All timestamps use seconds. Source selections are start-inclusive and end-exclusive: [in, out). Source timestamps are never rewritten by a trim.
+
+For a single range, output/sequence time is source time minus the in point. A cue intersects the range first; its intersected boundaries then map to output time. Subtitle delivery uses millisecond timestamps; intersections that collapse at that precision are omitted with a visible explanation, while the source cues remain saved. Cues entirely outside the selection are omitted from its subtitle deliverable, while the editable source cue remains untouched. An ordered-range mapping helper supports future joins, but the UI and renderer currently export one source range.
+
+The out inspector retrieves the decoded frame immediately before the excluded boundary. Seeking/transport UI smoothness is not used as a substitute for decoded frame timestamps.
+
+Edit decisions, playback position, source metadata and export artifacts are distinct. Every successful output retains its producing revision, range, caption snapshot and settings. Undo/redo always increments the current revision, so an older artifact remains identifiable even if decisions return to an earlier shape.
+
+IndexedDB version 2 has metadata and asset stores. Migration transfers v1 records in one upgrade transaction before dropping the old store; an aborted upgrade rolls back. Legacy output-relative cues and markers are normalized only when original media is available. An export-only project uses that saved export as its editable source and explicitly states the original is unavailable.
+
+Autosave is debounced by 600 ms, queued, and also attempted when the tab becomes hidden or the workspace exits. Switching to the project list awaits saving; a failed save keeps the editor open. A newer stored revision cannot be overwritten by an older queued save. This does not provide full conflict resolution for editing the same project concurrently in multiple tabs.
+
+## Completed verification
+
+- npm test: nine regression tests.
+- npm run lint: passes without errors.
+- npm run build: production static export and TypeScript checks pass. Next.js still reports the existing multiple-lockfile workspace-root warning.
+- Edge production browser suite: real fixtures and exported files, not simulated captions or waveform data.
+- Both native WebCodecs and single-thread FFmpeg were exercised. The native test explicitly blocked FFmpeg assets.
+- Known color boundaries: exported first frame is green and last frame is blue, excluding the yellow frame at the out point.
+- Fractional 30000/1001, actual VFR, portrait, single-frame and synthetic hour-long sources passed inspection and playable output checks.
+- Silent audio, absent audio tracks, malformed timecodes, controlled caption typing, undo/redo, reload, cancellation, corruption, quota failure/retry and legacy migration passed.
+- Desktop 1366×900 and mobile 390×844 layouts were captured; no horizontal overflow or uncaught browser errors were observed.
+- Real English transcription was verified using a locally synthesized speech recording. The first model download produced the expected sentence before a video export. A fresh transcription worker reused cached model assets while Hugging Face network access was blocked; undo restored the corrected name.
+- Model-download failure and cancellation keep the previous edited transcript.
+- HDR verification uses a synthetic metadata-tagged fixture to check the guard, not a claim of HDR rendering support.
+
+The worker build uses Next.js Webpack. Inspection and browser tests found that the default bundler emitted workers as raw TypeScript assets; those workers could not execute. Tailwind configuration also now resolves relative to its own file so launching from a different directory cannot silently remove the styles.
+
+## Deferred work
+
+The core Phase 2 editing workflows are now implemented; see [Phase 2](phase-2.md) for current verification and the remaining analysis, language and accessibility backlog. The table below records the original phase allocation.
+
+| Phase | Remaining work |
+| --- | --- |
+| Phase 2: 11–20, 22–25, 31–40, 86–95 | Thumbnail/waveform generation, timeline zoom/navigation, scrubbing improvements, loop/speed/contextual review, richer shortcuts, cue highlighting/search/split/merge/group shift, readability warnings, accurate cache status/download-size UI, scene analysis records/refinement/sensitivity, named editorial markers, adaptive workspace and broader accessibility/touch work. Native playback, frame controls, focus-safe shortcuts, controlled captions and reduced motion already have foundations. |
+| Phase 3: 26–30, 62–65, 72–74, 77, 80 | Actual caption burn-in and matching style/layout, subtitle import, export quality/presets, project rename/duplication, portable backups/relinking, detailed storage/cache cleanup and durable-storage requests. Current video exports deliver captions as sidecars only. |
+| Phase 4: 41–60 | Multiple kept ranges, ripple/split edits, extraction/batch workflows, reframing/aspect ratios, audio adjustments and shared preview/render effects. |
+| Phase 5: 96–100 and advanced timing | Multiple sources, transcript-driven edits, review suggestions, persistent queues/presets and handoff artifacts. Word emphasis remains deferred until reliable word timing exists. |
+
+## Remaining verification and manual checklist
+
+1. On Firefox, Safari and mobile browsers, import, trim, frame-step, export, cancel, retry and reopen a draft. Record actual codec limits and fallback behavior; do not infer support from API existence.
+2. Check frame-snapping target feedback at different rendered widths and confirm Shift bypass and typed values.
+3. Exercise an actual phone rotation-metadata file, a real long high-resolution recording, HDR/10-bit footage and memory pressure. Portrait geometry and hour timestamps were tested, but these are not substitutes for those characteristics.
+4. Verify multi-thread FFmpeg under the deployed cross-origin-isolated hosting headers; the available tests used the compatible single-thread path.
+5. Use a screen reader, touch input and increased text scaling for import, transport, trim fields, caption correction, dialogs and saving errors.
+6. Profile repeated successful imports/exports/cancels/reopenings for retained resources. Cleanup paths and absence of uncaught errors were inspected/tested; no heap plateau claim is made.
+7. Test real near-quota storage and upgrade interruption on browser/device implementations. A real IndexedDB put failure was injected; physically filling the browser quota was not performed.
+8. Verify unusual codecs/containers, audio/video timestamp offsets, damaged files and full end-to-end playback on additional devices.
+9. Before later phases ship, add SRT/VTT import round trips, preview/burn-in comparison, backup/relinking, actual multi-range joins and rendering parity tests. Those flows are currently deferred.
+
+## Running the browser checks
+
+Install or provide Playwright and Edge, and put FFmpeg/ffprobe on PATH. Serve frontend/out with a local static server, then run frontend/tests/browser.mjs with CUTMARK_TEST_URL pointing to it. CUTMARK_PLAYWRIGHT_PATH can point to an installed Playwright package; CUTMARK_ARTIFACTS selects the fixture/output/screenshot directory.
+
+The optional tests/speech.mjs check additionally needs CUTMARK_SPEECH_FIXTURE pointing to a local English-speech MP4 and network access for the first public model download. The verification fixture was generated locally with Windows speech synthesis; no user media or transcript was uploaded.
diff --git a/docs/phase-2.md b/docs/phase-2.md
new file mode 100644
index 0000000..cbdea65
--- /dev/null
+++ b/docs/phase-2.md
@@ -0,0 +1,62 @@
+# Phase 2 — visual editing and transcript workflow
+
+Historical phase checkpoint: the current implementation and verification inventory are tracked in [the complete checklist](backlog.md), [Phase 4](phase-4.md) and [Phase 5](phase-5.md). Portable versions 1–3 and database version 7 supersede the earlier format/storage versions described below.
+
+Implemented locally on October 14, 2026. This delivers the core daily-editing portion of the Phase 2 backlog. It preserves the source-based project and validated, revision-aware export contracts from Phase 1. Scene analysis/review and editorial markers are now implemented as a second Phase 2 increment. Remaining language, device verification and workspace customization work is explicitly deferred below.
+
+## Delivered and verified
+
+“Verified” means the production static build in Windows Edge, with real decoded media and native playback. It does not imply validation on every browser or device.
+
+| Backlog items | Status | Evidence and limits |
+| --- | --- | --- |
+| 10: predictable snapping | Implemented, verified | Ten visible pixels map to the current viewport span. A highlighted target and boundary label appear during drag. Browser checks cover target feedback, Shift bypass, typed values, and one undo entry per drag. Unit checks cover different zoom spans and long-source contexts. |
+| 11: footage thumbnails | Implemented, verified | A worker decodes actual source frames at visible slot times, prioritizing the center and active boundary. Frames arrive progressively with their decoded timestamps. Aspect ratio is preserved, 64 cached images are bounded and evicted URLs are revoked. Real green/blue fixture frames match their source timestamps. |
+| 12: waveform | Implemented, verified | Streamed decoded audio becomes bounded source-aligned peak bins and a multiresolution pyramid. The rendering query uses only blocks contained in the requested pixel interval, preventing nearby transients from filling pauses. Real AAC peaks and rendered pixels distinguish known signal/silence on a ten-minute fixture. Silent audio and absent tracks have separate messages. |
+| 13–15: timeline interaction | Implemented, verified | Zoom around the playhead, fit source/selection, horizontal viewport navigation, source overview, optional playback follow, accessible draggable playhead, generous trim targets and boundary thumbnails. Rapid drags coalesce native seeks; the final media time is checked. Fit/navigation work on ten-minute media. Full-source navigation hides when it is unnecessary. |
+| 16–17: transport/context | Implemented, verified for normal playback | Play/pause, decoded frame steps, included out-frame inspection, selection loop, preview speed/volume and configurable before/after cut review with replay. Context is explicitly labeled as including footage outside output. Native media rate/volume and multiple selection loops are checked. Fullscreen/PiP use native browser APIs; real window modes remain manual verification. |
+| 18–20: keyboard and frame synchronization | Implemented foundations, regression verified | Existing Space, I/O, frame arrows, larger-step modifier and named undo/redo remain scoped to the workspace. Typing, composition, dialogs and browser modifier combinations are respected. Native frame callbacks update the playhead where available. Predictable reverse J/K/L shuttle is deferred. |
+| 21–24: transcription and transcript editing | Implemented, verified | Transcribe the selection or full source before export. Source-timestamp cues highlight during playback; cue/search actions seek to the source. Controlled text/timing, add at playhead, split timing at playhead and wording at the actual caret, adjacent merge, delete, signed group shift and literal replace preview are reversible. Actual Unicode/multiline edits, operations, save/reopen and selected SRT timing pass. Split does not claim word-level timing. |
+| 22: cue following | Implemented, verified | Optional following scrolls only the transcript container. A 180-cue source-timed transcript on actual ten-minute media verifies active highlighting, container-only scrolling, manual wheel browsing pausing follow, Resume, and search seeking. Caption text was seeded as manual fixture annotations; this is not a claim of recognizing ten minutes of speech. Real touch and screen-reader checks remain open. |
+| 25: timing/readability | Implemented, verified | Invalid millisecond intervals, selection intersections, overlap, line length/line count and reading speed are flagged. Guidance is configurable and saved. Notes can acknowledge intentional guidance exceptions, while invalid intervals cannot be acknowledged. Exceptions are tied to reviewed timing/text/range/guidance, so a changed context requires review again. Wording is preserved. Delivery actions show the flag count. |
+| 31: first model run | Partly implemented, verified | Purpose, local processing and English coverage are explained before starting. The UI inspects actual browser-cache requests to distinguish missing/partial/cached model weights. Download asset progress and transcription stages are distinct. First download, cached network-blocked retries and cache messaging pass. A reliable approximate total download-size display is deferred; no total is invented. |
+| 33–35: recognition outcomes | Implemented, verified | Existing deliberate repetition preservation and independent cancellation/retry remain. Silence/no speech are normal statuses that preserve corrected cues, distinct from technical failure. Absent audio disables transcription. |
+| 36–39: scene workflow | Implemented, verified | One worker-backed detector serves the editor and compatibility entry points. Source/selection scope, quick/refined mode, fewer/balanced/more sensitivity and recorded coverage/settings are saved. Refined hard-cut timestamps match real transition frames with before/at thumbnails. Confirm, move, dismiss, add and select-scene operations are undoable. Rescans preserve manual/confirmed/dismissed corrections by default; explicit replacement is scoped and confirmed. Partial scans preserve unchecked cuts. Cancellation, failed worker setup, retry and reopening pass. Dissolve, motion and flash footage is tested; refinement searches candidates, not every source frame, and can still miss cuts or flag non-cuts. |
+| 40: editorial markers | Implemented, verified | Source-time names, optional color/notes, name/note search, time editing, timeline/keyboard-accessible seeking and removal with undo. Notes and colors survive rescans and reopening. These annotations are separate from detected cuts and do not become burned-in video text or exported chapters. |
+| 66, 82–84: analysis lifecycle | Implemented foundations, verified | Waveform and thumbnail work run separately from export/transcription. Their availability never blocks basic editing. Cancelling waveform terminates its worker; stale setup cannot update the UI. Independent retry and source replacement pass. Media readers, frames, workers and URLs have cleanup paths; heap profiling remains open. |
+| 86–89: adaptive workspace | Implemented core, verified | A compact source preview with transport/timeline and a desktop caption/details inspector. Mobile Trim/Captions/Details buttons expose relevant panels while preserving drafts. Secondary scene/export/storage controls are disclosures; export actions stay near the work area. Desktop/mobile screenshots, 390px viewport, larger text and reduced motion checks pass without horizontal overflow. Persistent panel dimensions and broader customization are deferred. |
+| 90–95: accessibility/touch/privacy | Partly implemented | Native labeled inputs/buttons, keyboard sliders, focus styles, normal text entry, reduced motion and a narrower-screen tool switcher are available. Decode/model limitations and local-media behavior are explicit. Real touch manipulation and a full screen-reader/contrast audit remain manual work; language promises remain English only. |
+
+No core implementation item above is blocked. Advanced work is deferred by phase; unavailable device/browser coverage is a verification gap.
+
+## Technical contracts
+
+- Timeline, waveform, caption editor and source transport use source seconds. Trim is start-inclusive and end-exclusive. Selected subtitles map through the shared source-to-output range conversion.
+- Thumbnails use decoded presentation timestamps, not labels fabricated from slot centers. Frame stepping/out inspection still uses decoded frame timestamps.
+- Waveform peaks are amplitude envelopes, normalized to the source maximum for visual readability; they are not calibrated loudness meters. Base bins are approximately 5 ms until the 262,144-bin cap requires coarser aggregation on longer media. Packet memory is bounded independently.
+- Timeline seeks retain the latest request while the native element is already seeking. Switching media cancels pending seeks and analysis. Preview speed/volume/context/follow controls do not alter export decisions.
+- Caption edits, review notes and readability guidance are saved in project metadata. Existing projects without guidance use sensible defaults. Undo history remains session-local. An operation is one named edit; text typing remains coalesced.
+- Scene scans sample at most 480 positions, including the last included source frame. The record identifies source, requested area, settings, detector version, time, planned/checked samples, spacing, actual partial coverage and refinement count. Quick/refined time budgets are 30/120 seconds, with a 150-second worker-response limit. Completing sampling does not imply every intervening frame was checked; refinement completion/limits remain separately visible.
+- Unreviewed scene candidates are refreshed only in the checked area. Manual/confirmed cuts and dismissed brackets survive ordinary rescans, while outside cuts always remain. Explicit replacement clears reviewed cuts and wholly covered dismissals in the checked area. Moved detected cuts retain a dismissal of their original bracket. These decisions are named undo actions and stored without rewriting media assets.
+- Editorial markers are independent source annotations. Their text, colors and positions persist through trim/export/rescans, and never alter output pixels.
+- At the completion of this phase, caption delivery remained separate SRT/VTT files. Styling and actual burn-in are now implemented in the [Phase 3 caption-delivery step](phase-3.md).
+
+## Verification
+
+- Twenty unit regressions pass, covering timing, mappings, revisions, migration, zoom, pixel snapping, waveform intervals, caption operations and reviewed exceptions.
+- Lint, TypeScript and production static build pass. The existing multiple-lockfile workspace-root warning remains.
+- The Phase 1 browser suite passes: actual native/FFmpeg exports, first/last boundary frames, fractional/VFR/portrait/single-frame/hour-long fixtures, previous output retention, cancellation, corruption/retry, quota safety, seven-record migration, cleanup and HDR guard.
+- The Phase 2 browser suite passes: real decoded thumbnails, latest seek, snap target/bypass, native loop/rate/volume, contextual replay, transcript operations, persisted guidance/review notes, subtitle alignment, mobile/larger text/reduced motion, ten-minute AAC pause alignment, waveform cancellation/retry and no uncaught browser errors.
+- The scene-tools suite passes: decoded quick/refined boundary comparisons, sensitivity/scope records, cut confirmation/movement/dismissal, explicit scoped replacement, partial coverage, cancel/failure/retry, scene selection, searchable source markers with Unicode notes/colors, reopening, mixed dissolve/motion/flash footage and the 180-cue follow/browse workflow. The partial-scan test advances the actual worker clock after decoded samples to exercise its real time-limit branch.
+- The real speech suite passes: initial model download, transcription before encode, cached retry with model network blocked, undo preserving a name correction and full-source cue timestamps while a shorter trim remains selected.
+- The long recording is a synthetic ten-minute timing/pause fixture, not a claim of testing every characteristic of a real high-resolution talking-head recording.
+
+Run npm test, npm run lint and npm run build from frontend. Serve frontend/out and run tests/browser.mjs, tests/phase2.mjs, tests/scenes.mjs and tests/speech.mjs with CUTMARK_TEST_URL and CUTMARK_PLAYWRIGHT_PATH configured. The Phase 2 suite needs CUTMARK_ARTIFACTS pointing to the Phase 1 fixture directory; it creates a phase-2 subdirectory. The speech suite also needs CUTMARK_SPEECH_FIXTURE pointing to local English speech.
+
+## Next backlog and manual checks
+
+1. Scene records, sensitivity/refinement, candidate movement/confirmation, editorial markers and the multi-cue follow/browse acceptance session are implemented and verified. Further detector accuracy/performance tuning requires representative high-resolution real recordings; the current heuristics remain reviewable candidates.
+2. Verify fullscreen/PiP, touch dragging, phone rotation metadata, low-powered/high-resolution media, screen readers, text contrast and Firefox/Safari behavior. Profile repeated import/analysis/export cycles for a stable heap.
+3. Add other transcription languages/quality choices only after demonstrating supported models and acceptable performance; add a measured approximate model-size explanation.
+4. The [Phase 3 caption-delivery step](phase-3.md) completes subtitle import, shared preview/export styling and actual burn-in. Export presets and output controls are now verified in [Phase 3B](phase-3-export.md). [Phase 3C](phase-3-recovery.md) now completes names/duplication, portable recovery and targeted storage management. Continue with Phase 4 sequence and repurposing work.
+5. Keep multi-range joins, reframing, audio/effects and later multi-source/review/queue capabilities in their later phases, with rendering parity and preservation tests.
diff --git a/docs/phase-3-export.md b/docs/phase-3-export.md
new file mode 100644
index 0000000..4a5b0ea
--- /dev/null
+++ b/docs/phase-3-export.md
@@ -0,0 +1,59 @@
+# Phase 3B — export settings and inspection
+
+Historical phase checkpoint: the current implementation and verification inventory are tracked in [the complete checklist](backlog.md), [Phase 4](phase-4.md) and [Phase 5](phase-5.md). Portable versions 1–3 and database version 7 supersede the earlier format/storage versions described below.
+
+Implemented locally on October 14, 2026. Caption delivery was completed in [Phase 3A](phase-3.md). This step implements actual export resolution/quality/audio settings, useful presets and persistent measured output inspection. [Portable recovery, names/duplication and cache management are now completed in Phase 3C](phase-3-recovery.md). No hosting changes are included.
+
+## Editor-visible changes
+
+- Export settings are disclosed within Export and storage details. Match source, Smaller file and High quality presets expose their resulting settings rather than hiding them.
+- Choose source dimensions or an upper 1080p/720p/480p limit. Resolution is bounded by the longest edge for landscape or portrait; footage is never enlarged, reframed or cropped. Encoding-size rounding can introduce a slim letterbox border.
+- Choose Smaller file, Balanced or High quality compression. Choose whether source audio is included. Preview volume still belongs to source review, while the output summary explicitly identifies absent audio.
+- Frame timing remains source-based, including variable rates. Codec/resolution/framing controls that have no implemented renderer are not offered. Vertical reframing belongs to Phase 4. SRT/VTT downloads remain available without video encoding.
+- Export captures the settings and project revision. Settings and presets are saved editing decisions with named undo/redo. Existing projects receive Match source defaults.
+- Before encoding, the summary names dimensions, duration, source timing, audio and caption delivery. Afterwards, measured dimensions/tracks/codec/duration/file size appear alongside the captured quality intent. Measured metadata survives reopening; legacy files without stored measurements retain their recorded settings.
+- The source remains available after export. Cancellation, failed validation and quota errors preserve the prior successful MP4.
+- File selection is available after the client import handler is ready, preventing an initial source-selection race.
+
+## Checklist
+
+| Backlog items | Status | Verification / limits |
+| --- | --- | --- |
+| 62: export settings | Implemented for current single-range capabilities | Resolution, quality, audio inclusion and caption delivery affect actual MP4 output through both processors. Original/VFR timestamp behavior remains fixed rather than offering unverified frame-rate conversion. |
+| 63: output presets | Implemented for supported delivery | Match source, Smaller file and High quality set inspectable controls. Caption-only SRT/VTT downloads already work without encoding. Vertical short/framing presets remain deferred until actual reframing is implemented. |
+| 64: consistent engine intent | Implemented | Shared output dimensions, audio and quality policy feed native conversion and FFmpeg. Bitrate/quantizer and CRF express matching quality intent, not identical algorithms or file sizes. Compatible-source caption preparation uses high intermediate quality, followed by the requested final policy and the shared caption renderer. |
+| 65: summary and output inspection | Implemented | Actual dimensions/tracks/duration/playability must match the request before success. Measured metadata, file size, codec and prior-version settings persist. No speculative size estimates are presented. |
+| 72–74 and expanded 77/80 | Completed in [Phase 3C](phase-3-recovery.md) | Names/duplication, portable backup/relinking, targeted model cleanup and explained retention requests are implemented and verified. Existing autosave, source download, individual project deletion and quota recovery remain working. |
+
+## Output contract
+
+ExportPreferences are optional version-compatible edit decisions. The resolved OutputSpec contains the requested canvas size, audio presence and encoder policies. Lower-resolution dimensions preserve aspect ratio to even-pixel rounding; both paths contain the source within those dimensions. Source dimensions are retained exactly when no downscale is necessary.
+
+A full-length MP4 with Match source, Balanced compression, unchanged audio and sidecar captions can reuse its original bytes. Trims, High quality/Smaller file, actual resizing, removal of an existing audio track or burned-in captions require encoding. Selecting a ceiling above a small source does not force enlargement.
+
+Native conversion applies target dimensions before captions. Caption preview uses the same target-sized layout and canvas; the source preview remains the original footage. The caption renderer returns an explicitly timestamped RGBA VideoFrame. Testing found that canvas-backed VideoFrames could displace glyphs by one pixel at 854px width; supplying explicit pixels eliminates that displacement without compensating caption positions. Returned frames are closed by the conversion implementation; each worker is terminated on completion/cancellation. Pixel readback adds per-frame work, so large-media performance remains an explicit verification gap.
+
+FFmpeg uses an aspect-preserving scale/pad when resizing, passes through original timestamps and applies the chosen H.264 CRF/AAC policy. For burned-in delivery, it prepares the selected source, then the shared browser renderer applies the final caption layout/quality; copied prepared audio avoids a second AAC encode. Omitted audio is never decoded unnecessarily by the native path and is absent from both exports.
+
+Validation compares playable output metadata with the resolved request, not with unchanged source dimensions/audio. HDR/wide-color re-encoding guards include every setting that requires an encode; Match source on the unchanged full range remains the preservation path.
+
+## Verification
+
+Windows Edge is the available browser target.
+
+- 29 unit regressions pass, including landscape/portrait resolution ceilings, no enlargement, intentional audio omission, reversible settings and immutable output snapshots.
+- Lint, TypeScript and production static build pass. The existing multiple-lockfile workspace-root warning remains.
+- The export-settings browser suite checks actual MP4s from native and compatible processors: High versus Smaller compression, original 24fps timing, audio retention, reduced-resolution audio omission, target-sized Unicode captions, presets/undo/reopen, measured metadata persistence, mobile overflow, and reduced portrait multiline captions.
+- On the tagged BT.709 1280×720 fixture, native Smaller/High files measured approximately 0.55/1.37 MB and 38.94/53.10 dB PSNR against the same source frame. Compatible Smaller/High measured 0.79/1.48 MB and 39.79/50.28 dB. These are observations for this fixture, not promised compression ratios or a quality claim about every recording.
+- Reduced landscape output is 854×480 with no audio track; reduced portrait output is 480×854. Caption comparisons use exact-position ink agreement, without accepting a coordinate shift.
+- The existing export-safety suite passes: precise first/last boundaries, actual audio, retained source/corrections, cancellation, quota failure/retry, corruption/retry, migration, blank captions, fractional/VFR/portrait/single-frame/hour-long media, and guarded HDR.
+- Caption-delivery regressions cover subtitle import, saved styles, font/overflow failure, cancel/retry, sidecar-only video, safe areas, native accessibility caption track, compatible captions/audio and tiny portrait frames.
+
+Run npm test, npm run lint and npm run build from frontend. Serve frontend/out and run tests/export-settings.mjs using CUTMARK_TEST_URL, CUTMARK_PLAYWRIGHT_PATH and CUTMARK_ARTIFACTS as described in README. FFmpeg/ffprobe and Edge are required; artifacts are written under export-settings.
+
+## Remaining work
+
+1. Phase 3 is completed by [portable recovery/storage](phase-3-recovery.md). Continue to Phase 4 multi-range sequences and repurposing.
+2. Check real high-resolution/long recordings, rotation metadata, low-powered devices and pixel-readback performance. Untagged source colors can be interpreted differently by decoders; the quantitative fixture uses explicit BT.709 metadata. Broader SDR color preservation remains a manual check.
+3. Verify Firefox/Safari, screen readers, touch devices and fullscreen/PiP behavior. No universal codec or browser support claim is made.
+4. Keep crop/reframing, multi-range joins, richer audio controls and vertical-format presets in Phase 4.
diff --git a/docs/phase-3-recovery.md b/docs/phase-3-recovery.md
new file mode 100644
index 0000000..e8df5bf
--- /dev/null
+++ b/docs/phase-3-recovery.md
@@ -0,0 +1,72 @@
+# Phase 3C — portable recovery and storage
+
+Historical phase checkpoint: the current implementation and verification inventory are tracked in [the complete checklist](backlog.md), [Phase 4](phase-4.md) and [Phase 5](phase-5.md). Portable versions 1–3 and database version 7 supersede the earlier format/storage versions described below.
+
+Implemented locally on October 14, 2026. Together with [caption delivery](phase-3.md) and [export settings](phase-3-export.md), this completes Phase 3 for the supported single-source, single-range Windows Edge workflows. No hosting, accounts or cloud processing are introduced.
+
+## Editor-visible result
+
+- Rename a project independently of its source filename. Names persist and participate in named undo/redo. Export filenames capture the title at rendering time; renaming does not relabel an earlier output.
+- Duplicate the current project into an independently editable copy. Creation time is new for the duplicate and preserved through later exports. Source media stays shared, and an inherited export remains shared until replaced.
+- Download a lightweight .cutmark.json project file or a .cutmark bundle including the complete source. Both capture current trim, corrected captions, style/delivery, readability guidance/review notes, scene cuts/analysis/settings/dismissals, editorial notes and export preferences.
+- Restore into a separate project after reviewing its title, source and cue/marker counts. Lightweight files require matching media; bundles include it. A differently named exact source works. A different video with the same filename fails.
+- Cancellation, malformed files, unsupported versions and quota failure preserve the current project and available MP4. Import transactions roll back metadata and media together; recovery can be retried.
+- Inspect saved-media references, estimated site usage/quota and the English model cache. Shared media is counted once within each category; older unmeasured records and unavailable cache sizes are identified.
+- Remove only the cached English Whisper model files, preserving other models/caches, projects, captions and source/output media. The next transcription downloads missing model files again.
+- Request browser storage retention only after an explanation. A grant reduces automatic eviction; it does not replace downloaded backups or protect against clearing browser data.
+
+## Checklist
+
+| Backlog items | Status | Verification / limits |
+| --- | --- | --- |
+| 72: names and duplication | Implemented | Rename/undo, saved titles, source filename preservation, immutable output filenames, creation times and independent duplicate edits pass. Each project retains its latest successful output; duplicate creates an independently revisable variant. |
+| 73: portable project format | Implemented | Versioned lightweight JSON and source-included binary bundles are downloaded and restored in fresh browser contexts. Previous rendered MP4s, session undo, models and derived preview data are deliberately excluded and explained before download/recovery. |
+| 74: media relinking | Implemented | Complete-content fingerprint, byte size, duration, dimensions, codec/track presence and HDR metadata checked. Filename is advisory. Same-name changed content fails; renamed identical media passes. Converted media is not accepted as an exact replacement. |
+| 75: legacy preservation | Implemented | Version-1 recent records and version-2 combined assets remain readable. Original-source versus export-only provenance stays explicit in portable files. No original source is inferred from a saved export. |
+| 76: visible retention policy | Implemented | Projects remain until explicit deletion. Latest output replaces the prior stored output only after successful rendering/validation; shared duplicate outputs remain while referenced. No silent project eviction or pin exception is needed because all projects follow the same retention policy. |
+| 77: information and targeted cleanup | Implemented for current caches | Site estimate, measured media references and cache file counts/reported lengths available. Scoped English-model cleanup and individual project deletion pass. Preview thumbnails/waveforms are memory-only and released on source changes. No erase-everything action is offered. |
+| 78: metadata and media separation/reuse | Implemented | Listings use metadata. Duplicates share source/export references; parent deletion preserves media needed by a duplicate. A new export stores only that new output, keeping its source shared. Unreferenced asset keys are collected after export/deletion. |
+| 79: quota safety | Implemented | Open work/downloads retained; portable downloads require no IndexedDB save. Failed recovery leaves no partial project and allows retry. Existing save-retry and source/output downloads remain. |
+| 80: durable storage | Implemented | Explained user-triggered request with grant, denial and unsupported/error handling. Actual grant policy remains browser-controlled. Local file handles are not required; ordinary downloads and IndexedDB remain the portable fallback. |
+
+## Portable format v1
+
+The lightweight file is UTF-8 JSON with format cutmark-project, version 1, title, creation/edit times, a source reference and current edit decisions. The source reference records original filename/type, byte size, metadata, provenance and a content fingerprint. Unknown format versions, editing features and unsupported range counts fail rather than being silently discarded. This version supports one source range; Phase 4 must extend the format when sequence editing is added.
+
+The bundle is a Blob concatenation, not a ZIP or base64 document:
+
+1. Eight ASCII bytes CMARK001.
+2. Four-byte little-endian unsigned JSON-header length.
+3. That many bytes of the same UTF-8 project JSON.
+4. The complete source bytes.
+
+Metadata is limited to 16 MiB and collections to 50,000 entries, with bounded nesting and validated timing, identifiers, styles, notes and settings. A source-length mismatch, incomplete header or invalid UTF-8/JSON is rejected. A rendered output is not included as an additional artifact. For an export-only legacy project, the retained export is the source itself and its limitation is recorded.
+
+Fingerprint algorithm sha256-chunks-4m-v1 hashes each consecutive 4 MiB source chunk with SHA-256, turns those digests into lowercase hexadecimal, then hashes UTF-8 text cutmark-source-v1:Runs locally in your browser.
diff --git a/frontend/app/privacy/page.tsx b/frontend/app/privacy/page.tsx index 3f34682..4f3f525 100644 --- a/frontend/app/privacy/page.tsx +++ b/frontend/app/privacy/page.tsx @@ -13,7 +13,7 @@ export default function PrivacyPage() {Video editing, trimming, scene analysis, and speech recognition run in your browser on your device. Cutmark does not send your source video, exported video, audio, or transcript to its application servers as part of the editor workflow. Speech recognition uses a model that may be downloaded from Hugging Face the first time you use that feature; the model download does not include your video or audio.
-To show recent projects and let you reopen them, Cutmark saves up to five projects in this browser’s local IndexedDB storage. A saved project can include the source clip, exported clip, file name, trim range, scene markers, caption text, and processing status. This data stays in the browser profile on this device. Use the delete control beside a recent project to remove it, or clear this site’s browser storage to remove all saved projects. Browser storage can be cleared or evicted by the browser at any time.
+To show recent projects and let you reopen them, Cutmark autosaves unfinished projects and retains saved projects in this browser’s local IndexedDB storage until you delete them. Cutmark does not automatically delete older projects when saving a new one. A saved project can include source videos, local image assets, exported clips, file names, ranges, captions, markers/notes, framing/audio/layer settings, and processing status. This data stays in the browser profile on this device. Use the delete control beside a recent project to remove it, or clear this site’s browser storage to remove all saved projects. Browser storage can be cleared or evicted by the browser at any time.
Framing changes the output canvas. Fill crops the image; Fit preserves it with a solid background. Positive gain may clip. Listening volume is separate; render a preview to hear exported gain and fades across the whole sequence.
+ + + {audio.gainDb>0&&!audio.mute&&Gain above 0 dB may exceed the signal ceiling. Inspect the rendered preview before delivery.
} +Missing media. Relink the matching source before rendering.
; +} +export default function AssemblyPanel({assembly,media,primaryAssetId,guidance,saveStatus,onGuidance,onPrimaryCaptions,onRelinkImage,disabled,onPrimary,onImport,onRelink,onChange,onPreview}:{assembly?:Assembly;media:RecordAssemble up to four local sources with hard cuts. Each range references its original source. All sources share the primary canvas, caption style, quality and final audio adjustments. Primary sources follow later corrections unless you turn off the link. Assembly audio is stereo. Sources without audio contribute silence when another source supplies audio. Preparing several sources increases memory use in the compatible processor.
+ + {assembly&&<>{assembly.enabled?"The primary timeline remains a source editing view; the export action now renders this assembly.":"The export action uses primary kept ranges. Assembly sources and decisions remain saved."} · Assembly duration {formatTime(sequenceDuration(assembly.ranges))}
+{source.reference.fileName} · {source.reference.metadata.width} × {source.reference.metadata.height} · {formatTime(source.reference.metadata.duration)} · {source.reference.metadata.hasAudio?"audio":"no audio"}
+Source review uses native caption appearance. Render the assembly to inspect the output styling and audio adjustments. {source.captions.length} source cues. {source.primary?"Primary corrections remain linked to the main caption editor.":"This source has independent caption corrections."}
Range {index+1} · {source.reference.fileName} · {formatTime(range.end-range.start)}
This measures the primary source preview. It is a sample-peak listening meter, not a true-peak or loudness-standard measurement. Preview volume affects listening; exported gain is adjusted separately.
{enabled&&{peak>0?(20*Math.log10(peak)).toFixed(1)+" dBFS":"Silent / paused"}{peak>=1?" · Signal at or above clipping ceiling":""}
{message}
}{props.delivery==="sidecar"?"Styling is a preview; exported video has no added caption pixels. Subtitle files retain words and timings.":"The MP4 will include these captions permanently. Browser video encoding is required; incompatible sources are prepared locally first."}
+ +Native preview and picture in picture use the source caption track; they do not show the chosen video style.
+ + + + +Size scales with the frame’s shorter edge. Long words wrap; text is never removed to fit.
+ {(["color","outlineColor","backgroundColor"] as const).map(field=>)} + + + + + + + + Font license +Analyze the primary source and review low-amplitude intervals before removing anything. Quiet words, breaths and deliberate pauses may be flagged. Padding keeps material on both sides. Level feedback uses decoded sample peaks; it is not a true-peak or loudness-standard measurement.
+{message}
} + {data&&Decoded source sample peak: {data.maximum? (20*Math.log10(data.maximum)).toFixed(1)+" dBFS":"silent"}. After {gainDb} dB gain: {data.maximum?(20*Math.log10(data.maximum)+gainDb).toFixed(1)+" dBFS":"silent"}.{data.maximum*10**(gainDb/20)>1&& Signal may clip; reduce exported gain.}
} +{suggestions.length} candidates · sample bins about {Math.round(data.binSeconds*1000)} ms
} +Showing the first 200 candidates; adjust the threshold or minimum pause to narrow the list.
} +Add the selected range as a named deliverable. Each clip captures its framing and export settings. Captions and audio changes are captured when the queue starts. Jobs run one at a time; a failed job leaves other results available. Downloads remain here while this project is open; clip definitions save with the project.
+{formatTime(clip.range.end-clip.range.start)} · {clip.framing.ratio} · {clip.preferences.resolution} resolution · {clip.preferences.quality} · {clip.preferences.audio==="keep"?"keep audio":"no audio"}
+ + {output&&{output.status} · revision {output.revision} · {output.message}
}{output?.url&&{activeItem ? `${activeItem.label} in progress` : doneCount === items.length ? "Processing complete" : hasFailed ? "Processing finished with an unavailable step" : "Processing steps"}
-{activeItem ? messages[activeItem.key] ?? "Working on this step… Progress updates as the work completes." : doneCount === items.length ? "Your export is ready." : "Steps update as each part of your video finishes."}
+{activeItem ? messages[activeItem.key] ?? "Working on this step… Progress updates as the work completes." : doneCount === items.length ? completionCopy : "Steps update as each part of your video finishes."}
{file ? file.name : "New project"}
{file ? "Source clip" : "Import a video to begin"}
{file ? edits.projectTitle?.trim()||file.name : "New project"}
{file ? displayedSaveStatus : "Import a video to begin"}
{nativeCaptionPreview?"Native source caption preview · render a sequence preview to inspect framing, titles and images":burnCaptions?"Styled preview · captions will be burned into the MP4":"Styled preview · MP4 has no added captions until burned-in delivery is selected"}
} +Focus the workspace: Space plays/pauses; I/O set in/out; arrows step frames; Shift+arrows seek one second; Ctrl/⌘ Z undoes; Ctrl/⌘ Shift Z redoes. Text fields keep normal typing.
{frameMessage}
} +{sequencePreview.revision===revision?"Current":"Earlier"} rendered sequence preview
{sceneScanMessage}
} + {reviewIssues.length > 0 &&{reviewIssues.length} caption timing or readability flags to review in Captions before delivery. Wording is preserved; subtitles use the selected range.
} + {(progress || errorMessage) &&{errorMessage ?? progress}
} + {(status==="PROCESSING"||captionWorking||sceneScanStatus==="working") &&{projectProgress}
} + {historyMessage &&{historyMessage}
} + {shortCaptionIntersections > 0 &&{shortCaptionIntersections} caption intersections are too brief for millisecond subtitle timestamps and are omitted from the selected subtitle file. The source cues remain saved.
} +The source filename stays unchanged. Duplicate creates independent decisions and shares stored source/export media until a new export is made.
+ +Project files require the matching video. Bundles include that source without reading it all into memory. Both preserve editing decisions and exclude previous rendered MP4s; download those separately.
+ {projectWorking&&} +Export: {outputFileName(outputStem,exportPreferences)} · {formatPreviewTime(sequenceLength)} · {spec ? spec.width + " × " + spec.height + " · " + (spec.audio ? "source audio" : "no audio") : "Checking source"} · {outputTitles.length} timed title sections · source frame timing · {burnCaptions?"captions burned into video"+(captionDelivery==="both"?" and delivered as files":""):"captions delivered separately"}.
+Source captures preserve the decoded image. Composed captures include framing and the edited caption layer at that source frame; neither includes safe guides. Reports contain local editorial wording and notes.
{result.revision === revision ? "Latest export" : "Earlier export"} · {result.settings.captions==="sidecar"?"subtitle files":result.settings.captions==="burned"?"burned-in captions":"burned-in captions and files"} · revision {result.revision} · {(result.videoBlob.size / 1024 / 1024).toFixed(2)} MB · {formatPreviewTime(result.duration)} · {result.metadata?result.metadata.width+" × "+result.metadata.height+" · "+(result.metadata.hasAudio?"audio present":"no audio")+" · "+(result.metadata.videoCodec??"video"):(result.settings.width+" × "+result.settings.height)} · {result.settings.preferences?.quality??"legacy quality"}
Projects remain until you delete them. Deleting a project removes only media no longer shared by another project; the current project stays open. Browser storage is not a backup.
+This source has HDR or wide-color metadata. Export the unchanged full source to preserve its color; HDR trimming and re-encoding are currently unavailable.
} + +Finished clips are saved in this browser.
Drafts and exports are saved in this browser. Projects stay until you delete them; browser storage is not a backup.
Your five most recent exports will appear here.
} + :Your saved drafts and exports will appear here.
}