Skip to content

Recipes & Patterns

Bite-sized patterns you can copy into your projects. Each recipe is self-contained and demonstrates a common animation technique.

1. Animated Function Plot with Moving Tangent

Section titled “1. Animated Function Plot with Moving Tangent”

Use useCurrentFrame and interpolate to sweep a tangent line along a curve.

-4-3-2-11234-2-112
0.00s / 3.97s · F0
import { Player, Axes, FunctionPlot, Line, Circle, Text,
useCurrentFrame, interpolate, easeInOutCubic } from '@elucim/core';
function TangentDemo() {
const frame = useCurrentFrame();
const x = interpolate(frame, [0, 120], [-3, 3], { easing: easeInOutCubic });
const y = Math.sin(x);
const dy = Math.cos(x); // derivative of sin
const ox = 300, oy = 200, sc = 50;
const px = ox + x * sc, py = oy - y * sc;
return (
<Player width={600} height={400} fps={30} durationInFrames={120}>
<Axes origin={[ox, oy]} xRange={[-4, 4]} yRange={[-2, 2]} scale={sc} />
<FunctionPlot fn={Math.sin} domain={[-4, 4]} origin={[ox, oy]} scale={sc}
color="#818cf8" />
<Line x1={px - 40} y1={py + 40 * dy} x2={px + 40} y2={py - 40 * dy}
stroke="#f472b6" strokeWidth={2} />
<Circle cx={px} cy={py} r={4} fill="#f472b6" />
</Player>
);
}

Use <Stagger> to reveal a row of labeled boxes one at a time.

InputTokenizeEmbedAttendOutput
0.00s / 2.97s · F0
import { Player, Stagger, FadeIn, Rect, Text } from '@elucim/core';
const labels = ['Input', 'Tokenize', 'Embed', 'Attend', 'Output'];
function Pipeline() {
return (
<Player width={700} height={200} fps={30} durationInFrames={90}>
<Stagger staggerDelay={8}>
{labels.map((label, i) => (
<FadeIn key={i} duration={15}>
<Rect x={30 + i * 130} y={60} width={110} height={50}
fill="rgba(79,195,247,0.15)" stroke="#4fc3f7" rx={8} />
<Text x={85 + i * 130} y={90} fill="#e0e7ff" fontSize={14}
textAnchor="middle">{label}</Text>
</FadeIn>
))}
</Stagger>
</Player>
);
}

Use the <Graph> component with custom edge colors and labels.

import { Player, FadeIn, Graph } from '@elucim/core';
function NetworkGraph() {
return (
<Player width={500} height={400} fps={30} durationInFrames={60}>
<FadeIn duration={20}>
<Graph
nodes={[
{ id: 'a', x: 100, y: 200, label: 'A', color: '#4fc3f7' },
{ id: 'b', x: 250, y: 80, label: 'B', color: '#a78bfa' },
{ id: 'c', x: 400, y: 200, label: 'C', color: '#f472b6' },
{ id: 'd', x: 250, y: 320, label: 'D', color: '#34d399' },
]}
edges={[
{ from: 'a', to: 'b', color: '#4fc3f7' },
{ from: 'b', to: 'c', color: '#a78bfa', directed: true },
{ from: 'c', to: 'd', color: '#f472b6' },
{ from: 'd', to: 'a', color: '#34d399', directed: true },
{ from: 'a', to: 'c', color: '#64748b', label: '5' },
]}
nodeRadius={20}
edgeWidth={2}
/>
</FadeIn>
</Player>
);
}

4. Multi-Slide Presentation with DSL Builder

Section titled “4. Multi-Slide Presentation with DSL Builder”

Generate a two-slide deck programmatically and render it.

import { DslRenderer } from '@elucim/dsl';
import { presentation, darkTheme } from '@elucim/dsl';
const t = darkTheme;
const doc = presentation('Quick Demo', darkTheme, { width: 800, height: 500 })
.slide('Intro', s => {
s.title('Welcome');
s.wait(5);
s.subtitle('Built with the Builder API');
s.wait(5);
const boxes = s.boxRow(['Step 1', 'Step 2', 'Step 3'], {
y: 300, boxWidth: 120, boxHeight: 50, gap: 20,
});
s.connectDown(boxes, { color: t.muted });
})
.slide('Conclusion', s => {
s.title('That\'s it!');
s.wait(5);
s.latex('\\sum_{i=1}^{n} i = \\frac{n(n+1)}{2}', { y: 300, fontSize: 32 });
})
.build();
function App() {
return <DslRenderer dsl={doc} style={{ maxWidth: 800, margin: '0 auto' }} />;
}