DSSL v0.2: “First Light”, ratified

The v0.1 draft was put to a seven-point vote. This document is the ratified v0.2 result, and every decision below is implemented by the engine serving this page. The engine itself has kept growing since: it is now at v0.15.0 (see the changelog for what the site demanded).

Decision log

Seven questions, seven answers, the draft spec was amended to match.

#QuestionDecisionConsequence
1Syntax styleBracesC-shaped blocks; semicolons optional, newline-terminated declarations
2Styling engineOwn engineNo CSS output for regular rules, selectors matched against the live DOM, declarations applied directly; pseudo-elements excepted (shadow CSS)
3Bare numberspxpadding: 16 is 16px; unitless preserved where CSS demands it
4CascadeLayers + orderNo specificity, no !important; five layers; pin as the only escape hatch
5VocabularyModerate sugarAll CSS names valid + a small semantic set (row, grid, fluid, …)
6ConditionsCSS shapesNested state blocks (hover, focus…) + @media / @container; @signal added as the JS bridge
7Website shapeDocs siteMulti-view docs with live examples, playground, spec and changelog

1 · Architecture

DSSL is a styling language plus engine. Source files use the .dssl extension. The engine, four dependency-free ES modules (parser, resolver, engine, API), fetches stylesheets, parses them, resolves tokens, and computes styles for elements in the live DOM. It survives DOM mutations via a MutationObserver, re-evaluates states on interaction events, and re-runs media conditions through matchMedia listeners.

Regular rules produce no CSS: winning declarations are applied to elements directly. Pseudo-elements, which cannot be expressed inline, are the single exception, they compile to a shadow stylesheet that references the same tokens. A tiny opt-in reset (data-dssl-reset) is likewise generated CSS, zero-specificity via :where().

pipeline.txt
.dssl source
  └─ parser.js     braces syntax → node tree (loud, line-numbered errors)
      └─ resolver.js   tokens · semantic expansion · behaviors · flatten
          └─ engine.js   match → cascade (layer, order) → element.style
                          states via events · @media via matchMedia
                          motion via Web Animations API
              └─ shadow CSS  ::before/::after/::selection + reset only

2 · Syntax

  • Blocks open with header { and close with }; one-liners allowed.
  • Declarations are prop: value, newline- or ;-terminated. Valueless semantics (truncate) and use name need no colon.
  • Comments: // and block comments. Strings are "…" or '…'.
  • Values continue across lines while parens are open, or the line ends with a top-level comma or colon.
  • Bare numbers are px; 16/1.4 size-over-lineheight in font; token/40 is alpha.

3 · Tokens

tokens { } blocks define named values in nested groups (color.ink, space.4). They compile to --dssl-* custom properties on :root. Reference resolution is strict: an identifier that matches no token and no known keyword is a compile error with a suggestion. Tokens may be defined conditionally (inside @media/@signal), that is how theming works. Bundles share one token registry in load order.

4 · Cascade

For every element, the engine collects all structurally-matching rules whose conditions pass, sorts them by (layer, source order), and applies declarations in sequence, later declarations overwrite earlier ones on the element. Layers, lowest first:

tokens < base < components < utilities < pin

Author rules default to components. @layer re-assigns a subtree. pin blocks apply with !important-grade priority as the single sanctioned escape hatch. Selectors keep their native meaning, ids and pseudo-classes select exactly as in CSS, they simply carry no weight in conflict resolution.

5 · Conditions

  • Element states, nested blocks named for the pseudo-class (hover, focus-visible, active, disabled, checked, …). The engine wires the events; rules re-evaluate live via matches().
  • @media, any media query; bare numbers become px ((width >= 768)).
  • @container, evaluated against the nearest ancestor with container-type set, tracked by the engine with a ResizeObserver.
  • @signal, name (truthy), name == value, name != value; driven from JS.
  • Conditions compose by nesting; siblings AND together. Raw pseudo-classes in selector text (.tab:hover) also work.

6 · Motion

motion name { } declares keyframes (from, to, at N%); a single terminal block interpolates from the element's natural state. animate: name duration easing fill runs it via the Web Animations API, the engine deduplicates re-runs so recomputes never restart animations; DSSL.replay() does that on demand. Reduced-motion disables animations unless essential: true.

7 · Signals

DSSL.signal(name, value) sets a named value in the engine and mirrors it onto <html> as data-dssl-signal-<name>, inspectable, framework-free theming and UI state. Clearing with null returns conditions to their system-preference defaults.

8 · Errors

Unknown properties, unknown tokens, unknown motions, malformed conditions and bad header shapes are compile errors carrying file, line, message and, where the edit distance is close, a suggestion. Error objects are structured (DSSL.errors()) so tools like the playground can render them. Uncaught selector evaluation failures are contained per-rule and reported once.

9 · Deliberate limits (v0.2)

  • No @import/module graph: bundles merge in load order.
  • Behaviors take no parameters; no loops or user functions.
  • Comma selector lists do not combine with nested state blocks (bind states per-rule instead).
  • Pseudo-element rules accept declarations only.
  • No minification or build step, the engine is the pipeline.
The growth protocol: anything the site needed that the language lacked was added to the language, logged in the changelog with the reason. That is how v0.1 became v0.2.

10 · Versioning

DSSL follows semver for the language surface: new semantic properties, condition kinds and API calls are minor versions; breaking grammar changes are major. The engine reports DSSL.version, currently 0.2.0, “First Light”, ratified and grown during the construction of the site you are reading.