What “Marker-Driven” Actually Means
When Captyne generates animated caption layers, it places named markers on each word layer. These markers are not just visual labels — they are the single source of truth for every animation in a preset. If your preset is built correctly, an animator can change a word’s entire timing by dragging one marker, and every effect updates automatically.
This is the core difference between a basic After Effects caption setup and a Captyne preset. A basic setup has keyframes at hardcoded time positions. A Captyne preset has expressions that read marker positions at runtime, so “the in-animation completes at frame 12” becomes “the in-animation completes at whatever time IN_END is placed” — fully flexible, forever.
The Four Core Markers
Every word layer Captyne generates carries four named markers. Understanding what each one represents is essential before building a preset.
How Expressions Read Marker Positions
In After Effects, you access a named marker’s time using marker.key("name").time. Every expression in a Captyne preset uses this to make animations relative to marker positions rather than absolute frame numbers. The pattern looks like this:
The inProgress pattern — a 0-to-1 normalized value — is the foundation of every marker-driven expression. Once you have it, you can drive any property by scaling or remapping it.
Always wrap marker reads in try/catch in production presets. If a word layer is missing a marker (e.g. no MID on simple presets), accessing marker.key("MID") throws an error and breaks the expression. The preset template provides safe wrapper functions — use those in your final saved preset.
Step 1 — Open the Preset Creator
Preset Creator → Create New PresetIn the Captyne panel, go to Presets → Create New Preset. The builder opens with a blank word layer template in a test composition. This template already contains:
- A text layer named CAPTYNE_WORD — this becomes each caption word at generation time
- The four named markers pre-placed at sensible default positions on the layer
- A library of pre-written helper expressions in the left panel (inProgress, outProgress, hasMID, etc.)
- Test words of different lengths in the preview panel so you can see how your preset behaves across widths
Before writing any expressions, spend a minute dragging the markers in the test comp timeline. IN_END controls how fast the word appears. Moving OUT_START left shortens the hold. This physical intuition will make every expression decision clearer.
Step 2 — Build the In-Animation (Opacity + Scale)
Property: Opacity & Scale on CAPTYNE_WORDThe in-animation runs from IN_START to IN_END. Apply the following expression to the Opacity property of the CAPTYNE_WORD text layer. This handles all four phases — before, in, hold, and out — in a single expression:
Now add a subtle scale pop on the in-phase by applying a similar expression to the Scale property:
The values 85 and 100 above are just a starting point. Try 0 and 100 for a hard pop, or 92 and 100 for a very subtle settle. These are the only numbers you’ll be changing — the timing always follows the markers.
Step 3 — Add Easing to the In-Animation
Replace linear() with ease()The linear() function creates mechanical, robotic motion. Replace it with After Effects’ built-in ease() for a smooth deceleration into the hold phase, or easeIn()/easeOut() to control which end gets the ease:
For most caption presets, ease() on opacity and easeOut() on scale gives a natural, confident feel. Experiment in the test comp — you can see results instantly without generating any real caption layers.
Step 4 — Build the MID Marker Effect (Hold-Phase Animation)
Optional: Add a sweep, pulse, or glow during holdThe MID marker lets you fire an animation event while the word is fully visible — between IN_END and OUT_START. This is how the built-in Light Sweep and Neon Glow presets work: the word appears, then a secondary effect plays during the hold phase.
A common pattern is a brightness sweep: a glow or highlight that travels across the word from left to right starting at MID.
The try/catch here is essential. If a generated word layer has no MID marker (Captyne only adds it when you include MID in the preset definition), the expression would throw an error without it. The catch block returns a safe fallback position instead.
The key technique in the sweep expression is sourceRectAtTime(time).width — this reads the actual pixel width of the text layer at runtime. That is what makes the sweep automatically adapt to words of any length. A three-letter word and a twelve-letter word each get a sweep that travels the right distance, with no per-word configuration.
Step 5 — Build the Out-Animation
Mirror the in-phase from OUT_START to OUT_ENDThe out-animation is structurally identical to the in-animation, just reversed and starting at OUT_START. If the in-phase fades up and scales from 85 to 100, the out-phase scales from 100 to 85 and fades down. You already handled this in the full lifecycle expression from Step 2.
For out-animations that are different from the in (for example: the word slides up to exit instead of fading), you can write a separate out-phase branch:
Notice that position[0] and position[1] reference the layer’s own keyframed position value, not hardcoded coordinates. This is critical — it means the expression works correctly regardless of where Captyne places the word in the composition.
Step 6 — Connecting Spatial Effects to Word Width
sourceRectAtTime() is your spatial anchorMany effects need to know the physical dimensions of the word — where its left edge is, where its center is, how wide it is. After Effects provides this through sourceRectAtTime(time) on a text layer, which returns a rectangle object with left, top, width, and height.
Use wordWidth to set effect radii, glow sizes, or sweep distances. Use compCenter to position effects that need an absolute comp-space coordinate (like CC Light Sweep’s Center point). This is the mechanism that makes every built-in Captyne preset automatically adapt to any word length.
Step 7 — Test with Variable Word Lengths
Preset Creator → Preview PanelThe preset builder’s preview panel shows your preset applied to several test words simultaneously: a short word (3–4 characters), a medium word (7–8 characters), and a long word (12+ characters). Before saving, verify:
| What to check | Why it matters |
|---|---|
| Opacity / scale starts and ends correctly | Expression errors often show as stuck values (always 0 or always 100) |
| Sweep or glow covers the full word width | Short sweep on a long word means the sourceRect read is wrong |
| Animation completes before OUT_START | If in-animation bleeds into hold, IN_END is too close to IN_START |
| No expression errors in the info panel | Any red error indicator means the expression will fail on generation |
| Dragging markers updates the animation in real time | If not, you have a hardcoded frame number somewhere that overrides the expression |
Check the longest test word carefully. The most common preset bug is a sweep or glow that looks correct on a short word but undershoots on a long one because sourceRectAtTime was called at the wrong layer time or the width was cached before the text was fully rendered.
Step 8 — Declare Markers in the Preset Definition
Preset Creator → Markers TabThe preset definition file tells Captyne which markers to place on each generated word layer. Open the Markers tab in the preset builder and configure:
- IN_START — always required. Set to word audio start.
- IN_END — always required. Set default offset from IN_START (e.g.
+0.25s). - MID — check “Include MID marker” only if your preset uses it. Set default offset from IN_END (e.g.
+0.15s). - OUT_START — always required. Set to word audio end by default.
- OUT_END — always required. Set default offset from OUT_START (e.g.
+0.2s).
These defaults are what Captyne uses when it auto-places markers during generation. Users can always drag them later — these are just sensible starting positions so the preset looks good without any manual adjustment.
Step 9 — Save and Apply Your Preset
Preset Creator → Save PresetGive your preset a name, choose an accent color for the dot in the preset list, and click Save Preset. It immediately appears in the Captyne panel’s preset list alongside the built-in styles.
To test on real content: open any composition with audio, run Transcribe, select your new preset from the list, and click Generate Captions. Every generated word layer will have the exact marker structure your preset declared, and your expressions will drive all the animations.
Complete Minimal Preset: Reference Template
Here is a complete working preset template combining all the expressions from this tutorial — opacity fade, scale pop, and an optional MID sweep — in a single copy-paste-ready block:
Ready to build your own preset?
The preset creator is included in every Captyne beta install. Apply for free access below.
Apply for Free Beta Access →Common Mistakes and How to Avoid Them
Hardcoded frame numbers in expressions
If you write linear(time, 0, 0.3, 0, 100) instead of linear(time, t0, t1, 0, 100), the animation is no longer marker-driven — it always starts at frame 0 regardless of where IN_START is. Always use the marker time variables, never raw numbers for timing.
Missing try/catch on MID marker reads
Every marker.key("MID") call must be inside a try/catch. If the preset is ever applied to a word layer that has no MID marker, the expression errors silently and the effect may freeze or snap to an unexpected value.
Position expressions not referencing the layer’s own position
If you write a position expression that returns absolute coordinates (e.g. [960, 540]), it will break the moment Captyne places the word somewhere other than dead center. Always offset from position[0] and position[1] to respect whatever position Captyne assigns.
sourceRectAtTime called before IN_START
Text layers can have zero-size bounding boxes before they are visible. Call sourceRectAtTime(t1) (using IN_END time as the sample point) rather than the current time if your effect needs a stable width reference throughout the layer’s life, rather than a potentially-zero value at early frames.