component 02 / 28WORKINGfeatured
SC Animated Radial Ellipse
- type
- Code Component
- platform
- Framer
- last update
- read time
- 7–9 min
- license
- SecretoCho Design
demo · runs with JavaScript
Renders a radial array of SVG <ellipse> strokes with optional gradient, rotation, and trim-path windows; dimensions adapt via fixed or container-relative radii.
A highly customizable SVG animation that draws multiple rotating ellipses in radial symmetry. Supports trim-path style reveals, gradient strokes, and responsive sizing—perfect for abstract loaders, hypnotic loops, animated backgrounds, and generative motifs.
- Pro Tips
- Generative
Main
Overview
- Built With
- React, SVG, CSS, Framer Code Component API
- Layout Support
- Fully Responsive or fixed width/height
- Orientation
- Full Fill or Text Mask
- Ideal Use Case
- Animated backgrounds, design motifs, abstract loaders
Tags
Code comment
/** * SC Animated Radial Ellipse * © SecretoCho Design 2025 (https://secretocho.design) * Dynamic SVG-based radial ellipse pattern with customizable count, size, and animation. * Ideal for hero visuals, interactive backgrounds, and meditative art pieces. * @framerDisableUnlink * @framerSupportedLayoutWidth any * @framerSupportedLayoutHeight any */Dependencies
- Technologies
- None (pure SVG/React)
- Notes
- No runtime libraries required; works with Framer’s standard runtime.
Complexity
- Logic Level
- Medium (animated render, dash math)
- Runtime Cost
- Medium–High with rotate + trim active (bounded by ellipse count)
- Component Size
- ~3–4 KB (raw TSX)
- Notes
- Use Show FPS only while debugging.
Guide
Instructions
- Add SCAnimatedRadialEllipse to your canvas.
- Choose sizing: Size Mode = fixed (px) or dynamic (% of container).
- Set geometry: Count, Width/Height (or Width%/Height%), Width/Height Ratio.
- Style strokes: Stroke Width/Color or enable Gradient Blend and set a unique Gradient ID.
- Animate: toggle Animate → set Rotation direction/speed.
- Trim window (optional): enable Trim Path, tune Trim Speed, Trim Offset, Trim Phase Start, and Mirror Trim.
- Position: set Anchor and X/Y Offset.
- (Debug) Toggle Show FPS during tuning; disable before publish.
Examples / Presets
Loader Minimal
- count
- 9
- strokeWidth
- 1
- animate
- on
- trimPath
- on
- trimSpeed
- 0.006
- rotationSpeed
- 0.15
- gradient
- off
Hypnotic Halo
- count
- 33
- strokeWidth
- 2
- gradient
- on
- ellipseRatioX
- 1
- ellipseRatioY
- 1.2
- animate
- on
- trimPath
- on
- mirrorTrim
- on
Low-Power Accent
- count
- 13
- animate
- on
- trimPath
- off
- rotationSpeed
- 0.1
- strokeWidth
- 1
Mechanics
How it Works
- Odd symmetry: Ensures an odd Count for balanced radial spacing (angleStep = 360/oddCount).
- Sizing: Uses fixed px or container-relative % to compute actualWidth/Height; ratios (ellipseRatioX/Y) thin/flatten radii (rx = width/ratioX, ry = height/ratioY).
- Rotation: Each ellipse receives a per-element transform: rotate(angle, cx, cy) where angle = index*step + rotation.
- Trim window: Approximates ellipse perimeter with Ramanujan’s formula; applies strokeDasharray=perimeter and animates strokeDashoffset by a sinusoidal phase (supports Mirror Trim by offsetting half-perimeter).
- Gradient: Optional <linearGradient id={gradientId}> stroked via url(#id)—unique IDs prevent collisions across instances.
- Layout: ResizeObserver and a resize handler update container dimensions; anchor presets offset the cluster by quarter-frame steps plus X/Y offsets.
Performance & Tuning
- Cost scales with Count × Stroke effects. Keep strokeWidth ≤ 2–3px when Trim Path is on.
- Prefer moderate Count (7–33 UI accents, 33–99 hero visuals).
- Large gradients across many ellipses are expensive—reuse one gradient where possible.
- Disable Show FPS for production.
Compatibility & Limits
- Modern evergreen browsers (Chrome/Edge/Safari/Firefox).
- SVG gradients and stroke-dash animations are broadly supported; verify on older mobile Safari if using heavy gradients.
- Multiple instances on one page must use unique Gradient ID.
Quality
Accessibility
- Decorative by default; if it conveys no information, wrap with aria-hidden="true".
- In Text Mask scenarios (external), ensure readable contrast or provide a plain-text alternative nearby.
Security & Privacy
- No network calls; no data stored.
- Typed props; no dangerouslySetInnerHTML / eval.
- No device permissions.
- Cleanup note: event listeners created for resize are removed; ResizeObserver is disconnected on unmount.
Reference
Props
| name | type | default | description |
|---|---|---|---|
count | number | 15 | Number of ellipses (auto-forces odd for symmetry) |
strokeWidth | number | 1 | SVG stroke width of each ellipse (px) |
strokeColor | string | #FF4081 | Stroke color (used if Gradient Blend is off) |
gradient | boolean | false | Enable linear gradient stroke instead of solid color |
gradientId | string | grad-default | Unique SVG gradient id (avoid collisions) |
sizeMode | string(enum) | fixed | Ellipse sizing mode (fixed or container-relative) |
ellipseWidth | number | 200 | Ellipse width in pixels (when Size Mode = fixed) |
ellipseHeight | number | 600 | Ellipse height in pixels (when Size Mode = fixed) |
widthPercent | number | 12 | Ellipse width as % of container (when Size Mode = dynamic) |
heightPercent | number | 48 | Ellipse height as % of container (when Size Mode = dynamic) |
ellipseRatioX | number | 1 | Width divisor for ellipse radius (higher = thinner) |
ellipseRatioY | number | 1 | Height divisor for ellipse radius (higher = flatter) |
animate | boolean | false | Turn on rotation/trim animation loop |
showFPS | boolean | false | Overlay a live FPS counter (for testing) |
rotationDirection | string(enum) | counter-clockwise | Rotation direction (counter-clockwise/clockwise) |
rotationSpeed | number | 0.2 | Degrees per frame tick while animating |
trimPath | boolean | false | Animate a traveling stroke “window” via dash offsets |
mirrorTrim | boolean | false | Mirror trim window around the ellipse path |
trimSpeed | number | 0.01 | Trim phase speed (cycles per frame tick) |
trimOffset | number | 0 | Per-ellipse trim phase offset (−1..1) |
trimStartOffset | number | 0 | Global trim phase start (0..1) |
positionAnchor | string(enum) | center | Base anchor for the ellipse cluster |
xOffset | number | 0 | Horizontal offset from anchor (px) |
yOffset | number | 0 | Vertical offset from anchor (px) |
Notes & Tips
- If gradients look “shared” between instances, duplicate and change Gradient ID.
- Uneven trim? Keep trimSpeed small and confirm dash length uses the current perimeter (already computed).
- For ultra-smooth rotation, prefer modest rotationSpeed (0.1–0.3).
Troubleshooting / FAQ
Gradient ID collision
Set a unique gradientId per component instance.
Stuttering
Lower count, reduce strokeWidth, and disable mirrorTrim.
Trim not visible
Ensure Trim Path is on; try increasing strokeWidth or lowering trimSpeed.
Source
Header comment
/** * SC Animated Radial Ellipse * * © SecretoCho Design 2025 (https://secretocho.design) * Generates a dynamic SVG-based radial ellipse pattern with customizable count, size, and animation behaviors. * Ideal for hero visuals, interactive backgrounds, or meditative animated art pieces. * @framerDisableUnlink * @framerSupportedLayoutWidth any * @framerSupportedLayoutHeight any */Key excerpt
The ellipse loop: Ramanujan’s approximation gives each ellipse’s length, a sine phase slides its dash window along it, and each copy turns by one angle step.
const ellipses = [] for (let i = 0; i < oddCount; i++) { const angle = i * angleStep + rotation const rx = actualWidth / ellipseRatioX const ry = actualHeight / ellipseRatioY const length = Math.PI * (3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry))) const t = Math.sin( (trimPhase + i * trimOffset + trimStartOffset) * 2 * Math.PI ) const normalized = (t + 1) / 2 const offset = trimPath ? normalized * length : 0 const dasharray = trimPath ? `${length}` : undefined const dashoffset = trimPath ? mirrorTrim ? `${offset - length / 2}` : `${offset}` : undefined ellipses.push( <ellipse key={i} cx={centerX + offsetX} cy={centerY + offsetY} rx={rx} ry={ry} stroke={gradient ? `url(#${gradientId})` : strokeColor} strokeWidth={strokeWidth} fill="none" strokeDasharray={dasharray} strokeDashoffset={dashoffset} transform={`rotate(${angle}, ${centerX + offsetX}, ${centerY + offsetY})`} /> ) }Credits
Credits
Concept, implementation, and Framer adaptation by SecretoCho Design.
Ellipse trim math uses a Ramanujan-style circumference approximation.
- license
- SecretoCho Design
SecretoCho Design 2025
Disclaimer
Provided “as is” for visual/UX purposes. Validate performance, accessibility, and visual contrast on your target devices and layouts.
Proves
Hiring a design engineer?
I’m open to senior design engineer roles: remote from Belgrade, or relocation with visa sponsorship. Write to me, or read the CV first. Client work stays selective, one project at a time.
sc@secretocho.design