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.
.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.
16bare number → 16px1.5in unitless props (line-height…): stays 1.5color.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 barecalc(100% - 16)calc-family: bare numbers are px--my-varcustom properties pass through unvalidatedrow: 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: 50font: 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 bothMotion runs on the Web Animations API; re-run with DSSL.replay(sel). Disabled under reduced-motion unless the motion says essential: true.
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 tooRuntime 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.
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.
@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 { … } }later winssource order beats every selectorlayers trump ordertokens < base < components < utilities < pin(default)your rules are components: layers are opt-in@layer utilities { }name a layer when you carepin { } / pin:the one escape hatch, beats everythinginside one blocklater lines win too, put display: none AFTER row:/column:/grid: (they set display: flex)No specificity. No !important. Ever.
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.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.
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 applyAuto-boot: link[rel="stylesheet/dssl"] + style[type="text/dssl"], then window fires dssl-ready.
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"?
}