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
900px t
Edit
Point at anything in the page to see its box, its lookup path and the line that made it.

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.

src/pages/profile.layrOpen in playground
Page(
  .name(Profile)
  .route('/')
  Scaffold(
    .body(
      Row(
        .config(
          w: fill
          gap: 16
          padding: all(24)
          yAlign: mid
        )
        Container(
          .config(
            size: 56
            color: accent
            cornerRadius: 999
          )
        )
        Column(
          .config(
            w: fill
            gap: 4
          )
          Text(
            .config(
              size: 18
              weight: semibold
            )
            .obj('Ada Lovelace')
          )
          Text(
            .config(color: muted)
            .obj(
              'Analyst, Analytical Engine'
            )
          )
        )
      )
    )
  )
)

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.

mPhone390 × 844
tTablet834 × 1194
wDesktop1440 × 900

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.

src/pages/store.layrOpen in playground
Page(
  .name(Store)
  .route('/')
  Scaffold(
    .body(
      Container(
        .id(card)
        .config(
          w: 260
          !mut color: panel
          cornerRadius: 12
          padding: all(16)
          .border(
            color: line
            width: 1
          )
        )
        .obj(
          Column(
            .config(gap: 4)
            Text(
              .config(
                size: 15
                weight: semibold
              )
              .obj('Order 1042')
            )
            Text(
              .config(
                size: 13
                color: muted
              )
              .obj(
                'Two items, ships Monday'
              )
            )
          )
        )
      )
    )
  )
)

Extract(
  .from(Store.card)
  .exeOrder(-1)
  insets base = card.padding
)

Inject(
  .into(Store.card)
  .exeOrder(0)
  card.padding = base * 2
)

Inject(
  .into(Store.card)
  .exeOrder(1)
  card.padding = card.padding + all(4)
)

Store.card

live

Order 1042

Two items, ships Monday

Store.carddeclared
padding: all(16)
InjectexeOrder(0)
InjectexeOrder(1)
InjectexeOrder(2)
Resolvedwhat renders
padding:
color:

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

src/pages/checkout.layrOpen in playground
Page(
  .name(Checkout)
  .route('/')
  Scaffold(
    .body(
      Container(
        .id(card)
        .config(
          !mut color: panel
          padding: all(24)
          widht: 320
        )
      )
    )
  )
)

Inject(
  .into(Checkout.card)
  card.color = accent
)

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

src/pages/stats.layr
import { useQuery } from '@tanstack/react-query'
import { LineChart, Line } from 'recharts'
import { getVisits } from './api.ts'

Page(
  .name(Stats)
  .route('/stats')
  .react { const q = useQuery({ queryKey: ['visits'], queryFn: getVisits }) }
  Scaffold(
    .body(
      Column(
        .config(
          gap: 12
          padding: all(24)
        )
        Text(
          .config(type: h2)
          .obj('Visits')
        )
        LineChart(
          .config(
            w: fill
            h: 240
          )
          .props(data: q.data)
          .obj(Line(.props(dataKey: 'n')))
        )
      )
    )
  )
)

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.

# Once per project: the rules, the canonical form, every widget and diagnostic
$layr skills install
✓ LAYR Skill 3.3.0 → .claude/skills/layr
✓ added the LAYR section in AGENTS.md
# Then ask for anything. The agent checks its own work with the compiler
›Build a pricing page in LAYR with three plans that stack on phones. Run layr format and layr analyze --json, and fix every diagnostic before you finish.

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