Skip to content

Commit 07640ce

Browse files
committed
docs(captions): fold the two render paths into the one that survived
The caption doc still described a DOM preview painter alongside the native exporter, and linked to `CaptionLayer.tsx`, which no longer exists — the docs check failed on the dead link. Rewritten around what is actually there: one path, cues -> synthetic text regions -> annotation plumbing -> native compositor, which draws preview and export alike. That is a stronger version of the property the old text was reaching for: preview and export cannot drift because they are the same renderer, not two box models kept in sync by hand. Kept a short note on why the DOM layer existed and why it went, so the next reader does not re-add a "preview overlay" to fix a perceived gap. Also recorded that `captionBackgroundCss` emits `rgba(...)`, which is what forces the native colour parser to accept CSS colours rather than hex only. `docs:check` OK (22 files).
1 parent f7d25d3 commit 07640ce

1 file changed

Lines changed: 25 additions & 18 deletions

File tree

technical-documentation/architecture/transcription-and-captions.md

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ flowchart LR
2121
C -- "IPC return" --> B
2222
B --> F["AxcutTranscript<br/>on document.transcripts[]"]
2323
F --> G["deriveCaptionCues<br/>(src/lib/ai-edition/captions/cues.ts)"]
24-
G -- "CaptionCue[]<br/>(virtual ms)" --> H["Preview overlay<br/>(CaptionLayer.tsx)"]
25-
G -- "synthetic text regions<br/>(annotation path)" --> I["Export<br/>(native compositor)"]
24+
G -- "CaptionCue[]<br/>(virtual ms)" --> H["captionCuesToTextRegions<br/>(synthetic text regions)"]
25+
H -- "annotation path<br/>(scene description)" --> I["Native compositor<br/>(preview AND export)"]
2626
```
2727

2828
The renderer pieces — `transcribeMono16kToSegments`
@@ -340,23 +340,30 @@ document — see the next subsection.
340340

341341
### Render paths
342342

343-
The cue list reaches two surfaces, designed to share the same code so
344-
preview and export cannot drift:
345-
346-
- **Preview**[`src/components/ai-edition/CaptionLayer.tsx`](../../src/components/ai-edition/CaptionLayer.tsx)
347-
paints the cue active at the current playhead inside a
348-
pointer-events-none band. The per-line background plate uses
349-
`boxDecorationBreak: clone` so each wrapped line gets its own plate —
350-
the same trick the native export uses, so what the preview shows is
351-
what the export draws. `zIndex: 60` keeps the caption above the
352-
annotation overlay in the preview.
353-
- **Export**`captionCuesToTextRegions`
343+
There is **one** render path. The cue list becomes synthetic text regions
344+
that ride the annotation plumbing into the native compositor, which draws
345+
both the preview and the export — so preview and export cannot drift,
346+
because they are the same renderer rather than two implementations kept in
347+
sync.
348+
349+
> Until 2026-07-28 the preview had a second, DOM-based painter
350+
> (`CaptionLayer.tsx`) that mirrored the exporter's box model. Once the
351+
> native compositor took over the preview it became a duplicate: both
352+
> painted the same cue, and because CSS `word-break` and DirectWrite break
353+
> lines differently, the two copies wrapped at different points and the
354+
> caption visibly doubled. The DOM layer was deleted; the native canvas is
355+
> the sole pixel source (see [preview.md](preview.md)).
356+
357+
- **Preview and export**`captionCuesToTextRegions`
354358
([`src/lib/ai-edition/captions/cues.ts:242`](../../src/lib/ai-edition/captions/cues.ts:242))
355-
converts the virtual-ms cue list into synthetic `AnnotationRegion`s,
356-
using the same `captionBandRect` + `captionBackgroundCss` helpers as
357-
the preview. Those regions ride the existing annotation path through
358-
the scene description and onto the native compositor; the export has
359-
no separate caption path of its own. `CAPTION_Z_INDEX_BASE = 100_000`
359+
converts the virtual-ms cue list into synthetic `AnnotationRegion`s via
360+
the `captionBandRect` + `captionBackgroundCss` helpers. Those regions
361+
ride the existing annotation path through the scene description and onto
362+
the native compositor; neither surface has a caption path of its own.
363+
Note that `captionBackgroundCss` emits `rgba(...)` (it recombines the
364+
inspector's separate colour and opacity fields), so the native colour
365+
parser has to accept CSS colours and not just hex — that contract is
366+
pinned by a test on each side. `CAPTION_Z_INDEX_BASE = 100_000`
360367
([`src/lib/ai-edition/captions/cues.ts:39`](../../src/lib/ai-edition/captions/cues.ts:39))
361368
gives the export even more clearance above real annotations, and the
362369
synthetic regions carry no `annotationSource` marker because they are

0 commit comments

Comments
 (0)