Skills/Video Composition/Captions Element

ef-captions

Attributes

target
string

Selector for ef-video or ef-audio element

captions-script
string

ID of script element with JSON captions

captions-src
string

URL to JSON captions file

captions-data
object

Direct captions data object

Synchronized captions with word highlighting.

Basic Usage

Live

Caption Data Format

{
"segments": [
{ "start": 0, "end": 3, "text": "Sentence one." }
],
"word_segments": [
{ "start": 0, "end": 0.5, "text": "Sentence" },
{ "start": 0.5, "end": 1.0, "text": "one." }
]
}

Times are in seconds relative to the parent timegroup.

Active Word Styling

Color Highlighting

Live

Background Box Style

Live

Underline and Shadow

Live

Animated Pop Effect

Live

Slide-In Animation

Live

Segment-Level Styling

Full Segment Display

Live

Multi-Line Segments

Live

Karaoke-Style Captions

Classic Karaoke

Live

Progress Bar Karaoke

Live

Gradient Progression

Live

Custom Timing Examples

Fast-Paced Captions

Live

Slow Dramatic Timing

Live

Multiple Speakers

Live

Loading Captions

From External File

<ef-captions captions-src="/captions/video-transcript.json" class="absolute bottom-12 left-0 right-0 text-center">
<ef-captions-before-active-word class="text-white/60 text-xl"></ef-captions-before-active-word>
<ef-captions-active-word class="text-yellow-300 text-2xl font-bold"></ef-captions-active-word>
<ef-captions-after-active-word class="text-white/40 text-xl"></ef-captions-after-active-word>
</ef-captions>

From Inline Script

<ef-captions captions-script="my-captions">
<ef-captions-active-word class="text-yellow-300"></ef-captions-active-word>
</ef-captions>
<script type="application/json" id="my-captions">
{
"segments": [
{ "start": 0, "end": 3, "text": "Your caption text here." }
],
"word_segments": [
{ "start": 0, "end": 1, "text": "Your" },
{ "start": 1, "end": 2, "text": "caption" },
{ "start": 2, "end": 3, "text": "text" },
{ "start": 3, "end": 4, "text": "here." }
]
}
</script>

Via JavaScript

<ef-captions id="dynamic-captions">
<ef-captions-active-word class="text-cyan-400"></ef-captions-active-word>
</ef-captions>
<script>
const captions = document.getElementById('dynamic-captions');
captions.captionsData = {
segments: [
{ start: 0, end: 3, text: "Dynamically loaded captions." }
],
word_segments: [
{ start: 0, end: 1, text: "Dynamically" },
{ start: 1, end: 2, text: "loaded" },
{ start: 2, end: 3, text: "captions." }
]
};
</script>

Sub-Elements

ef-captions uses child elements to separate caption text into styleable parts. These elements act as slots — they're containers that ef-captions fills with text. You style them with CSS classes, and ef-captions handles updating their content.

All caption sub-elements use display: inline by default for natural text flow. They act as transparent containers — the text flows as if the element boundaries don't exist.

ef-captions-active-word

The word currently being spoken. Automatically hidden when empty or contains only punctuation.

CSS Variables:

  • --ef-word-seed - Deterministic random (0-1) per word for animations

Behavior:

  • Adds trailing space automatically for proper word spacing
  • Hidden via hidden attribute when no active word

ef-captions-before-active-word

All words in the current segment that have already been spoken.

Behavior:

  • Adds trailing space when followed by active word
  • Hidden via hidden attribute when no prior words

ef-captions-after-active-word

All words in the current segment not yet spoken.

Behavior:

  • No leading space (active word adds trailing space)
  • Hidden via hidden attribute when no upcoming words

ef-captions-segment

The full text of the current caption segment.

Behavior:

  • Hidden via hidden attribute when no active segment
  • Can be used alone or alongside word-level elements

Layout Patterns

<!-- Inline flow (default) -->
<ef-captions class="text-white text-xl">
<ef-captions-before-active-word></ef-captions-before-active-word>
<ef-captions-active-word class="font-bold"></ef-captions-active-word>
<ef-captions-after-active-word></ef-captions-after-active-word>
</ef-captions>
<!-- Multi-line layout -->
<ef-captions>
<div class="text-center">
<ef-captions-segment class="block text-white/50 mb-1"></ef-captions-segment>
</div>
<div class="text-center">
<ef-captions-active-word class="text-yellow-400 text-2xl"></ef-captions-active-word>
</div>
</ef-captions>

Technical Notes

  • All sub-elements use light DOM (not shadow DOM) for styling simplicity
  • Parent ef-captions element updates child textContent directly
  • Empty or punctuation-only content automatically hides elements via hidden attribute
  • Elements maintain text flow by using display: inline with no margins/padding
  • --ef-word-seed provides deterministic randomness based on word index (not random each frame)

Generate Captions

Use the Editframe CLI to generate captions from video/audio files:

npx editframe transcribe video.mp4 -o captions.json
# Transcribe with specific language
npx editframe transcribe video.mp4 --language en -o captions.json
# Transcribe audio file
npx editframe transcribe audio.mp3 -o captions.json

Then load the generated captions:

Live

See transcription.md for complete transcription workflow documentation.