A Rust tool that reads 2D contours from YAML files, text strings, or SVG files, computes their complex Fourier decomposition, and generates interactive HTML visualizations with animated epicycles.
cargo install circles-sketch
Each example also generates a standalone <div> snippet (*-embed.html) that can be embedded directly into your own HTML page via an <iframe> or by inlining the markup:
Any closed 2D shape can be described as a sum of rotating circles (Fourier series). This tool:
max_harmonics terms (default 500, configurable in the config YAML)The animation shows epicycles (rotating circles) that, when chained together, trace out the original shape. As more harmonics are added, the approximation gets closer to the original contour.
graph LR
subgraph Inputs
YAML["YAML points<br/><i>guitar.yml</i>"]
TEXT["Text + Font<br/><i>'Hello' + Arial</i>"]
SVG["SVG file<br/><i>band.svg</i>"]
CFG["Config YAML<br/><i>*-config.yml</i>"]
end
YAML -->|serde_yaml::from_str| C["Contour<br/>Vec<(f64,f64)>"]
TEXT -->|svg_path_of_text| SP["SVG path string"]
SVG -->|extract <path> d=| SP
SP -->|points_of_svg_path| C
C -->|"interpolate(n)"| IC["Interpolated<br/>Contour"]
IC -->|svg_path_of_contour| SVGPath["SVG path"]
IC -->|fourier_decomposition| FD["Fourier<br/>Coefficients"]
SVGPath --> GEN["html_of_svg_path_with_fourier<br/>embed_html_of_svg_path_with_fourier"]
FD --> GEN
CFG -->|EmbedOptions| GEN
subgraph Output
HTML["stem.html<br/><i>Full interactive page</i>"]
EMBED["stem-embed.html<br/><i>Minimal embed</i>"]
end
GEN --> HTML
GEN --> EMBED
style YAML fill:#4a9eff,color:#fff
style TEXT fill:#4a9eff,color:#fff
style SVG fill:#4a9eff,color:#fff
style CFG fill:#f5a623,color:#fff
style C fill:#7b68ee,color:#fff
style SP fill:#7b68ee,color:#fff
style IC fill:#7b68ee,color:#fff
style SVGPath fill:#7b68ee,color:#fff
style FD fill:#7b68ee,color:#fff
style GEN fill:#e06c75,color:#fff
style HTML fill:#50c878,color:#fff
style EMBED fill:#50c878,color:#fff
The tool uses subcommands for different input types:
circles-sketch points examples/guitar.yml
open examples/guitar.html
Reads guitar.yml and the matching config guitar-config.yml, producing guitar.html and guitar-embed.html.
circles-sketch text --font "TimesNewRomanPSMT" "Hello World"
open hello-world.html
Renders text using a system font and generates the visualization. Use list-fonts to find available font PostScript names:
circles-sketch list-fonts
circles-sketch --flip-y svg examples/band.svg
open examples/band.html
Extracts <path> data from an SVG file. Supports absolute and relative M, L, C, Q, H, V, Z commands with bezier curve sampling. Use --flip-y for SVGs with negative Y scale transforms.
circles-sketch init-config my-config.yml
--config <file> — specify a config YAML-o <stem> — set the output file stem-n <N> / --num-points <N> — number of interpolation points (default: 1000)--flip-y — flip Y coordinates (for SVGs with negative Y scale transforms)The config file controls animation behavior and display options:
steps:
ranges:
- from: 1
step: 1
to: 10
speed: 3.0
- from: 10
step: 5
to: 20
speed: 3.0
- from: 20
step: 10
to: 100
speed: 3.0
show_contour: Never # Always, Never, or !Congruence {modulo: N, congruents: [0]}
show_point: true
show_trace: Always
trace_length: 0.5
opacity: 0.5
show_nh: true
trace_width: 1.0
contour_width: 1.0
show_fourier_circles: Always
trace_colors:
- red
- lime
- dodgerblue
- gold
- hotpink
- cyan
- orange
The steps field controls how harmonics progress across animation loops. Each range specifies from, step, to, and speed:
nh = first range's from, with increment = first range's stepnh += incrementnh >= range's to, move to the next rangespeedFor example, with ranges [(1, 1, 10, 3.0), (10, 5, 20, 3.0), (20, 10, 100, 1.0)]:
The steps schedule is editable in the interactive HTML page using the format from step to speed ; from step to speed ; ....
Fields show_contour, show_trace, and show_fourier_circles accept:
Always — show on every loopNever — never show!Congruence {modulo: N, congruents: [r1, r2, ...]} — show when loop_index % N is in the congruents listThe generated full HTML page includes:
from step to speed ; ...), speed is per-rangeContour files are simple YAML with a list of [x, y] points:
points:
- [0.0, 0.0]
- [1.0, 0.0]
- [1.0, 1.0]
- [0.0, 0.0]
| File | Description |
|---|---|
examples/square.yml |
Simple square |
examples/cardioid.yml |
Cardioid curve |
examples/move-the-line |
“Move The Line” text (AkayaTelivigala font) |
examples/guitar.yml |
Electric guitar |
examples/band.svg |
Band silhouette (SVG input) |
src/
lib.rs — Library crate root
contour.rs — Contour, ContourFunction, Fourier decomposition
model.rs — EmbedOptions, HarmonicSteps, WhenToShow config types
canvas.rs — SVG path parsing, HTML/Canvas generation
text.rs — Text-to-SVG-path using system fonts
test.rs — Unit tests
bin/
circles-sketch.rs — CLI binary (clap subcommands)
examples/
*.yml — Contour data files
*-config.yml — Config files
*.html — Generated full interactive pages
*-embed.html — Generated minimal embed pages
cargo build
cargo test
A Makefile is provided to regenerate the example HTML files. It only rebuilds examples whose source files have changed:
make examples
clap — CLI argument parsing with subcommandsserde + serde_yaml — YAML serialization/deserializationttf-parser — Font glyph outline extractionfont-kit — System font lookup