No SVG. No canvas. No JS charting library.

st-core.fscss v2 now draws spider (radar) charts the same way it draws area and line charts: FSCSS arrays, CSS custom properties, and clip-path: polygon(). The result looks like a modern product dashboard — skills matrices, multi-axis scores, team comparisons — and the payload stays tiny.

The module Source:

github.com/fscss-ttr/st-core.fscss

Why this feels modern

Modern UI is not “more libraries.” It’s clarity, density, and motion that doesn’t cost a framework.

Spider charts in st-core lean on:

  • Token-driven color — --st-accent, --st-surface, --st-border. Change one variable; the whole chart follows.
  • Soft polar geometry — fill via color-mix, stroke as a dual-pass polygon, rings and spokes as gradients. No harsh SVG strokes fighting your theme.
  • Composable layers — grid, spokes, fill, line, dots stack as plain divs. Multi-series is just more layers with their own accent.
  • Native inheritance — coordinates are custom properties. Children inherit. Multi-team cards don’t need a state tree; they need scoped hosts.

That combination reads as “product UI,” not “demo from 2014.”

Why st-core stays lightweight

What you don’t ship What you do ship
Chart.js / D3 / Recharts A few @define mixins
SVG path builders clip-path: polygon()
Canvas + DPR logic CSS % + sin() / cos() in calc()
Hydration for the chart Optional JS that only sets variables

Geometry is decided at compile time from @arr length. Runtime work is rewriting --st-sxN / --st-syN (or --st-pN for linear charts). Animations can use transition: clip-path on the compositor.

Compiled CSS for a chart class stays on the order of about a kilobyte, not a hundred. The page paints charts with zero chart-library JavaScript.

That’s the st-core bet: visualization as styling, not as an app runtime.

The one rule (same as linear charts)

Points write. Renderers read.

@st-spider-points(array) → writes --st-sxN / --st-syN on the host @st-spider-fill / line / dots → only read those variables 

Call points on the host that owns the series. Multi-series means one host per series — same pattern as multi-line area charts in v2.

Angle 0° is at the top. Values are 0–100 scores scaled by rmax (default 42% of the box).

What you can build

1. Minimal radar

Six axes, one series, grid + spokes + fill + line + dots.

@import((*) from st-core@v2) @st-root() @st-spider-root() @arr skills[80, 65, 90, 55, 70, 85] @st-spider-fill(.spider-fill, skills) @st-spider-line(.spider-line, skills) @st-spider-dots(.spider-dot-, skills, 9px) @st-spider-grid(.spider-grid) @st-spider-spokes(.spider-spokes, skills) .spider { @st-spider-points(skills, 42) position: relative; width: 280px; height: 280px; border-radius: 50%; background: var(--st-surface); } 
<div class="spider"> <div class="spider-grid"></div> <div class="spider-spokes"></div> <div class="spider-fill"></div> <div class="spider-line"></div> <div class="spider-dot-1"></div> <!-- … through .spider-dot-6 --> </div> 

Dots need real DOM nodes — the mixin only generates the CSS.

2. Team comparison cards

Two hosts, two accents, shared label layout:

@arr teamA[92, 78, 85, 55, 48, 80] @arr teamB[68, 82, 70, 95, 62, 58] .spider-wrap.team-a { @st-spider-points(teamA, 42) --st-accent: #9d7eff; --st-spider-fill-opacity: 28%; } .spider-wrap.team-b { @st-spider-points(teamB, 42) --st-accent: #4fffb0; --st-spider-fill-opacity: 30%; } 

Axis labels are ordinary absolute spans (Speed, Quality, UX, Scale, Cost, Support,...) around the circle. No special chart API — just layout.

3. Multi-series overlay

One polar grid, five polygons, each series a full-size absolute layer with its own @st-spider-points and --st-accent. Lower --st-spider-fill-opacity keeps overlaps readable.

4. Live updates without a library

function polarVars(values, rmax = 42) { const n = values.length; return values.map((v, i) => { const ang = (i * 360) / n; const r = (v / 100) * rmax; return ( `--st-sx${i + 1}: calc(50% + (${r} * 1%) * sin(${ang} * 1deg));` + `--st-sy${i + 1}: calc(50% - (${r} * 1%) * cos(${ang} * 1deg));` ); }).join(" "); } host.style.cssText = polarVars([80, 65, 90, 55, 70, 85]); 

Same length as the compiled polygon; values morph. Optional transition on clip-path for soft motion.

Under the hood (short)

Layer Technique
Coordinates --st-sxN / --st-syN from sin / cos in calc()
Fill Closed polygon() + color-mix with --st-spider-fill-opacity
Stroke Dual-pass polygon; inner path scaled by --st-spider-stroke-scale
Rings radial-gradient stops at 20 / 40 / 60 / 80%
Spokes Thin conic-gradient bands from -90deg + center mask

Everything is documented in the repo: README (API + examples), EXPLAINED (every @define), integration/html (dual-team and multi-series demos).

Install

NPM CLI:

npm install -g fscss charts.fscss charts.css 

Testing via CDN:

<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.5/runtime.min.js" async></script> 
@import((*) from st-core@v2) 

Prefer FSCSS CLI for production CSS with zero runtime preprocessor.

Requires FSCSS v1.2.3+. MIT licensed.

Area and line charts proved that dashboards don’t need a JS chart runtime. Spider charts extend that idea into polar space without changing the contract: arrays in, custom properties out, polygons on screen.

Explore the module, the demos, and the under-the-hood write-up here:

github.com/fscss-ttr/st-core.fscss

Pure CSS. Still lightweight. Now with radar.