CSS & Animations
Style elements with Tailwind classes, CSS animations, and time-driven CSS custom properties.
Tailwind
Tailwind is configured in all scaffolded compositions. Use utility classes directly on any element:
<ef-timegroup duration="5s" class="w-[1920px] h-[1080px] bg-gradient-to-br from-indigo-900 to-purple-900 flex items-center justify-center">
<ef-text class="text-white text-8xl font-bold tracking-tight drop-shadow-lg">
Styled with Tailwind
</ef-text>
</ef-timegroup>CSS animations
Standard @keyframes and the animation property work as expected. The renderer steps through frames deterministically so animations are frame-accurate.
animation-fill-mode: both
animation-fill-mode: both (the both keyword in the shorthand). Without it, elements snap to their pre/post-animation state at frame boundaries, causing visible flicker.Per-segment stagger (ef-text)
When ef-text uses split, each segment gets CSS variables for coordinated animations:
| Variable | Description |
|---|---|
--ef-stagger-offset | Calculated delay for this segment — use as animation-delay |
--ef-index | Integer index (0, 1, 2 …) |
--ef-seed | Deterministic random 0–1 per segment |
<ef-timegroup duration="5s" class="w-[1920px] h-[1080px] bg-slate-900 flex items-center justify-center">
<ef-text split="word" stagger="100ms" class="text-white text-7xl font-bold text-center max-w-4xl leading-tight">
Words reveal one by one
</ef-text>
<style>
@keyframes wordReveal {
from { clip-path: inset(0 100% 0 0); opacity: 0.3; }
to { clip-path: inset(0 0% 0 0); opacity: 1; }
}
ef-text-segment {
display: inline-block;
animation: wordReveal 0.4s ease-out both;
animation-delay: var(--ef-stagger-offset);
}
</style>
</ef-timegroup>Use --ef-seed for random variation:
<ef-timegroup duration="5s" class="w-[1920px] h-[1080px] bg-black flex items-center justify-center">
<ef-text split="char" stagger="50ms" class="text-white text-9xl font-black tracking-widest">
RANDOM
</ef-text>
<style>
ef-text-segment {
display: inline-block;
animation: charIn 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
animation-delay: var(--ef-stagger-offset);
color: hsl(calc(var(--ef-seed) * 280deg + 200deg) 80% 70%);
}
@keyframes charIn {
from {
transform: translateY(calc(var(--ef-seed) * 60px - 30px)) rotate(calc(var(--ef-seed) * 40deg - 20deg));
opacity: 0;
}
to { transform: translateY(0) rotate(0deg); opacity: 1; }
}
</style>
</ef-timegroup>Time-driven CSS variables
Editframe sets CSS custom properties on every element during rendering and preview. Use them to drive animations directly from the timeline without JavaScript.
| Variable | Description |
|---|---|
--ef-progress | Current progress as 0–1 (multiply by 100% when needed) |
--ef-duration | Total duration as a CSS time (e.g. 10s) |
--ef-transition-duration | Overlap duration (only set when parent has overlap) |
--ef-transition-out-start | When the outgoing fade-out should start (duration - overlap) |
<ef-timegroup duration="4s" class="w-[1920px] h-[1080px] bg-black flex flex-col items-center justify-center gap-8">
<ef-text class="text-white text-5xl font-bold">Timeline progress</ef-text>
<!-- Progress bar driven by --ef-progress, no JavaScript -->
<div style="
width: 60%;
height: 8px;
background: rgba(255,255,255,0.15);
border-radius: 4px;
overflow: hidden;
">
<div style="
height: 100%;
background: #818cf8;
width: calc(var(--ef-progress) * 100%);
"></div>
</div>
</ef-timegroup>Crossfade between scenes
<ef-timegroup mode="sequence" overlap="1.5s" class="w-[1920px] h-[1080px]">
<ef-timegroup mode="fixed" duration="4s" class="absolute w-full h-full bg-indigo-900 flex items-center justify-center"
style="animation: var(--ef-transition-duration) fade-out var(--ef-transition-out-start) both;">
<ef-text class="text-white text-7xl font-bold">Fades Out</ef-text>
</ef-timegroup>
<ef-timegroup mode="fixed" duration="4s" class="absolute w-full h-full bg-rose-900 flex items-center justify-center"
style="animation: var(--ef-transition-duration) fade-in 0s both;">
<ef-text class="text-white text-7xl font-bold">Fades In</ef-text>
</ef-timegroup>
<style>
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes fade-out { from { opacity: 1; } to { opacity: 0; } }
</style>
</ef-timegroup>The --ef-transition-duration and --ef-transition-out-start variables are set automatically based on the parent's overlap value — you don't compute them manually.