Fractal Tree
A fractal tree drawn by a recursive function over 10 levels: its branches gently spread and close, from a pale pink trunk to green tips.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. SVG has 30 effects, including 3 free. Explore the category →
3 usage examples



How it works
The branch() function draws a segment, then calls itself twice from its tip, with the length cut to 70 % and the angle shifted left then right. It stops at the 10th level or when a branch would be shorter than 2 px: 1,023 segments in all. The trunk starts at the middle of the bottom edge and is 20 % of the area height; the whole tree takes about 64 % of the height and 76 % of the height in width, so a 300 px tall area needs at least 230 px of width.
Only the spread moves: it equals 0.5 + sin(phase) × 0.2 radian, from 0.3 to 0.7, and the phase advances 0.0012 radian per millisecond, a full cycle about every 5.2 s. Elapsed time is capped at 50 ms per frame, so the rhythm is the same at 60 and 120 Hz. Nothing grows and nothing is random: the tree is identical on every load. Hue and thickness depend on the level: 5 px trunk in very light pink (hue 320, 90 % lightness), 0.5 px green tips (hue 140, 45 % lightness).
The canvas is cleared on every frame (transparent, so the background of .fx-0616-root shows through) and fully redrawn. Its size is read from the displayed area and multiplied by devicePixelRatio; a ResizeObserver follows it, an IntersectionObserver stops the loop off screen, and nothing starts while the area is 0 px. Every root on the page runs on its own, and only once (data-ftr-ready), even if the script is pasted twice.
Accessibility
- Label:
role="img"andaria-labelon the canvas. When nearby text already says the same thing (empty state, reward card), switch it toaria-hidden="true". - Reduced motion: under
prefers-reduced-motion: reduce, the tree is drawn once, still, at its average 0.5 radian spread. - Pausing: the sway lasts as long as the tree is visible. For WCAG 2.2.2, a button that toggles the root's
hiddenattribute is enough: the loop stops at zero size and resumes at the same phase. - Keyboard: the effect has no interactive element.
- Contrast: the 45 % lightness green tips stay visible on a dark background; on white, the last 0.5 px branches become very faint.
Browser compatibility
2D canvas and about 3.4 KB of JavaScript, no dependency. ResizeObserver: Chrome 64, Firefox 69, Safari 13.1; IntersectionObserver: Chrome 51, Firefox 55, Safari 12.1 (MDN data). Measured in Chromium 151, Firefox 153 and WebKit 26.5: 2× density rendering, two independent copies, start after a delayed reveal, still tree under reduced motion, no frames computed off screen.
Without ResizeObserver, the tree only follows window resizes; without IntersectionObserver, it keeps swaying off screen. Without JavaScript, the area keeps the root's background with no tree.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0616-root">
<canvas class="ftr-canvas" role="img" aria-label="Fractal tree whose branches gently spread apart and close in"></canvas>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Depth (JS — LEVELS) |
10 levels (1,023 segments) | 7 gives a stylised tree with crisp branches. Branches shorter than 2 px are never drawn: beyond 10, a level is only added in a tall enough area (the 11th from 355 px high, the 12th from 506 px, up to 4,095 segments). |
Trunk (JS — TRUNK) |
0.2 (20 % of the height) | 0.25 makes a taller tree that nearly touches the top edge; 0.15 leaves room above for a heading. |
Shrink per level (JS — REDUCTION) |
0.7 | 0.6 gives a compact crown, 0.75 long branches that spill over the sides. |
Spread (JS — SPREAD) |
0.5 radian | 0.3 draws a narrow poplar, 0.8 a wide-open tree. |
Sway (JS — SWAY, SPEED) |
0.2 radian, 0.0012 radian/ms | SWAY at 0.05 for a shiver, SPEED at 0.0005 for a 12 s cycle. |
Colours (JS — strokeStyle line in branch()) |
hue 120 + level × 20, lightness 40 + level × 5 % | A fixed hue (30 for instance) with the same lightness formula gives a graded autumn tree. |
Background (CSS — background of .fx-0616-root) |
#0a0a0f | The canvas is transparent: this colour is the only one that matters. |
Height (CSS — --ftr-height) |
300px | Any fixed height, or 100% inside a parent of known height. Plan a width of at least 0.76 times the height. |
FAQ
LEVELS is fixed. Growth would require raising the depth or trunk length over time inside loop(). That is why the reward example reveals the tree at once instead of pretending it grows.