106 drawings.
One construction.

The Quiet Sky icon family. Every glyph is assembled from the same primitives against one of four keylines, measured after rendering, and generated from a single script — so the sprite and the files can never drift apart again.

Construction

Four keylines, one stroke.

A 24 × 24 grid with a 20 × 20 live area. Every form is fitted to one of four templates, and the template it was fitted to is recorded in icons.json. A circle is drawn larger than a square because it carries less optical weight at the same measurement — that difference is the whole reason the table exists.

The manifest records one of four optical templates for every icon: square, circle, portrait, or landscape.

ConstantValueWhy
Grid24 × 24Live area 20 × 20 — a 2px trim on every side so icons never touch their box.
Stroke1.5Round cap, round join. One weight; the family has no light or bold cut.
Cornerr = 2Every rectangular form. The system has no sharp corners at any scale, and 24px is not an exception.
The particleØ 3, filledThe only filled element in the family. It means what it means in the logotype: alive, now.
Keylines18.5 / 20 / 16.5×20 / 20×16.5Square · circle · portrait · landscape. Outer extent, stroke included.

Measured, not eyeballed

The build rasterises all 106 drawings and measures each one's tight bounding box against its declared keyline. An icon 2px short of its keyline reads as a mistake in a row of icons that aren't — and that is invisible to the eye until the row exists. Every drawing now lands within 2px, apart from the exemptions below, which are exempt because the geometry says so: a checkmark is not a square, an arrow has a length rather than a width, and a bold B that filled its box would be wider than any B ever drawn.

Run it yourself: python3 brand/doc/build_icons.py --audit

The set

Everything the system asks for.

Including the fourteen composer icons the application spec has always specified and no previous set contained.

Scale

Four sizes, no redraws.

14 inline · 16 buttons and meta · 18 navigation · 20 headers. The family is drawn to survive 16px without an optical cut — verified by rendering, not assumed.

Colour

Icons take text colour.

Every glyph consumes currentColor. Set the text colour on the parent and the icon follows — there is no fill to override and no second colour anywhere in the family.

Use

Rules.

Always

  • Reference the sprite (<use href="#ic-name">) or import the SVG. Never paste path data into a component.
  • Give every icon-only button an aria-label and a tooltip.
  • Pair an icon with text wherever it carries state — colour and shape never carry meaning alone.
  • Use particle and halo for agent presence. They are the logotype's dot, at icon scale.

Never

  • No sparkle, wand or star for AI. The agent's mark is the dot — platform-wide, no exceptions.
  • No second stroke weight, no filled variants, no duotone.
  • No accent colour at rest. Cyan only when the icon is the active or selected signal.
  • No emoji in chrome, no decorative colour, no icon invented outside the build script.
Files

What shipped.

PathWhat
brand/icons/svg/108 files — 106 drawings plus aliases. 24×24, currentColor, stroke 1.5.
brand/icons/sprite.svgAll 108 as <symbol id="ic-{name}">. One request, one cache entry.
brand/icons/icons.jsonManifest: group, keyline, aliases and intent for every glyph.
brand/doc/build_icons.pyThe generator and the audit. Change a constant, rebuild the family.

brand/doc/migrate_assets.py ships this family to assets/icons/, so the product paths and these masters are the same files. The v1 set — 35 icons, two of which rendered identically — is preserved at archive/assets-v1/.