Literate·Reactive·Portable

Write code that
reads like prose.

10x is a Literate programming language. .md files are programs — prose is ignored, expressions evaluate inline, compile to ESM, and power reactive web components.

hello.md LIVE
What is 10x?

You write .md files — headings, paragraphs, bullet lists — and embed expressions anywhere. The interpreter ignores prose and evaluates code directly. The compiler emits a clean ESM module. The runtime powers reactive UIs. One source file, three modes.

.md source Scanner Parser Eval result     Compiler .js ESM
Language

Numbers, units,
ranges & symbols.

Arithmetic and unit conversion are first-class. Ranges expand lazily. Symbols are lightweight tagged values. Every expression returns a result.

unit conversion ranges symbols fractions
primitives.md LIVE
Functions

Lambdas, closures,
and pipe composition.

Functions are first-class values. Multi-arg lambdas with (a b) -> syntax. Pipe sequences with |>. Memoization with bang !.

lambdas closures pipe |> memoize !
add    = (a b) -> a + b.
double = n -> n * 2.
square = n -> n * n.

add(3, 4).
double(7).
square(7).

fib = n ->
  @if (< n 2) 1, (< n 1) 0
  @else fib(n - 1) + fib(n - 2).
fib!(12).
Literate Format

The file is
the program.

10x source files are plain Markdown. Headings and paragraphs become documentation. Code expressions evaluate in order. No special fences or delimiters — the language lives alongside the prose.

.md source prose as docs mixed content literate style
x-counter.md program
# Counter Component
A minimal reactive counter. State lives in a signal, scoped to the component instance.
## State
The counter starts from a start prop when provided.
count = @signal @prop "start" 0.
## View
Renders into shadow DOM. Template subscribes to count automatically.
@render @shadow @html
  <h1 class="count">#{count}</h1>.
## Behavior
Buttons map directly to state transitions.
@on :click "#inc" count = count + 1.
Signals & Reactivity

Reactive state,
automatic re-render.

@signal creates observable state. @computed derives values. @render subscribes automatically — no manual updates ever.

@signal @computed @render @on
signals.md @shadow
count = @signal 0.

@render "#app" @shadow @html
  <div class="sig-root">
    <div class="sig-value">#{count}</div>
    <button id="inc">increment</button>
    <button id="reset">reset</button>
  </div>.

@on :click "#inc" @shadow count = count + 1.
@on :click "#reset" @shadow count = 0.
Web Components

Shadow DOM,
props & scoped state.

Write a .md file, compile to a setup(host) function. Each component instance gets independent signals. Props flow in via @prop. Styles stay scoped.

@render @shadow @prop scoped styles compile → setup()
x-counter.md @shadow
count = @signal @prop "start" 0.

@render @shadow @html
  <div class="ctr-root">
    <div class="ctr-value">#{count}</div>
    <button id="dec">−</button>
    <button id="inc">+</button>
    <button id="reset">reset</button>
  </div>.

@on :click "#inc" @shadow count = count + 1.
@on :click "#dec" @shadow count = count - 1.
@on :click "#reset" @shadow count = @prop "start" 0.
Compiler

Source to portable
ESM in one pass.

The compiler walks the same AST the interpreter uses. Signals, effects, and event handlers become standard JS exports. Output runs in Node, Bun, Deno, and any browser — no runtime overhead.

10x → ESM tree-shaking friendly --bundle flag --alias flag
source
# signals.md
count  = @signal 0.
double = @computed count * 2.
@render "#app" @html
  <h1 class="count">#{count}</h1>.
@on :click "#inc" count = count + 1.
compiled
// signals.md → ESM
export const count = $.signal(0, "count");
const double = $.computed(() => $.read(count) * 2);
$.render("#app", $.html(() =>
  $.h("h1", { class: "count" }, $.read(count))));
$.on("click", "#inc", () => {
  count.set($.read(count) + 1);
});
Modular Runtime

Import only what you need.

Three packages. Zero coupling. Works in Node, Bun, Deno, and browser.

10x/runtime/core
  • signal, effect, read
  • computed, batch, untracked
  • style
  • Pure JS — no DOM dependency
10x/runtime/dom
  • render, renderShadow
  • on, h
  • html template tag
  • Browser-only reactive layer
10x/prelude
  • head, tail, map, filter
  • take, drop, range
  • concat, zip, size
  • Works in all JS runtimes
Tooling Ecosystem

Built to be edited
and extended.

From syntax queries to live reloading — the full language toolchain.

🌲

Tree-sitter Grammar

Full concrete syntax tree. Syntax queries, pattern matching, and structural editing.

shipped
🔭

Language Server

Hover docs, diagnostics, completions. Works in any LSP-compatible editor.

shipped

Zed Extension

Native syntax highlighting in Zed. Powered by the Tree-sitter grammar.

shipped
🔥

Vite Plugin

HMR for .md modules. Import 10x files directly in your Vite project.

shipped

CSS & Styles

Raw CSS strings, object styles, and auto-generated atomic utilities.

@style "body { margin: 0; }".
@style "h1 { color: #2dd4bf; }".
@render "#app" @html
  <div class="flex p-4 gap-2">
    <h1>Hello!</h1>
  </div>.

VDOM Directives

Native somedom attributes: d:*, s:*, and ref.

open = @signal :on.
name = @signal "".
el   = @signal :nil.
@render "#app" @html
  <input d:model={name}
    d:show={open}
    ref={el} />.

Bundler CLI

Bundle local modules and path aliases into a single portable artifact.

10x compile app/main.md --bundle
10x compile app/main.md --bundle \
  --alias "@app=./src"
bun run app.js
node app.js
Playground

See it run.

Edit any snippet — results and signals update instantly.

Quick Start

Up and running
in seconds.

Clone, install, and try the REPL — or feed a .md file directly to the interpreter. The live demo above runs the same engine in your browser.

Read the docs →
# install
bun install

# interactive REPL
bun run repl

# run a program
node bin/cli examples/fib_memo.md

# compile to ESM
10x compile examples/x-counter.md

# browser demo
make demo