Generate static images and animations of classic hypnotic spirals.
HypnoSpyrals is a CLI tool and interactive previewer that renders spiral visualizations to image files (SVG, PNG, JPG) and video files (MP4, WEBM, GIF). It supports five spiral types, configurable arm geometry, background images, oscillator-driven animation, stereoscopic 3D, and seamless looping.
# Clone and install
git clone https://github.com/PsynApps/hypnospyrals.git
cd hypnospyrals
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"- Python 3.10+
- FFmpeg (required for video/GIF export)
# macOS
brew install ffmpeg
# Ubuntu/Debian
sudo apt install ffmpeg# Open the interactive preview (default when no subcommand given)
hypnospyrals --preset rainbow
# Save a single frame as PNG
hypnospyrals save-image --preset tunnel -o tunnel.png
# Save a single frame as SVG (vector)
hypnospyrals save-image --preset galaxy -o galaxy.svg
# Save a seamless animation loop
hypnospyrals save-video --preset rainbow -o rainbow.mp4
# Custom parameters with overrides
hypnospyrals save-image --arms-count 6 --motion-spin-speed 0.3 --arms-colors "#FF0000" "#0000FF" -o spiral.png
# Combine a preset with overrides
hypnospyrals save-video --preset tunnel --motion-spin-speed 1.0 --arms-colors "#FF0000" "#00FF00" "#0000FF" -o fast.mp4
# List available presets
hypnospyrals list-presets
# Show a preset's configuration
hypnospyrals show-preset rainbow| Type | Description | Equation |
|---|---|---|
archimedean |
Classic hypnotic spiral (default) | r = b * theta |
logarithmic |
Self-similar, expanding spiral | r = a * e^(b*theta) |
fermat |
Windings converge at large radii | r = a * sqrt(theta) |
hyperbolic |
Windings converge near center | r = a / theta |
concentric |
Pulsing concentric rings | rings at fixed radii |
CLI flags use the universal prefix naming convention: --{tab}-{parameter}. All artistic parameters can also be set in YAML presets using the equivalent {tab}_{parameter} field name.
| Flag | Type | Default | Description |
|---|---|---|---|
--spiral-aperture |
string | circle |
Aperture shape: none, circle, square, diamond |
--spiral-type |
string | archimedean |
Spiral type (see table above) |
--spiral-windings |
float | 1.0 |
Winding tightness (-5.0 to 5.0; sign controls direction) |
--spiral-curve |
float | 1.0 |
Winding distribution exponent (0.1-3.0) |
| Flag | Type | Default | Description |
|---|---|---|---|
--background-color |
hex | #FFFFFF |
Background fill color |
--background-image |
path | Path to background image file (PNG, JPG, SVG) | |
--background-image-mode |
string | fill |
How background image is sized: fill, fit, stretch, center, tile |
| Flag | Type | Default | Description |
|---|---|---|---|
--arms-count |
int | 1 |
Number of spiral arms (1-16) |
--arms-colors |
hex list | #000000 #FFFFFF |
Arm colors (min 2), supports alpha (#RGB, #RGBA, #RRGGBB, #RRGGBBAA) |
--arms-width |
float | 0.5 |
Arm width relative to spacing (0.01-1.0; 1.0 = no gaps) |
--arms-gradient |
string | none |
Gradient mode: none, radial, angular |
| Flag | Type | Default | Description |
|---|---|---|---|
--effects-twists |
int | 0 |
Number of twist reversals (0-10) |
--effects-twist-bias |
float | 0.5 |
Where twist boundaries cluster (0.0=center, 0.5=even, 1.0=edge) |
--effects-softness |
float | 0.0 |
Edge softness (0.0 = sharp, 1.0 = fully feathered) |
--effects-opacity |
float | 1.0 |
Spiral opacity (0.0-1.0) |
| Flag | Type | Default | Description |
|---|---|---|---|
--motion-spin-speed |
float | 0.25 |
Spin speed in rotations/sec (-2.0 to 2.0; sign controls direction) |
--motion-color-cycle-speed |
float | 0.0 |
Color rotation speed in Hz (-2.0 to 2.0; sign controls direction) |
Oscillators modulate any numeric parameter over time using periodic waveforms. Add them via the CLI or the interactive preview's Oscillators tab.
# Add an oscillator: TARGET:SHAPE:SPEED:MIN:MAX
hypnospyrals --oscillator spiral_windings:sine:0.5:0.5:3.0
# Multiple oscillators
hypnospyrals --oscillator spiral_windings:sine:0.5:0.5:3.0 --oscillator arms_width:triangle:0.2:0.1:0.8Available targets: any numeric parameter in PARAM_RANGES (spiral_windings, spiral_curve, arms_count, arms_width, effects_twists, effects_twist_bias, effects_softness, effects_opacity, motion_spin_speed, motion_color_cycle_speed, stereo_depth).
Available shapes: sine, triangle, sawtooth, square.
| Flag | Type | Default | Description |
|---|---|---|---|
--stereo-mode |
string | none |
Stereo output format (see table below) |
--stereo-depth |
float | 1.0 |
Stereo depth (-1.0 to 1.0; negative = into screen) |
--stereo-depth-curve |
string | cube_root |
How depth varies with radius (see table below) |
Depth curves (steepest to flattest near center):
| Curve | Formula | Effect |
|---|---|---|
cube_root |
(r/R)^(1/3) | Dramatic gravity-well funnel (default) |
square_root |
(r/R)^(1/2) | Moderate funnel |
linear |
r/R | Uniform slope |
quadratic |
(r/R)^2 | Flat center, depth at edges |
inverse |
1 - r/R | Flipped: center close, edges far |
Stereo modes:
| Mode | Description | Output Size |
|---|---|---|
none |
Mono (default) | W x H |
cross |
Cross-eye (viewable without glasses) | 2W x H |
sbs |
Side-by-side (full) | 2W x H |
half_sbs |
Side-by-side (half width per eye) | W x H |
ou |
Over/under (full) | W x 2H |
half_ou |
Over/under (half height per eye) | W x H |
anaglyph |
Red/cyan anaglyph | W x H |
# Cross-eye 3D viewable without glasses
hypnospyrals save-image --preset stereo-tunnel -o cross.png
# Red/cyan anaglyph
hypnospyrals save-video --preset tunnel --stereo-mode anaglyph -o anaglyph.mp4
# Side-by-side for VR headsets
hypnospyrals save-video --preset rainbow --stereo-mode half_sbs -o vr_spiral.mp4| Flag | Type | Default | Description |
|---|---|---|---|
--resolution |
WxH | 1080x1080 |
Per-eye render resolution (e.g., 1920x1080) |
--fps |
int | 30 |
Frame rate for video/GIF |
--quality |
int | 90 |
JPEG quality / video CRF control |
--supersampling |
int | 2 |
Render at Nx resolution then downscale (1, 2, or 4) |
--duration |
float | auto | Force specific duration in seconds |
--max-loop-duration |
float | 300.0 |
Maximum auto-loop duration |
--codec |
string | auto | Video codec override |
Running hypnospyrals with no subcommand (or with --preset) opens the PySide6 (Qt6) interactive preview. The UI provides seven parameter tabs (Spiral, Background, Arms, Effects, Motion, Oscillators, Stereo) with real-time rendering, transport controls, and the ability to load/save presets and export images/video directly.
Signed parameters (windings, speeds) use sliders with a centered zero tick mark.
Basic spiral types:
| Preset | Description |
|---|---|
archimedean |
Basic Archimedean spiral |
logarithmic |
Basic logarithmic spiral |
fermat |
Basic Fermat spiral |
hyperbolic |
Basic hyperbolic spiral |
concentric |
Basic concentric rings |
Feature showcases:
| Preset | Description |
|---|---|
archimedean-twisted |
Twist reversals with counter-spin |
archimedean-multiarm |
Four-arm pinwheel |
concentric-breathing |
Pulsing rings with windings oscillator |
fermat-curved |
Exaggerated winding curve |
throb |
Pulsing concentric rings with dual oscillators |
Aesthetic presets:
| Preset | Description |
|---|---|
rainbow |
Rotating rainbow arms with color cycling |
tunnel |
Circle-framed tunnel vortex |
galaxy |
Soft logarithmic spiral galaxy with SVG starfield |
vortex |
Intense fast-spin Fermat vortex |
dreamy |
Soft pastel meditation spiral with angular gradient |
starburst |
Diamond-framed six-arm rotating mandala |
hypnotic |
Twisted logarithmic spiral |
lenscover |
Circle-framed four-arm lens pattern |
Stereoscopic 3D:
| Preset | Description |
|---|---|
stereo-tunnel |
Cross-eye 3D concentric tunnel |
stereo-hypnotic |
Cross-eye 3D twisted logarithmic spiral |
stereo-throb |
Cross-eye 3D pulsing rings with depth oscillator |
All animated exports are automatically rendered as exactly one seamless loop. The loop period is computed as the LCM of all active animation periods (spin, oscillators, color cycle). If the exact loop would exceed 300 seconds, the closest near-seamless approximation within that limit is used.
| Extension | Type | Notes |
|---|---|---|
.svg |
Static | True vector output via Cairo |
.png |
Static | Raster, first frame at t=0 |
.jpg |
Static | JPEG with configurable quality |
.mp4 |
Animated | H.264 by default, seamless loop |
.webm |
Animated | VP9 by default, seamless loop |
.gif |
Animated | Palette-optimized via FFmpeg |
MIT