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.
5.2 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| svg-path-draw | Animate SVG paths drawing progressively using stroke-dasharray and stroke-dashoffset. |
|
SVG Path Draw
Reveals an SVG shape by animating its stroke as if a pen were tracing it. Two stroke properties together: stroke-dasharray = <pathLength> makes the entire path one dash; stroke-dashoffset starts at the path length (dash shifted fully out of view → invisible) and tweens to 0 (fully drawn). The length comes from the DOM API path.getTotalLength() — measured, never guessed.
Works on anything with a stroke: <path>, <circle>, <rect>, <line>, <polyline>, <polygon>, <ellipse>.
Recipe
<!-- inside a standard scene clip -->
<svg class="logo-mark" viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
<path id="bar-left" d="M 60 40 L 60 160" />
<path id="bar-right" d="M 140 40 L 140 160" />
<path id="bar-mid" d="M 60 100 L 140 100" />
</svg>
.logo-mark path {
fill: none; /* outline-only draw — a fill would appear immediately and ruin the reveal */
stroke: {accentColor};
stroke-width: 12;
stroke-linecap: round; /* softer endpoints */
stroke-linejoin: round;
}
// Setup: measure each path and set its dash pattern. Real measured geometry, not a magic number.
document.querySelectorAll(".logo-mark path").forEach((p) => {
const len = p.getTotalLength();
p.style.strokeDasharray = `${len}`;
p.style.strokeDashoffset = `${len}`;
});
// Stagger draws so the eye reads continuous motion — each segment starts at
// ~70-80% of the previous segment's duration, before it finishes.
tl.to(
"#bar-left",
{ strokeDashoffset: 0, duration: SEGMENT_DRAW_DUR, ease: "power2.out" },
SEG_1_START,
);
tl.to(
"#bar-right",
{ strokeDashoffset: 0, duration: SEGMENT_DRAW_DUR, ease: "power2.out" },
SEG_2_START,
);
tl.to(
"#bar-mid",
{ strokeDashoffset: 0, duration: FINAL_SEGMENT_DUR, ease: "power2.out" },
SEG_3_START,
);
// Companion wordmark fades in only after the last stroke settles.
tl.to(
".brand-line",
{ opacity: 1, duration: BRAND_FADE_DUR, ease: "power1.out" },
BRAND_FADE_START,
);
Variations
- Ring starting at 12 o'clock —
<circle>/<rect>strokes start at 3 o'clock by default; rotate the element-90degso a progress ring draws from the top:
<circle
cx="100"
cy="100"
r="60"
id="ring"
style="transform-origin: 100px 100px; transform: rotate(-90deg)"
/>
- Linear (constant-speed) draw —
ease: "none"for a steady-rate "real pen" trace. - Draw then fill — for filled shapes, tween
fillOpacity: 0 → 1AFTER the stroke completes (requiresfill-opacity: 0initially and a realfillin CSS):
tl.to(
"#path",
{ strokeDashoffset: 0, duration: SEGMENT_DRAW_DUR, ease: "power2.out" },
SEG_1_START,
);
tl.to(
"#path",
{ fillOpacity: 1, duration: FILL_FADE_DUR, ease: "power1.out" },
SEG_1_START + SEGMENT_DRAW_DUR,
);
Values
| token | range | notes |
|---|---|---|
| SEGMENT_DRAW_DUR | 0.3–0.8s | fast snap vs deliberate pen trace; >~1s feels sluggish for a logo reveal |
| FINAL_SEGMENT_DUR | 60–80% of SEGMENT_DRAW_DUR | proportional to segment length — a short connector at full duration reads slower than its siblings |
| SEG_N_START | previous start + 70–80% of its duration | reads as continuous motion, not N isolated animations |
| SEG_1_START | 0–0.4s | a small ~0.2s lead-in lets the viewer settle before motion |
| BRAND_FADE_START | ≥ last stroke end (+ ~0.2s beat) | earlier and the wordmark competes with the draw |
| BRAND_FADE_DUR | 0.3–0.8s | snap (urgent) vs glide (premium) |
Ease families are discrete choices: stroke draws use power2.out (a hand lifting at end of stroke) or none for constant speed — never back.out / elastic.out (pens don't bounce). Fades use power1.out.
Critical Constraints
fill: nonefor outline-only draws — otherwise the fill appears immediately.- Dasharray/dashoffset = the measured
getTotalLength(), set at setup; requires the SVG in the DOM (inline SVG is fine; a loaded<image>SVG is not). - Complex paths: if
getTotalLength()looks wrong, overestimate slightly (len * 1.05) — too large is invisible at animation start; too small clips the end. - Stagger multi-path draws at ~70–80% of the previous segment's duration.
See also
svg-icon-enrichment (internal parts animate after the outline draws) · counting-dynamic-scale (stroke draws an icon while a number counts up) · hacker-flip-3d (logo draws, wordmark decodes beneath).