Cheat sheet

Every day-to-day feature of DSSL on one page. When a line here isn't obvious, the docs chapter with the same name has the long version and a live demo.

30-second version
app.dssl
.card {
  background: color.card      // built-in default token
  padding: space.4            // 16px, also built in
  radius: md
  transition: 150

  hover {                     // states are nested blocks
    translate: 0 -4
    shadow: lg
  }

  @media 768 {                // viewport ≥ 768px
    grid: 3
  }
}

Install: <link rel="stylesheet/dssl" href="app.dssl"> + <script type="module" src="dssl/boot.js">. No tokens, layers, or config required, rules land in the components layer by default.

values
16bare number → 16px
1.5in unitless props (line-height…): stays 1.5
color.inktoken reference → var(--dssl-color-ink)
color.ink/40token at 40% alpha (color-mix)
oklch(62% 0.19 35)functions pass through, color fns keep numbers bare
calc(100% - 16)calc-family: bare numbers are px
--my-varcustom properties pass through unvalidated
layout in one word
row: gap 12 center wrap
column: gap 8 start
grid: 3
grid: auto-fill 220
stack: center        // overlay children
center: both         // center: x / center: y, the engine guarantees a
                     // formatting context, so it can never silently no-op
place: center        align: center
cover: fixed         sticky: 0
size: 40 100%        circle: 36
grow: 1              z: 50
text & motion
font: 16/1.4 color.ink    // size / leading / color
fluid: 16, 24             // clamp() 360→1200px
truncate
visually-hidden           // a11y: hidden to eyes, read by screen readers
transition: 150 snap      // all 150ms, named easing
transition: 150 snap background-color, 300 transform
                          // per-property specs
stagger: 60               // children cascade in, i × 60ms

easings: snap smooth bounce ease-in-out…

motion pop { from { opacity: 0; translate: 0 16 } }
animate: pop 400 snap both

Motion runs on the Web Animations API; re-run with DSSL.replay(sel). Disabled under reduced-motion unless the motion says essential: true.

texture, aura, slider, glass, tilt
texture: wood                      // 40 presets; stacks with commas
texture: noise scale 3 color #123 blend multiply   // or your own

aura-glow: #ff7a00 30 pulse 900 flicker 0.3
aura-particle: #fd0 -> #f60 -> rgba(255,40,0,0) 60 up
glow-particle: #fff 30 out         // glowing particles
aura-glow-particle: #7cf 24 count 40 up
aura: glow #f80 30, particles #fd0 count 60   // both slots
aura-glow: none                    // clears one slot; aura: none clears both

behavior fire { aura-glow: ... aura-particle: ... }   // aura has no presets
.torch { use fire }

slider: track 6 #456 radius full, fill #f80, thumb 22 #fff, ring 3 #f80
slider: graph 20 45 70 90 60, graph-height 52   // a histogram slider

glass: 18 saturate 1.6             // frosted glass, plain CSS
tilt: 10 lift 1.04 glare           // follows the pointer, engine only
border: 1 solid white/30           // alpha works on named colours too

Runtime features: dssl build leaves them out and says so. Aura draws on one canvas, stills under reduced motion, and shares a budget of 1800 particles. Open the designer in the VS Code extension to build all three with sliders.

states & selectors
hover { … }        focus { … }
focus-visible { … } active { … }
disabled checked empty open
seen { … }        // engine-native: fires once on scroll-in

// states can restyle descendants too
hover { .tip { opacity: 1 } }

// full CSS selectors work, incl. nesting
.gallery > .tile:nth-child(2n) { translate: 0 -2 }
&.featured { border-color: color.accent }

The engine listens to pointer/focus events itself and re-evaluates entering and leaving the state, no CSS involved.

conditions
@media dark         @media light
@media reduced-motion
@media 768          // ≥ 768px
@media <= 768       // narrower
@media 480..960     // range
@media (width >= 768)   // full CSS form
@container (min-width: 480px)
@signal theme == dark   // JS bridge
@signal ready           // truthy form

// compose by nesting
@media <= 860 { @signal nav == open { … } }
cascade
later winssource order beats every selector
layers trump ordertokens < base < components < utilities < pin
(default)your rules are components: layers are opt-in
@layer utilities { }name a layer when you care
pin { } / pin:the one escape hatch, beats everything
inside one blocklater lines win too, put display: none AFTER row:/column:/grid: (they set display: flex)

No specificity. No !important. Ever.

behaviors & tokens
behavior focus-ring {
  focus-visible { outline: 2 solid color.accent }
}
button { use focus-ring }

tokens {
  color { accent: oklch(62% 0.19 35) }
  space { lg: 24 }
}   // → var(--dssl-color-accent), shared across files

.danger {
  --color.accent: color.err   // re-declare a token per subtree
}                             // descendants re-resolve automatically
deform & gradients
.btn {
  transition: 180 snap transform
  active { bend: 16; stretch: 0.94 }   // flex under the pointer
}
.flag     { bend-y: -18 }              // sideways bow
.mini     { hover { bend-up: 14 } }    // drawbridge
.page     { hover { fold: 14 } }       // folds over the top edge
.pill-row { bend-around: -22 }         // children on a smile arc

.banner {
  gradient: linear 135, color.accent -> color.ok
  gradient-flow: 6s alternate         // the gradient drifts forever
}
.head { gradient-text: linear to right, color.accent, color.ink }

Deform composes into transform, so one transition tweens it and it works in motion keyframes too. stretch keeps volume; gradient stops take tokens, alpha (color.ink/40) and % positions, a stop that is not a color fails loud.

js api
DSSL.load(['/styles/app.dssl'])
DSSL.apply(src, { scope: '#el', name: 'pg', replace: true })
DSSL.compile(src)          // parse+resolve, no DOM
DSSL.signal('theme', 'dark')   // null clears
DSSL.replay(sel)  DSSL.refresh()
DSSL.errors                // from the last apply

Auto-boot: link[rel="stylesheet/dssl"] + style[type="text/dssl"], then window fires dssl-ready.

errors

Unknown property, unknown token, bad value, unclosed block, all refuse to compile with file, line, and a did-you-mean over every known property, token and motion. In the console, or live in the playground error panel.

.badge {
  colour: red             // ✗ did you mean "color"?
  background: color.acnt  // ✗ did you mean "color.accent"?
}