AI Generated finetuned for the visualisation and not code quality.
complex_poly_roots.mov
Interactive C + Raylib viewer for exploring how complex polynomial roots, values, and zero contours behave across a small set of preset equations. The app shows the roots on a 2D complex plane, lifts the polynomial magnitude into a colourful 3D surface, and animates a smooth morph between one preset polynomial and the next.
- Displays preset complex polynomials and their roots
- Cycles between presets with a smooth homotopy instead of a hard cut
- Matches roots between presets by angle order and best cyclic shift
- Evaluates the mixed polynomial across a dense complex grid
- Turns
|p(z)|into a 3D height field so roots become visible valleys - Draws the zero-locus curves for
Re(p_t(z)) = 0andIm(p_t(z)) = 0 - Lets you orbit the surface, zoom in, and probe any point under the mouse
- Shows an explanation panel for the currently hovered complex sample
| Area | What You See |
|---|---|
| Main 3D view | A lifted surface built from the current polynomial value over the complex plane |
| Mini complex plane | The current root positions for the active preset or transition |
| Cyan contour lines | Where the real part of the mixed polynomial is zero |
| Gold contour lines | Where the imaginary part of the mixed polynomial is zero |
| Vertical beams | Root locations projected up from the floor plane |
| Bottom explanation panel | How the hovered point becomes a value and then a surface height |
The viewer interpolates between two preset polynomials:
p_t(z) = (1 - t) P_a(z) + t P_b(z)
It then converts the mixed value into a surface height:
height(z) = -2.25 * tanh(0.58 * ln(|p_t(z)| + 1e-6))
That gives the app three linked ways to understand the same point:
- location in the complex plane
- complex value
p_t(z) - height and colour on the rendered surface
flowchart LR
A["Preset A Roots<br/>current equation"]
B["Preset B Roots<br/>next equation"]
C["Root Matching<br/>sort by argument + best cyclic shift"]
D["Root Interpolation<br/>mixed root positions"]
E["Polynomial Evaluation<br/>sample p_t(z) over a grid"]
F["Height Mapping<br/>ln(|p_t(z)|) -> surface"]
G["Contour Extraction<br/>Re=0 and Im=0"]
H["Render Views<br/>3D surface + mini plane + probe panel"]
A --> C
B --> C
C --> D
D --> E
E --> F
E --> G
F --> H
G --> H
classDef roots fill:#15263d,stroke:#8fd3ff,color:#f3fbff,stroke-width:2px;
classDef match fill:#45215f,stroke:#ff9de1,color:#fff6fd,stroke-width:2px;
classDef math fill:#173f32,stroke:#9ff5b8,color:#f3fff7,stroke-width:2px;
classDef render fill:#5a3300,stroke:#ffd166,color:#fff8eb,stroke-width:2px;
class A,B roots;
class C,D match;
class E,F,G math;
class H render;
flowchart TB
M["Mini Complex Plane<br/>roots and probe position"]
S["Surface Mesh<br/>colour and height from p_t(z)"]
C["Mirror Floor<br/>zero contours"]
P["Probe / Hover<br/>chosen z"]
R["Cyan Curves<br/>Re(p_t(z)) = 0"]
I["Gold Curves<br/>Im(p_t(z)) = 0"]
H["Height Panel<br/>z -> p_t(z) -> |p_t(z)| -> y"]
M --> P
P --> S
P --> H
S --> C
C --> R
C --> I
classDef panel fill:#11243a,stroke:#8ecae6,color:#eef8ff,stroke-width:2px;
classDef probe fill:#4f1f63,stroke:#ff99d7,color:#fff6fd,stroke-width:2px;
classDef contour fill:#204d38,stroke:#9fe5a8,color:#f5fff6,stroke-width:2px;
classDef detail fill:#5b3f06,stroke:#ffd166,color:#fff9ed,stroke-width:2px;
class M,S,C panel;
class P probe;
class R,I contour;
class H detail;
| Visual cue | Meaning |
|---|---|
| Root dots in the mini plane | Current root positions for the active preset blend |
| Root dot glow and orbit rings | The root currently being hovered |
| Spectral surface colours | Phase and magnitude structure of the polynomial value |
| Bright probe marker | The exact z sample currently under inspection |
| Cyan contour network | Re(p_t(z)) = 0 |
| Gold contour network | Im(p_t(z)) = 0 |
| Root beams and floor markers | Where roots sit inside the shared complex domain |
z^2 + 1 = 0z^2 - 5z + 6 = 0z^4 - 1 = 0z^5 - 1 = 0z^3 - 8 = 0z^6 + 1 = 0(z-1)(z+2i)(z+1-i)=0z^7 - 1 = 0
These give a mix of real roots, roots on the unit circle, asymmetric configurations, and degree changes during transitions.
q: quit1: open the roots visualizer page2: open the empty placeholder pagespace: pause or resume the animationp: advance to the next preset and start the morph
left drag: orbit the 3D camera around the surfacemouse wheel: zoom in or outhover the 3D surface: probe the corresponding complex coordinatehover the mini complex plane: inspect root positions or choose a custom complex sample
This repo is doing more than drawing roots as static dots. It links together:
- algebra: the factorised roots that define the polynomial
- geometry: the complex plane location
z = x + iy - analysis: the value
p_t(z)and its real and imaginary zero sets - shape: a 3D surface whose valleys reveal where the polynomial gets close to zero
That makes it easier to see how roots move, how zero contours cross, and how the local behaviour around a root changes as the polynomial morphs from one preset to another.
raylibpkg-config- a C compiler such as
ccorclang
make
make run