SVG Drawing Animation notes

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
No comments yet. Be the first to comment.
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

What it is: The distance around the outside of a circle Formula: circumference = 2 × π × radius Example: Circle with r="6" → 2 × 3.14159 × 6 = 37.7px
dasharray = WHAT the pattern looks like (creates the dashes)
dashoffset = WHERE the pattern starts (shifts the pattern)
<!-- Creates pattern: [10px dash][10px gap][10px dash][10px gap]... -->
<line stroke-dasharray="10" />
<!-- Same pattern, shifted 5px along -->
<line stroke-dasharray="10" stroke-dashoffset="5" />
Make one dash = full shape length
Hide it by offsetting it away
Animate offset back to 0 to reveal
<!-- Step 1: Calculate length -->
<circle r="6" />
<!-- circumference = 37.7 -->
<!-- Step 2: Setup -->
<circle r="6" stroke-dasharray="37.7" <!-- One dash="full" circle -->
stroke-dashoffset="37.7"
<!-- Hidden initially -->
/>
<!-- Step 3: Animate -->
<!-- Change stroke-dashoffset to 0 via CSS/JS --></circle
>
circle {
stroke-dasharray: 37.7;
stroke-dashoffset: 37.7;
transition: stroke-dashoffset 2s ease;
}
circle:hover {
stroke-dashoffset: 0; /* Draws the circle */
}
const circle = document.querySelector("circle");
const circumference = 2 * Math.PI * 6; // radius = 6
// Setup
circle.style.strokeDasharray = circumference;
circle.style.strokeDashoffset = circumference;
// Animate
circle.style.transition = "stroke-dashoffset 2s ease";
circle.style.strokeDashoffset = "0";
Normalizes path length to any number you want instead of using actual SVG units
<!-- Without pathLength: need to calculate exact length -->
<path d="..." stroke-dasharray="12.847" />
<!-- With pathLength: use round numbers -->
<path d="..." pathLength="10" stroke-dasharray="10" />
Before: Calculate actual path length (messy decimals)
After: Choose your own units (clean round numbers)
<!-- Real checkmark path might be 12.847 units long -->
<path d="M7.75 11.75L10 14.25L16.25 7.75" pathLength="10" />
<!-- Now you can use stroke-dasharray="10" instead of "12.847" -->
<circle
cx="12"
cy="12"
r="6"
stroke-dasharray="37.7"
stroke-dashoffset="37.7"
/>
<circle
cx="12"
cy="12"
r="6"
stroke-dasharray="37.7"
stroke-dashoffset="37.7"
style="transform: rotate(-90deg); transform-origin: center;"
/>
<path
d="M7.75 11.75L10 14.25L16.25 7.75"
pathLength="10"
stroke-dasharray="10"
stroke-dashoffset="10"
/>
// Don't animate all the way to 0
const circumference = 37.7;
const partialOffset = circumference * 0.25; // Show 75% of circle
circle.style.strokeDashoffset = partialOffset;
const percentageComplete = (startTime - timeLeft) / startTime;
const offset = circumference * (1 - percentageComplete);
circle.style.strokeDashoffset = offset;
const rotationDegrees = percentageComplete * 360;
line.style.transform = `rotate(${rotationDegrees}deg)`;
/* Exact match */
button[aria-checked="true"] {
}
/* Attribute exists */
button[aria-checked] {
}
/* Starts with */
button[class^="btn-"] {
}
/* Ends with */
button[class$="-large"] {
}
/* Contains */
button[class*="nav"] {
}
element.style.setProperty("--rotation", "45deg");
// or
element.style.cssText = "--rotation: 45deg;";
// or in React
<div style={{ "--rotation": "45deg" }} />;
.element {
transform: rotate(var(--rotation));
transition: transform 1s ease;
}
<circle>
<animate
attributeName="stroke-dashoffset"
from="37.7"
to="0"
dur="2s"
fill="freeze"
/>
</circle>
<svg id="svg">
<circle>
<animate
attributeName="stroke-dashoffset"
to="0"
dur="1s"
fill="freeze"
begin="svg.mouseover"
/>
</circle>
</svg>
Issue: Can't animate dashed shapes using stroke-dasharray technique Why: stroke-dasharray is already used for the dash pattern Solution: Use SVG masks instead
// For paths
const length = path.getTotalLength();
// For circles
const length = 2 * Math.PI * radius;
// For any shape with pathLength attribute
// Just use the pathLength value
/* Add transitions to make animations smooth */
.animated-path {
transition: stroke-dashoffset 1s linear;
}
// Circle circumference
const circumference = 2 * Math.PI * radius;
// Percentage to degrees (for rotation)
const degrees = percentage * 360;
// Progress animation offset
const offset = circumference * (1 - percentageComplete);
// Partial reveal offset
const offset = circumference * percentageRemaining;
// React component
const [timeLeft, setTimeLeft] = useState(60);
const [startTime] = useState(60);
const circumference = 2 * Math.PI * 6; // radius = 6
const percentageComplete = (startTime - timeLeft) / startTime;
const circleOffset = circumference * (1 - percentageComplete);
const lineRotation = percentageComplete * 360;
return (
<svg viewBox="0 0 24 24">
{/* Background circle */}
<circle cx="12" cy="12" r="6" opacity="0.2" />
{/* Progress circle */}
<circle
cx="12"
cy="12"
r="6"
stroke-dasharray={circumference}
stroke-dashoffset={circleOffset}
style={{
transform: "rotate(-90deg)",
transformOrigin: "center",
transition: "stroke-dashoffset 1s linear",
}}
/>
{/* Rotating line */}
<line
x1="12"
y1="8"
x2="12"
y2="10"
style={{
transform: `rotate(${lineRotation}deg)`,
transformOrigin: "center",
transition: "transform 1s linear",
}}
/>
</svg>
);