Why these two helpers

num() and count() are the foundation for advanced loops, keyframe generators, and chart-style calculations (including st-core@v2). They run at compile time (or in the browser runtime) and emit plain numbers into CSS.

num(expression)

+ - * / with optional unit after )

count(limit[, step])

Sequences for index arrays and loops

With @arr

Length-driven indexes, sum/min/max, normalized %

<script src="https://cdn.jsdelivr.net/npm/fscss@1.2.5/runtime.min.js" async></script>

1. num() — compile-time math

Arithmetic in stylesheets

Core

num(expression) evaluates +, -, *, / when FSCSS runs. Append a unit immediately after the closing parenthesis.

Critical rule — grouping

Do not use parentheses (), braces {}, or brackets [] inside the expression (they conflict with CSS/FSCSS parsing).

Use angle brackets < > for grouping:

num(<100 - 1> / <4 + 50>)%
FSCSS
/* Basic */
selector {
  max-height: num(40 * 4)px;          /* → 160px */
}

/* Grouping with < > */
something {
  $res: num(<100 - 1> / <4 + 50>)%;   /* → ~1.85% */
}

/* With random */
textarea {
  max-height: num(@random([40, 10, 5, 0]) + 50);
}

/* Nested / complex (v1.2.3+) */
.box {
  width: num(<45 - 2> / 2 * <5 - 3>)px;
}
Notes
Unit after ):
  num(10 * 2)px   ✓
  num(10 * 2 px)  ✗

Grouping:
  num(<a - b> / c)  ✓
  num((a - b) / c)  ✗ inside expr

Variables:
  num($n! * 2)rem
  num(@arr.x[$i!] * 1.5)px

2. count() — number sequences

Build index lists

Core
count(limit)          /* 1, 2, 3, …, limit */
count(limit, step)    /* from step, by step, up to limit */

From v1.2.1+, the limit may be an array’s .length:

Examples
exec(_log, "count(5)")       /* → 1, 2, 3, 4, 5 */
exec(_log, "count(10, 2)")   /* → 2, 4, 6, 8, 10 */

@arr colors[#ef4444, #f59e0b, #10b981, #3b82f6]
@arr indexes[count(@arr.colors!.length)]     /* → 1,2,3,4 */
/* or: count(@arr.colors!.length, 1) */
Typical use
@arr idx[count(@arr.data!.length, 1)]

/* then loop */
.item:nth-child(@arr.idx[]) { … }
rpt(@arr.idx[], "div ") { … }
inline("empty-@arr.idx[] { … }")

3. Patterns with arrays

Index array for looping

Most common
@arr colors[#ef4444, #f59e0b, #10b981, #3b82f6, #8b5cf6]
@arr indexes[count(@arr.colors!.length, 1)]

empty{ /* preserve */ }

.loading-dot:nth-child(@arr.indexes[]) {
  $index: @arr.indexes[];
  background: @arr.colors[$index!];
  animation-delay: num(@arr.indexes[] * 0.15)s;
}

Derived values (normalize / CSS variables)

v1.2.3+
@arr data[30, 55, 80, 45, 90]
@arr idx[count(@arr.data!.length, 1)]

empty-@arr.idx[] {
  $i: @arr.idx[];
  --st-p$i: num(100 - @arr.data[$i!])%;
}

Same idea as chart point inversion in st-core (100 - value → Y% for clip-path).

Math inside rpt() bodies

@arr sizes[8, 12, 16, 24]
@arr levels[count(@arr.sizes!.length)]

empty{ /* preserve */ }

rpt(@arr.levels[], ".item ") {
  padding: num(@arr.sizes[@arr.levels[]] * 1.5)px;
  font-size: num(@arr.sizes[@arr.levels[]] + 4)px;
}

Numeric array methods + num()

@arr nums[10, 20, 30, 40, 50]

.total  { width: num(@arr.nums!.sum)px; }
.min-w  { width: num(@arr.nums!.min)px; }
.max-w  { width: num(@arr.nums!.max)px; }

Also: @arr.n!.length with count() for index generation.

Quick reference

Feature Syntax Notes
Basic math num(a * b)px Unit after )
Grouping num(<a - b> / <c + d>) Use <> only
Sequence count(5) / count(10, 2) From 1 or from step
From length count(@arr.name!.length) v1.2.1+
Index array @arr idx[count(@arr.data!.length, 1)] Loop helper
Array numerics !.sum / .min / .max / .length With num()