a literate, typed, target-agnostic language
The source is a
document. The document
compiles.
ScalaScript makes Markdown structure real syntax — headings are scopes, fenced blocks are typed code — and lowers one source to the JVM, the browser, WebAssembly, Rust, Swift, and native.
---
name: greeter
targets: [jvm, js, wasm]
---
# greeter
This paragraph is part of the module.
```scalascript
def greet(name: String): String =
s"Hello, $name!"
@main def run(): Unit =
println(greet("world"))
```
how a file reads
Markdown is not decoration.
It is the grammar.
Every structural device you already use in a README carries meaning to the compiler. Nothing new to learn to start; the document you would have written is the program.
Headings define namespaces
A section heading opens a named scope. Nesting headings nests scopes — structure in the prose is structure in the program.
Links are references
A Markdown link resolves to an import or a cross-reference. The web of documents is the module graph.
Fences are typed code
A fenced block is a first-class, type-checked expression unit — Scala-flavored types, checked once at the IR.
Prose can interpolate
Inline ${…} weaves evaluated values back into the text. Documentation and computation share one surface.
one source, many machines
Write once.
Emit everywhere.
Semantics and type-checking are defined a single time at the IR level. A backend is a translator, never a reinterpretation — so the same .ssc means the same thing on every target.
greeter.ssc → six backends
beyond the basics
Typed algebraic effects,
with real handlers.
Effects and multi-shot delimited continuations are part of the language, checked in the type system and running the same across backends. Describe an effect, then decide what it means at the edge.
Self-hosted compiler · Apache-2.0effect Ask:
def ask(): String
def program(): String =
val name = Ask.ask()
s"Hi, $name"
val result = handle(program()) {
case Ask.ask(resume) => resume("Ada")
case Return(x) => x
}
println(result) // Hi, Ada
in your terminal
Run a document.
One CLI takes a .ssc file straight to output, or packages it for a target. No project scaffold required to begin.
$ ssc run greeter.ssc
Hello, world!
$ ssc build-jvm greeter.ssc -o greeter.jar
wrote greeter.jar
$ ssc run --bytecode ask.ssc # native VM lane
Hi, Ada
what you can build
One language,
the whole stack.
Every example is a real, runnable .ssc file in the repository — from a one-liner to a database engine written from scratch.
Hello, world
The smallest program — a typed fenced block inside a Markdown document, run straight to output.
view source ↗ algebraic-effects.sscTyped effects
Logger, State and NonDet as first-class effects with real handlers — checked in the type system, same on every backend.
view source ↗ actors-pingpong.sscActors
spawn / send / receive / self — message-passing concurrency, with a clustered transport over WebSockets.
A SQLite engine
SclJet reads and writes real .db files, byte-for-byte against sqlite3 — no C, no bundled library. More →
A web API
A todo REST API — typed routes, an HTML template literal, and a native reactive server, all in one document.
view source ↗ wasm-fibonacci.sscTo WebAssembly
The same source compiled to WASM — one of six backends the identical .ssc lowers to.
And it's fast: a three-tier interpreter with a JIT, plus AOT lanes to the JVM and native. See the performance notes and benchmark methodology, or browse all 210 examples.