Every SKILL.md already declared the new name — name: frames, frames-cli, frames-core, and so on — but the directories were never moved, so the tree carried frames-* in content and hyperframes-* on disk. Everything that resolves a skill by path missed: the core-skill list, the plugin marketplace pin, and the docs the CLI reads at runtime. Eight tests failed on main because the files they open do not exist. The directories now match what the files say they are, and the guide the claude-design contract reads takes the name that contract already used.
4.2 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| center-outward-expansion | Elements start clustered at screen center and expand outward to their final positions, driven by a shared progress value. |
|
Center-Outward Expansion
Elements begin at one shared center point and radiate outward to their final positions — the entry beat itself, or motion driven by another animation's progress (a counting number, a beat). Flat 2D cousin of depth-scatter-assemble.md (per-element 3D cloud): here every element shares the SAME origin.
How It Works
Each element carries its final offset as data-target-x/y. Its position lerps between center and target: x = targetX × progress. Self-centering is baked as xPercent/yPercent: -50 so the tweened x/y are pure offsets from the stage center. Standalone burst = per-item staggered fromTo; driven burst = one shared proxy (see Variations).
Recipe
<!-- inside a standard scene clip (frames-core) -->
<div class="burst-wrap">
<div class="burst-item" data-target-x="-360" data-target-y="-180">{itemA}</div>
<div class="burst-item" data-target-x="360" data-target-y="-180">{itemB}</div>
<div class="burst-item" data-target-x="0" data-target-y="360">{itemC}</div>
</div>
.burst-wrap {
position: relative;
width: 100%;
height: 100%;
display: grid;
place-items: center;
}
.burst-item {
position: absolute;
top: 50%;
left: 50%; /* GSAP xPercent/yPercent -50 bakes the centering; x/y tween the offset */
will-change: transform;
}
document.querySelectorAll(".burst-item").forEach((el, i) => {
tl.fromTo(
el,
{ xPercent: -50, yPercent: -50, x: 0, y: 0, scale: 0.6, opacity: 0 },
{
x: Number(el.dataset.targetX),
y: Number(el.dataset.targetY),
scale: 1,
opacity: 1,
duration: EXPAND_DUR,
ease: EXPAND_EASE,
},
ENTRY_AT + i * STAGGER,
);
});
Variations
- Synced to a driver (chord): when the burst shadows a counter / beat, drop the stagger and drive all items from ONE 0→1 proxy tween with the driver's exact duration AND ease;
onUpdatewritestranslate(-50%,-50%) translate(targetX*p, targetY*p)per item — the two read as one beat. - Partially-spread start: with 6+ items the full cluster piles up — start from
{ x: targetX * START_PROGRESS, ... }. - Idle micro-float: hand off to sine-wave-loop.md after landing instead of freezing.
Values
| token | range | notes |
|---|---|---|
| ITEM_COUNT | 3–8 | > 8 = visual chaos mid-expansion; low counts want wider spread |
| EXPAND_DUR | 1.0–1.8s | must equal the driver's duration in the synced variant |
| EXPAND_EASE | power3.out default |
power2.out gentler, expo.out dramatic stop; NEVER in eases |
| STAGGER | 0.04–0.08s | tighter = chord; looser = lazy arpeggio |
| ENTRY_AT | 0–0.5s | a beat of compositional quiet before the burst |
| START_PROGRESS | 0–0.5 | 0 = dramatic full cluster; ~0.3 avoids the pile-up |
Critical Constraints
- Tween
x/yover the bakedxPercent/yPercent: -50— mutatingleft/topfights the centering and causes pixel jitter. - Out-easing only —
ineasings read as items being sucked back mid-air. - No other absolute-positioned siblings inside
.burst-wrap— they'd steal the centered baseline. - ❗ The burst IS the beat — don't park a "real headline" label below it (the eye snaps to the label and ignores the burst). If a label is needed, reveal it post-burst in the same stack.
- Synced variant: identical duration + ease as the driver, or the chord falls apart.
See also
counting-dynamic-scale (the classic chord driver) · depth-scatter-assemble (3D per-element cloud) · card-morph-anchor (burst out of a morphed card) · sine-wave-loop (post-landing life).