A style language that tells you what you got wrong.

In CSS, a mistyped property is quietly ignored. In DSSL it is an error with the line number and a suggested fix. You also get design tokens as the vocabulary, a cascade you can explain in one sentence, and motion in four words.

It needs JavaScript, and the section below is honest about what that costs.

83 kB gzipped, no dependencies, works with any HTML and any JavaScript.

try.dssl
Waiting for the engine.

One line each, running on this page

None of this is a video or an image. Every effect below is a few words of DSSL applied by the same engine that styles the rest of the site. Move your mouse over the glass.

fire
.torch { use fire }

Fire is a recipe you write once with aura-glow and aura-particle, then reuse by name. Nothing is preset, so every number is yours.

Edit this fire
Frostedfollows the pointer
glass: 18; tilt: 10 glare

glass blurs what is behind it and survives a CSS build. tilt turns toward the pointer and stays in the engine.

Edit this glass
woodmarblecarbonhex
.sofa { texture: wood scale 6 }

Forty textures, ten of them wood species, or build your own from a generator and a few settings. They lay on top of whatever background the element already has.

Edit these textures
slider: graph 20 45 70 90 ...

Range inputs are styled through four vendor pseudo-elements. slider: writes them all from one description, and can turn the track into a histogram.

Edit this slider

Want to see a whole page? Heartwood is a field guide to wood, built with these: generated growth rings, glass, tilt, CSS counters, a fire, and styles compiled to real CSS with dssl build.

Four things CSS leaves to you

The cascade is arithmetic

CSSAn id beats a class beats a tag, then !important beats everyone.

DSSLLater wins, inside layers. That is the whole cascade, and there is no !important to reach for.

Typos fail silently

CSSMisspell background or a variable and the browser quietly does nothing.

DSSLYou get the file, the line and a did-you-mean. The editor above shows exactly that.

Motion needs a paragraph

CSS@keyframes plus an animation shorthand with five values in a fixed order.

DSSLDeclare a motion once, then write animate: rise-in 400 snap.

Theming from JavaScript is a hack

CSSYou poke data attributes or inline styles by hand and hope the cascade agrees.

DSSLDSSL.signal('theme', 'dark') restyles the page, and you can ask the engine why.

The same card, written twice

The DSSL version is about half the characters (141 against 304, ignoring whitespace). It is not fewer lines. It is shorter because the vocabulary does the work: tokens for colour and spacing, one word for a shadow, one number for a transition.

styles.css

.card {
  background-color: var(--card);
  border-radius: 14px;
  padding: 16px;
  box-shadow: 0 2px 4px rgb(0 0 0 / .1),
              0 4px 14px rgb(0 0 0 / .08);
  transition: all 160ms cubic-bezier(.2,.9,.3,1);
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 4px 8px rgb(0 0 0 / .12),
              0 14px 36px rgb(0 0 0 / .12);
}
.card:hover .chip { background: var(--accent-soft); }

card.dssl

.card {
  background: color.card
  radius: md
  padding: space.4
  shadow: md
  transition: 160 snap

  hover {
    translate: 0 -4
    shadow: lg
    .chip { background: color.accent/12 }
  }
}

This page has no CSS file

The engine matches selectors against the live DOM, runs its own cascade and drives motion through the Web Animations API. Pseudo-elements are the one exception: they compile to a generated stylesheet, because inline styles cannot reach them.

Its own cascade
Later wins. Layers when you care. No specificity score, and no !important, ever.
Tokens as vocabulary
color.ink, space.4, radius.md. References compile to custom properties you can inspect.
Readable states
hover, focus-visible and active are blocks. Rules nested under a state just work.
One-word conditions
@media dark, @media 768, @media 480..960. The same shape for @container and @signal.
Motion in four words
animate: rise-in 400 snap both. Add seen and stagger to reveal a grid on scroll. Reduced motion is respected by default.
Behaviors
Name a pattern once, like a focus ring or a chip, and use it anywhere with one line.
Loud errors
Unknown property, unknown token, bad value. Each one names the file and line and suggests a fix.
Texture, aura and sliders
Forty textures, ten of them real wood species, light and particles with no presets (you build the fire), and one-line range sliders. The VS Code extension has a designer with sliders and live previews.
A JavaScript bridge
DSSL.signal restyles live, DSSL.replay reruns motion, DSSL.compile powers tools like the VS Code extension.

Where DSSL is the wrong tool

DSSL is experimental and moving fast. It suits creative sites, prototypes, docs, playgrounds and internal tools. Here is what to weigh before you pick it.

  • It needs JavaScript. With no JavaScript there are no styles, because there is no CSS to fall back to.
  • Styles arrive after the engine loads. A big page can flash unstyled. This site avoids it by putting its stylesheets inside the HTML.
  • Strict CSP blocks it. A policy that forbids inline styles stops the engine from working.
  • Inline styles are heavy. In our test, 3000 small cards came to about 4.5 times the HTML of the same page with a CSS class.

If a page has to work without JavaScript, build the part of DSSL that can be plain CSS. dssl build turns tokens, states, media queries and layers into a real .css file. @signal rules and animate: stay in the engine, and the report counts them so you know exactly what was left behind.

terminal
node cli/dssl.mjs build styles.dssl -o styles.css
node cli/dssl.mjs check styles.dssl --strict   # for CI

Install

The engine is a folder of plain JavaScript files. No package manager, no build step, nothing installed globally. Any of these gives you a dssl-engine folder with the engine, a starter token set, an example stylesheet and a usage guide.

macOS, Linux and BSD

terminal
curl -fsSL https://dssl-sable.vercel.app/install.sh | sh

Plain sh is enough. It uses curl or wget, whichever you have, and unpacks with tar, falling back to unzip or python3.

Windows

powershell
irm https://dssl-sable.vercel.app/install.ps1 | iex

PowerShell 5.1 or newer, no admin rights needed.

No terminal

The exact package the one-liners fetch. Unzip it anywhere and read USAGE.md.

Then wire it into a page

your page
<script type="module" src="/dssl/boot.js"></script>
<link rel="stylesheet/dssl" href="/styles/tokens.dssl">
<link rel="stylesheet/dssl" href="/styles/hello.dssl">

The engine fetches your .dssl files, walks the DOM and keeps restyling as elements come and go. Inline sheets work too, with <style type="text/dssl">. The docs cover the rest.