Core Concepts
A handful of ideas carry the whole of Flow. Once they are clear, both the editor and the runtime read as variations on them.
Sequences
A sequence is one timeline: a named set of tracks with a length in seconds and a frame rate. A new sequence is 10 seconds long at 60 FPS. Time is stored in seconds, so the frame rate only sets the grid the editor snaps to and steps by; changing it never moves anything.
Sequences live in the place as instances under ReplicatedStorage.Flow.Sequences, one Configuration per
sequence. That is what makes Team Create and undo work: every edit is an ordinary change to the DataModel, so
collaborators see it replicate and Studio's undo history records it.
Tracks
A sequence holds tracks, listed top to bottom in the editor. Each track has a type, and the type decides what the track drives:
| Track | Drives |
|---|---|
| Instance | Any instance: a part, a model, a light, a GUI object |
| Camera | workspace.CurrentCamera, which it takes control of while it plays |
| Global Audio | An AudioPlayer (or a legacy Sound) it creates for the playback |
| Rig | A rigged Model, through its Animator |
| Empty | Nothing; holds sections that need no subject |
| Subsequence | Other sequences, played inside this one |
| Fade | A full-screen color overlay |
| Time Dilation | The sequence's own clock, to slow it down or speed it up |
| Folder | Other tracks, for organizing the list |
The instance a track drives is its subject. Most tracks have one; Camera, Global Audio, and Fade find or make their own; Empty and Folder have none.
Sections and keyframes
A track holds sections, the blocks you see on the timeline. Each section has a type, a start and end time, and parameters. A section only does anything while the playhead is inside it.
| Section | What it does |
|---|---|
| Property | Animates one property of the subject |
| Animation | Plays a Roblox animation on a rig |
| Audio | Plays the track's audio with a keyframed volume |
| Particle Emit | Emits particles from a ParticleEmitter |
| Subsequence | Plays another sequence over its range |
| Fade | Fades the screen to the Fade track's color |
| TimeScale | Scales playback speed on a Time Dilation track |
Parameters are either constant or keyframed. A keyframed parameter holds a list of keyframes, each a time and a value, and the runtime blends between them. Keyframe times are relative to the section's start, so moving a section moves its animation with it. Each keyframe also names the curve that leads out of it: linear, constant, an easing style, or a Bezier curve.
Sections that overlap in time on one track sit on separate sub-rows. When two sections write the same property at the same time, the one evaluated last wins: lower tracks win over higher ones, and lower sub-rows over higher ones. Blending weights and priority, covered in Sections and keyframes, let them mix instead.
Restore and Hold
Before a section first writes a property, Flow remembers the value that was there. When the section ends, its restore policy decides what happens:
- Restore, the default, puts the original value back. A sequence that finishes leaves the place as it found it.
- Hold keeps the last value the section wrote. Use it for an outcome that should stick, such as a door left open.
Flow keeps one shared record of these original values per property across every playback, so two sequences animating the same part at once still restore it to its true original when they are both done.
The root
Every sequence has a root instance, and every subject is stored as a path below it. The root defaults to
game, which reaches everything, so you can start building without thinking about it.
Narrowing the root is what makes a sequence reusable. If a sequence animates the pieces of a room and its root
is that room's Model, then pointing the root at a different copy of the room retargets every track at once.
When the root is a PVInstance (a part or model), its pivot is also the sequence's origin: positions are
stored relative to it, so moving the root moves the whole sequence with it.
A root does not have to be in the Workspace. A ScreenGui root is how you build a UI sequence.
Bindings
Behind every subject is a binding: a named slot that resolves to an instance when the sequence plays. Assigning a subject in the editor creates one for you, hidden from scripts.
When a subject should vary between plays, such as whichever door the player touched, you promote its binding and give it a public name. A script then supplies the instance:
Flow:Play("DoorOpen", { Bindings = { Door = touchedDoor } })
The instance assigned in the editor stays on as the preview target. Two other kinds of subject need no binding at all:
- Spawnables are cloned from a template stored with the sequence each time it plays, and removed after.
- Subject presets are produced on the client when the sequence plays. The built-in presets build a copy of the local player's character, or of a random friend's, at a fixed rig type. In the editor a grey stand-in rig takes its place.
Where sequences play
Sequences are evaluated on the client. A client can play one locally for itself, or the server can start a synced playback that every client evaluates from the same shared start time. Late joiners compute where the sequence should be and join it there. The server never animates anything frame by frame; it shares when a sequence started, how fast it is going, and what it is bound to.
That means state your game depends on, such as whether a door is really open for collision, stays your game's responsibility. Flow plays what happens on screen.