---
title: SC Animated Radial Ellipse
description: Radial SVG ellipse strokes with optional gradient, rotation and trim paths.
url: https://secretocho.design/lab/sc-animated-radial-ellipse/
type: SoftwareSourceCode
status: working
published: 2025-04-27
updated: 2025-04-27
---

# SC Animated Radial Ellipse

> Radial SVG ellipse strokes with optional gradient, rotation and trim paths.

component 02 / 28 · WORKING · featured

- **type**: Code Component
- **platform**: Framer
- **last update**: 2025-04-27
- **read time**: 7–9 min
- **license**: SecretoCho Design

![A still of the SC Animated Radial Ellipse demo, as its module draws it with reduced motion.](https://secretocho.design/_astro/still.BOFE9Gev_Z1Skbs0.webp)

*fig 00 · live demo, ported from **SC\_AnimatedRadialEllipse.tsx** · starts on Loader Minimal, since the source default is still*

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

- svg
- ellipse
- animation
- radial
- trim
- stroke-dash
- gradient
- responsive
- generative

### Code comment

```tsx
/**
 * 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

1. Add **SCAnimatedRadialEllipse** to your canvas.
2. Choose sizing: **Size Mode** = fixed (px) or dynamic (% of container).
3. Set geometry: **Count**, **Width/Height** (or **Width%/Height%**), **Width/Height Ratio**.
4. Style strokes: **Stroke Width/Color** or enable **Gradient Blend** and set a unique **Gradient ID**.
5. Animate: toggle **Animate** → set **Rotation** direction/speed.
6. Trim window (optional): enable **Trim Path**, tune **Trim Speed**, **Trim Offset**, **Trim Phase Start**, and **Mirror Trim**.
7. Position: set **Anchor** and **X/Y Offset**.
8. (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\_AnimatedRadialEllipse.tsx · lines 6–14 · header comment*

```tsx
/**
 * 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
 */
```

[props \[REF\]](#reference)

### 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.

*SC\_AnimatedRadialEllipse.tsx · lines 155–189 · tsx*

```tsx
    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

- [Creative coding](https://secretocho.design/about/#capabilities)

## 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](mailto:sc@secretocho.design)

[read the CV](https://secretocho.design/cv/) · [LinkedIn](https://www.linkedin.com/in/secretocho/)
