Drag a mouth-shape symbol onto the stage, scrub the playhead along the timeline, and nothing moves. Press Ctrl+Enter to test the movie and the same symbol loops frantically. One symbol, one piece of animation, two completely different results between authoring and runtime. That is not a bug. It is the fundamental difference in how Animate’s two symbol types resolve their timelines, and it determines which type belongs in lip sync, in character animation, and in interactive elements.
A symbol is not a folder of layers, it is an independent timeline
A symbol in Animate lives in the library; what sits on the stage is an instance of it. Every symbol carries a complete timeline of its own: layers, keyframes, and nested instances of other symbols. The instance on stage stores only a reference plus instance-level properties — a transform matrix, a colour effect, a blend mode, filters, and, crucially, the rule by which this instance picks a frame from that timeline.
Edit the symbol in the library and every instance changes. Instance-level properties affect one instance only. The item that actually causes trouble is the last one: the frame-picking rule is completely different between Movie Clip and Graphic.
A Graphic’s frame number is a function of the parent timeline
A Graphic symbol has no playhead of its own. Which frame it displays is computed directly from the parent timeline’s current frame number. Let:
P = current frame of the parent timeline
S = frame on the parent timeline where this instance starts
F0 = the instance's "First" property (starting frame offset, 1-based)
L = length of the symbol's own timeline, in frames
d = P - S // how many frames this instance has existed
The three loop modes give three different frame-picking functions:
Loop: frame = ((d + F0 - 1) mod L) + 1
Play Once: frame = min(d + F0, L)
Single Frame: frame = F0 // independent of d, always static
Because frame is a pure function of P, Animate can compute the child frame for any parent frame at authoring time. That is why scrubbing the parent playhead animates the nested content, and why exporting a frame sequence or a video produces the correct child frame on every single frame.
A worked example you can check by hand. Symbol length L = 8, the instance begins at parent frame S = 20, First is set to F0 = 3, mode is Loop. At parent frame P = 26:
d = 26 - 20 = 6
frame = ((6 + 3 - 1) mod 8) + 1 = (8 mod 8) + 1 = 1
Parent frame 27 yields child frame 2; parent frame 25 yields child frame 8. Change First to 1 and the same parent frame 26 yields child frame 7 instead. This is the single most common source of “the lip sync is off by a few frames”: the keyframes were drawn correctly, but some instance had its First value nudged.
A Movie Clip’s frame number ignores the parent entirely
A Movie Clip owns a playhead, driven by the runtime frame loop, with no relationship to where the parent timeline currently sits. Stop the parent timeline and the Movie Clip keeps playing. Scrub the parent backwards and the Movie Clip does not run backwards.
The direct consequence is that on the authoring stage, a Movie Clip instance always shows only its own frame 1. Animate cannot know in advance where the runtime playhead will be, so frame 1 is all it can draw. You have to test the movie to see motion.
That explains the behaviour in the opening paragraph, and it explains a more damaging case as well. Nest a Movie Clip inside a timeline that is being rendered frame by frame — exporting a PNG sequence or a video — and the nested animation in the output will usually be frozen on frame 1 in every single exported frame. The renderer evaluates by parent frame number, and a Movie Clip does not accept the parent frame number as input.
Why lip sync and character animation almost always use Graphic
In television animation pipelines, a character’s mouth, eyes and hands are built as Graphic symbols, precisely because the frame number is a function of the parent frame:
- Frame-accurate posing. Set the mouth symbol to
Single Frameand changeFirston each keyframe: that literally means “use mouth shape number N on this frame”. With the dialogue waveform below, you scrub and calibrate, and what you see is what you get. - Reliable export. Frame-by-frame rendering can compute the child frame, so the export never collapses to frame 1.
- Reverse and scrub. Dragging the parent playhead backwards steps the animation back correctly, which is how you check timing.
Movie Clips earn their place at runtime instead. They carry instance names and can be addressed by script; they support filters, blend modes and 3D transforms, which Graphic symbols cannot use; and they suit looping backgrounds, particles and UI parts — anything that does not need to align exactly with the parent timeline.
Nesting multiplies transforms, and it multiplies colour effects too
Instance transforms concatenate up the symbol hierarchy, structurally identical to a bone hierarchy:
M_world(instance) = M_world(parent) · M_local(instance)
So placing an already-scaled symbol inside a scaled parent multiplies the two scales rather than adding them. This is why line weights look wrong after three levels of nesting: stroke width is affected by the accumulated scale unless the stroke is set not to scale.
Colour effects — Alpha, Tint, Brightness, Advanced — compose the same way. A parent instance at 50% Alpha containing a child instance at 50% Alpha yields 25% final opacity. To fade a whole group out, apply Alpha once at the outermost level rather than on each child: per-child alpha composes non-linearly and cannot be driven by a single tween.
How to verify all of this inside Animate
The following checks need no plugins and survive version differences. Run them before trusting the formulas above:
- Verify the Graphic frame formula. Build an 8-frame symbol with the digits 1–8 drawn one per frame. Place it on stage, set Loop and
First = 3, extend the parent timeline to 30 frames. Step the playhead frame by frame, record the digit shown, and compare against the formula. - Verify that Movie Clips ignore the parent frame. Duplicate that symbol, change its type to Movie Clip, and place it on a layer below. Scrubbing should leave it on 1 the whole time; Ctrl+Enter should start it looping independently.
- Verify nested export behaviour. Put both instances on the timeline, export a PNG sequence, and check whether the Movie Clip lane is stuck on frame 1 in every image.
- Verify Alpha composition. Set 50% Alpha on both parent and child, then sample the final pixel with a colour picker. It should land near 25%, not 0% or 50%.
Panel positions and option names shift between Animate versions and language packs — “Loop”, “Graphic Options” and similar labels move around — but the frame-resolution rules themselves have been stable for years. If your measurements disagree with the formulas, suspect the 1-based versus 0-based convention on First, or the value you assumed for the instance start frame S, before suspecting the loop mode.
The question actually worth asking when choosing a type
Do not choose by asking “does this need to move” — that selects both types at once. There are only two useful criteria.
First, does this animation need to align exactly with the parent timeline? If yes — lip sync, character action, anything destined for frame-by-frame export — use Graphic. Second, does it need script addressing, filters or blend modes? If yes, it must be a Movie Clip, and you accept that it cannot be previewed while authoring and will not expand during frame-by-frame export.
When both conditions hold at once, meaning you need exact alignment and a filter, the usual answers are to move the filter to an outer container, or to pre-render that section as an image sequence and re-import it. Forcing a Movie Clip to do both generally fails at export time.