The Component Pattern: Encapsulating Motion with $.group()
July 8, 2026 · By VideoFlowLearn how to use the $.group() pattern in VideoFlow to build reusable, encapsulated video components that scale your programmatic video pipelines.
The Component Pattern: Encapsulating Motion with $.group()
When you start building programmatic video pipelines, it is tempting to treat the timeline as a single, monolithic script. You add a background, you add a title, you wait three seconds, and you add a CTA. This works for a 15-second ad, but as soon as you scale to complex personalized video ads or data-heavy dashboards, your code becomes a tangled web of frame math and coordinate offsets.
In traditional web development, we solved this with components. In VideoFlow, we solve it with the $.group() pattern. This isn't just about organization; it's about creating reusable, encapsulated units of motion that make your video code maintainable and dry.
The Monolith Problem
Imagine you are building a video that showcases three different product features. Each feature needs a rounded background card, an icon, a title, and a description. Without grouping, you have to manually calculate the startTime for every single layer. If you decide to move the second feature card 500ms later, you have to update the start times of the icon, the title, and the description individually.
This is the "Monolith Problem." It makes your video logic fragile and prevents you from reusing visual patterns across different projects.

Encapsulation with $.group()
The $.group() method in the VideoFlow core API allows you to create a container that nests other layers and treats them as a single entity.
A group has its own local coordinate system and, more importantly, its own local timeline. Inside the group callback, the flow pointer starts at zero. This means you can author a complex animation sequence inside the group without worrying about where it sits on the main timeline.
// A reusable product card component
const createProductCard = ($, { x, label, color }) => {
return $.group(
{ position: [x, 0.5], perspective: 20 },
{
transitionIn: { transition: 'zoom', duration: '600ms' },
transitionOut: { transition: 'fade', duration: '400ms' },
},
() => {
// These positions are relative to the project, but the group
// handles the overall transformation.
$.addShape(
{ width: 30, height: 40, fill: '#1a1a2e', cornerRadius: 2, strokeColor: color, strokeWidth: 0.1 },
{ shapeType: 'rectangle' }
);
$.addText({
text: label,
fontSize: 3,
color: '#fff',
position: [0.5, 0.45],
}).fadeIn('400ms');
$.wait('1s');
}
);
};
Composition and Layout
Because $.group() returns a GroupLayer instance, you can manipulate the entire group as if it were a single image or text layer. You can animate its position, apply cinematic GLSL effects, or even nest groups within groups.
In the example below, we use the component function to create three cards in a loop. Because each group handles its own internal timing, we only need to manage the stagger on the main timeline.
const $ = new VideoFlow({ width: 1920, height: 1080 });
const features = [
{ label: 'Fast', color: '#FF5A1F' },
{ label: 'Open', color: '#4ecdc4' },
{ label: 'Scale', color: '#a78bfa' },
];
features.forEach((feat, i) => {
createProductCard($, { x: 0.2 + i * 0.3, label: feat.label, color: feat.color });
$.wait('500ms'); // Stagger the entry of each card
});
$.wait('3s');

How VideoFlow Handles Grouping
Under the hood, VideoFlow's @videoflow/core compiler resolves these nested structures into a flat, portable VideoJSON document. The GroupLayer doesn't just hold children; it composites them onto a private surface before applying the group's own properties—like opacity, scale, or rotation—to the entire subtree.
This architecture ensures that your reusable components render identically across all three official renderers. Whether you are exporting an MP4 in the browser with @videoflow/renderer-browser or running a headless Node.js pipeline with @videoflow/renderer-server, the encapsulation remains frame-perfect.
Moving Toward Video-as-Code
Treating videos like software means adopting software engineering best practices. By using the $.group() pattern, you move away from "editing" a timeline and toward "architecting" a visual system. This is especially powerful for automated video localization, where you might need to swap text components across hundreds of variants while keeping the motion logic identical.
Ready to build your first component? Head over to the VideoFlow Playground to experiment with groups in real-time, or check out the GitHub repository to see how the GroupLayer is implemented in the core.