LAYR · Layout Authoritative Yet Responsive
Build websites deterministically.
A compiled UI language. Write layout in your design’s numbers and ship static CSS and React that resolve the same way on every screen.
Try it in the browser
npx @dynshift/layr create my-app// A studio booking page, the one in the home page's hero. Its colours are theme tokens (canvas,
// panel, ink, accent…), so it wears whichever theme you pick for this site. Resize the window: the
// row stacks when a pane would be squeezed, the chips wrap and every number scales, with no media
// queries written here.
Widget(
.name(DayBar)
.param(req txt day, req num load)
.obj(
Column(
.config(w: fill, gap: 8, xAlign: mid)
Container(
.config(w: fill, h: 96, color: sunken, cornerRadius: 6, objAlign: bottomMid)
.obj(Container(.config(w: fill, h: 96 * param.load, color: accent, cornerRadius: 6)))
)
Text(.config(size: 12, color: muted) .obj(param.day))
)
)
)
Widget(
.name(Slot)
.param(req txt time, bool picked = false)
.obj(
Container(
.config(color: param.picked ? accent : panel, cornerRadius: 8, padding: sym(x: 12, y: 7), .border(color: param.picked ? accent : line, width: 1))
.obj(Text(.config(size: 14, weight: medium, color: param.picked ? onAccent : ink) .obj(param.time)))
)
)
)
Widget(
.name(Booking)
.param(req txt day, req txt time, req txt who, req txt hours)
.obj(
Row(
.config(w: fill, gap: 14, yAlign: mid, padding: only(top: 10), .border(color: line, width: 1, sides: top))
Column(
.config(w: 52, gap: 0, xAlign: mid)
Text(.config(size: 12, color: muted) .obj(param.day))
Text(.config(size: 15, weight: semibold) .obj(param.time))
)
Text(.config(w: fill, size: 14) .obj(param.who))
Text(.config(size: 13, color: muted) .obj(param.hours))
)
)
)
Page(
.name(Room)
.route('/')
.meta(title: 'Room B')
Scaffold(
.config(color: canvas, textColor: ink)
.body(Column(
.config(w: fill, padding: all(24), gap: 20)
Row(
.config(w: fill, xAlign: between, yAlign: mid)
Column(
.config(gap: 2)
Text(.config(size: 13, color: muted) .obj('Studio booking'))
Text(.config(type: h1, size: 26, weight: semibold, letterSpacing: -0.4) .obj('Room B'))
)
Container(
.config(color: accent.alpha(12%), cornerRadius: 999, padding: sym(x: 10, y: 4))
.obj(Text(.config(size: 12, weight: semibold, color: accent) .obj('Available')))
)
)
Row(
.config(w: fill, gap: 20)
Column(
.config(w: fill, color: panel, cornerRadius: 12, padding: all(18), gap: 14, .border(color: line, width: 1))
Text(.config(size: 14, weight: semibold) .obj('This week'))
Row(
.config(w: fill, gap: 8)
DayBar(.config(day: 'Mon', load: 0.35))
DayBar(.config(day: 'Tue', load: 0.7))
DayBar(.config(day: 'Wed', load: 0.5))
DayBar(.config(day: 'Thu', load: 0.9))
DayBar(.config(day: 'Fri', load: 0.6))
)
)
Column(
.config(w: fill, color: panel, cornerRadius: 12, padding: all(18), gap: 14, .border(color: line, width: 1))
Text(.config(size: 14, weight: semibold) .obj('Pick a time'))
Wrap(
.config(gap: 8)
Slot(.config(time: '09:00'))
Slot(.config(time: '10:30', picked: true))
Slot(.config(time: '12:00'))
Slot(.config(time: '14:30'))
Slot(.config(time: '16:00'))
)
Row(
.config(gap: 8)
Button(
.config(color: accent, cornerRadius: 8, padding: sym(x: 16, y: 9))
.obj(Text(.config(size: 14, weight: semibold, color: onAccent) .obj('Book 2 hours')))
)
Button(
.config(cornerRadius: 8, padding: sym(x: 16, y: 9), .border(color: lineStrong, width: 1))
.obj(Text(.config(size: 14, weight: medium) .obj('Details')))
)
)
)
)
Column(
.config(w: fill, color: panel, cornerRadius: 12, padding: all(18), gap: 12, .border(color: line, width: 1))
Text(.config(size: 14, weight: semibold) .obj('Upcoming'))
Booking(.config(day: 'Tue', time: '10:30', who: 'Mixing session', hours: '2 hours'))
Booking(.config(day: 'Thu', time: '14:30', who: 'Podcast recording', hours: '1 hour'))
Booking(.config(day: 'Fri', time: '09:00', who: 'Band rehearsal', hours: '3 hours'))
)
))
)
)Layout you can read in the code.
Objects nest the way they render. The compiler turns the file into static CSS and a React module, and both are yours to read.
The language, step by step
One design, every screen.
Numbers are design pixels from your frames. Values flow between frames and structure steps at them. You write no media queries.
How Design Scale works
Change anything from anywhere, in order.
Extract reads a feature, Inject layers a change at an exeOrder, and !mut protects what must never change. Tick the layers, or untick !mut.
store.layr
Store.card
live
Order 1042
Two items, ships Monday
Export, Extract and Inject
Mistakes explained before they ship.
Every problem has a code, an explanation and a fix. The same checks run in your editor, in the CLI and in CI.
checkout.layr
layr analyze
2 errors
error L3101: `color` of `Checkout.card` is `!mut` and refuses Export/Extract/Inject mutation.--> src/pages/checkout.layr:20:3| card.color = accent| ^^^^^^^^^^error L1002: `Container` has no config key `widht`. Did you mean `w`?--> src/pages/checkout.layr:11:11| widht: 320| ^^^^^
Every diagnostic
Your React packages keep working.
Import a React component and use it as a node; hooks run in a .react block. LAYR components work inside React apps too.
stats.layr
React interop
Learn it and write it with any AI.
LAYR ships its own rules for AI: agents write canonical LAYR and check it with the same tools you use, and any assistant can teach it to you from the docs.
AI agents: the Skill and MCP
Write it in VS Code.
Completion that writes whole calls, wrap and extract refactors, format on save, and diagnostics with fixes, from the same compiler as the CLI.
Addons from the Library.
Official addons ship as LAYR source you can read and eject. Anyone can publish one to npm and list it.
Browse the Library
Start in the browser. Keep it in your repo.
The playground runs the real compiler. When you are ready, one command makes a project.
Try it in the browser
npx @dynshift/layr create my-app