Get started with scrml
Install the compiler, write your first
.scrml file,
run the dev server, ship a build.
Prerequisites
scrml's reference compiler runs on Bun. Bun is the only required runtime — no Node, no separate package manager, no bundler.
curl -fsSL https://bun.sh/install | bash
Verify the install. The compiler requires Bun 1.3.13 or newer:
bun --version
Install scrml
Until the npm package lands, install from source. Two
installs, not one — a couple of the compiler's
dependencies are declared in the nested
compiler/
manifest rather than the root one:
git clone https://github.com/bryanmaclee/scrml
cd scrml
bun install
cd compiler && bun install && cd ..
Link the
scrml
CLI onto your
PATH:
bun link
Confirm it works:
scrml --version
Hello, scrml
Create a file
hello.scrml:
<program>
<div class="flex flex-col items-center justify-center min-h-screen gap-4">
<h1 class="text-4xl font-bold">Hello, scrml</h1>
<p class="text-lg text-gray-600">No framework. Just output.</p>
</div>
</program>
Compile:
scrml compile hello.scrml -o dist/
That produces
dist/hello.html,
dist/hello.css,
and
dist/hello.client.js.
Open the HTML in a browser. There is no framework runtime
on the page — the compiler emits only the JS that
your specific program needs.
Reactivity in 30 seconds
Add state and event handlers. The
<x> = init
shape declares a reactive cell;
@x
reads it,
@x = expr
writes it. Any DOM read of
@x
re-renders automatically on write.
<program>
<count> = 0
<step> = 1
function increment() { @count = @count + @step }
function decrement() { @count = @count - @step }
function clearCount() { reset(@count) }
<div class="flex flex-col items-center gap-6 p-8 min-h-screen">
<h1 class="text-3xl font-bold">Counter</h1>
<p class="text-6xl font-bold text-blue-600">${@count}</p>
<div class="flex gap-2">
<button class="px-5 py-2 bg-red-500 text-white rounded" onclick=decrement()>−</button>
<button class="px-5 py-2 bg-gray-200 rounded" onclick=clearCount()>Reset</button>
<button class="px-5 py-2 bg-green-500 text-white rounded" onclick=increment()>+</button>
</div>
<label class="flex items-center gap-2 text-sm">
Step:
<input type="number" class="w-16 p-1 border rounded" bind:value=@step min="1" max="100">
</label>
</div>
</program>
Five things to notice:
-
No store wrapper.
<count> = 0is reactive on declaration. NouseState, nowritable(), noref(). -
No JSX.
The markup IS the language. Curly braces inside
${ }evaluate; everywhere else they're text. -
Standard event names.
onclick=decrement()— no@click,(click), oronClick. -
Two-way binding without a directive.
bind:value=@stepwires the input's value both ways. - Tailwind out of the box. Utility classes work with no setup — the compiler scans your markup and emits only the CSS you use.
Dev server with hot reload
scrml dev
Boots a local server on
localhost:3000,
watches every
.scrml
file in the directory, and triggers a recompile + browser
reload on every save. Compile errors print to the terminal
with a line/column pointer.
Custom port and output dir:
scrml dev . --port 3100 -o dist/
Build for production
scrml build
Produces optimised HTML, CSS, and JavaScript under
dist/,
content-addressed so cache invalidation is automatic. The
v0.3 release ships per-route per-role chunk splitting
— an unauthenticated visitor downloads only the
unauthenticated bundle; an
admin
visitor downloads only the admin bundle.
Where to go next
- <engine> — state machines as a first-class element. The Tier 2 form of "UI as a fully-handled state machine."
- ?{ … } — SQL as syntax. No ORM. The server boundary disappears.
- <errors of=…/> — the auto-synthesised validity surface. Validation lives on the type, not on a separate Zod- style schema.
- Reference — every element, keyword, context, and error code.
- Articles — long-form essays on the design decisions.
Standing notes
-
No null, no undefined.
scrml has no
nullliteral and noundefinedconcept. Usenotto express absence and""·0·[]for empty values. -
Cells declare with
<x> = initat top level. Inside${ }logic context, the assignment-form@x = initalso declares. -
One file format.
Markup, logic, styles, server functions, SQL, all in
the same
.scrmlfile. The compiler decides what runs where.