exosys
v0.1.1
Published
A from-scratch web framework written in five custom languages — .exo, .exocss, .exojs, .exouni, .exofont. No React, no Vite, no Tailwind, no third-party fonts.
Downloads
34
Maintainers
Readme
ExoSys — a framework written in five custom languages
ExoSys is a from-scratch web framework where every layer is its own custom DSL:
Install from npm
# Scaffold a new app
npx exosys init my-app
cd my-app
npm install
# Build & serve locally with hot rebuild
npm run dev # http://localhost:3000
# Or just produce the bundle
npm run build # writes public/index.exoThe build emits a single polyglot file at public/index.exo — both a valid HTML document and pure Exo source. Serve it from any static host as text/html.
CLI
exo init <name> Scaffold a new Exo app
exo build Build app/ → public/index.exo
exo dev [--port=3000] Build, serve, and rebuild on changeProgrammatic API
const { build, serve, init } = require('exosys');
build({ projectRoot: process.cwd() });Every layer of ExoSys is its own custom DSL:
| Language | Purpose | Implementation |
|--------------|----------------------------------------|---------------------------------------------------------------------|
| .exo | View language (pages, components) | Hand-written lexer + recursive-descent parser + DOM renderer |
| .exocss | Stylesheet language | Tokens + @mixin + nesting + shorthand props → CSS |
| .exojs | Scripting language | Pratt-precedence parser + tree-walking interpreter |
| .exouni | Emoji ("exoji") system + EUTF-8 | 24 hand-drawn SVG glyphs + custom variable-length byte encoding |
| .exofont | Custom binary glyph font | 3.4 KB binary file, decoded in the browser to inline SVG |
No React. No Vite. No Tailwind. No third-party fonts. Every parser, encoder, decoder, and runtime in this repo was written by hand.
Quick tour
exo-framework/
├── core/ # the framework itself
│ ├── exo.js .exo language (lexer/parser/AST)
│ ├── exocss.js .exocss compiler
│ ├── exojs.js .exojs interpreter
│ ├── exouni.js exoji registry + EUTF-8 + 24 SVG glyphs
│ ├── exofont.js .exofont binary decoder + SVG renderer
│ └── exo-runtime.js store, router, layouts, components, animations, effects
│
├── tools/
│ └── build-font.js Node-side encoder: SVG glyphs → .exofont binary
│
├── font/
│ ├── exouni.exofont the binary font (3,468 bytes, 24 glyphs)
│ └── exouni.exofont.b64.js base64 module inlined into the bundle
│
├── app/ # the demo project tree
│ ├── exo.config.exo @meta + @theme
│ ├── layouts/main.exo global layout with `slot`
│ ├── components/*.exo Hero, Feature, Stat, Step
│ ├── pages/*.exo index, features, exojis, font, docs, playground
│ ├── styles/global.exocss global stylesheet
│ └── scripts/app.exojs global state + actions
│
├── build.js bundler — walks app/, embeds runtime, emits index.exo
└── public/index.exo polyglot output (HTML bootstrap + Exo source)Build
node build.jsThis:
- Walks
app/(config, layouts, components, pages, styles, scripts) - Concatenates everything into one combined Exo source
- Inlines the runtime (
core/*.js) and the binary font (font/exouni.exofont) - Writes
public/index.exo— a polyglot file that's both a valid HTML document and pure Exo source
How it renders
- The browser receives
index.exoserved astext/html(a tiny worker rewrites the content-type) - The HTML bootstrap inlines the entire runtime
Exofont.decode(EXOFONT_B64)walks the 3,468 binary bytes, builds the gradient/animation/glyph tables, and patchesExouni.render()andExouni.rich()- The runtime parses the embedded
.exosource, mounts the router, and renders every page client-side - Every
:heart:,:fire:,:wave:shortcode in any text binding becomes an SVG node painted from the binary
Languages at a glance
.exo (view)
@page "/" layout="main" title="Home" {
@style { .home-cta { grid-cols: 3 } }
@script { state count = 0 action bump { count = count + 1 } }
Hero(eyebrow="…", title="…", subtitle="…")
section {
grid(3) {
Feature(icon=":sparkle:", title=".exo", text="…")
Feature(icon=":diamond:", title=".exocss", text="…")
}
button.primary "Bump :thumbs-up: ({clickLabel})"
on click -> bump()
effect="ripple"
}
}.exocss (stylesheet)
$theme { primary: #7c5cff pad-md: 24 radius: 14 }
@mixin glass {
background: rgba(255,255,255,0.04)
border: 1px solid rgba(255,255,255,0.08)
backdrop-filter: blur(12px)
}
.card {
pad: $theme.pad-md
radius: $theme.radius
@apply glass
&:hover {
border-color: $primary
transform: translateY(-3px)
}
}.exojs (scripting)
state count = 0
state name = "world"
computed greeting = "Hello, " + name + "!"
computed status = count > 10 ? "🔥 on fire" : "warming up"
action bump { count = count + 1 }
action bumpBy(by) { count = count + by }
on mount { log("ready") }
on count.change { if count == 10 { confetti() } }.exouni (exojis)
24 hand-drawn glyphs in three categories — faces, hands, symbols — with codepoints 0xE001..0xE018 and twelve animations (beat, flicker, wave, twinkle, flash, blink, spin, float, bounce, shake, pop, orbit).
.exofont (binary font)
HEADER (16 B):
+0 "EXOF" magic
+4 01 00 version 1.0
+6 03 E8 em-size 1000
+8 00 0F gradient count
+10 00 0D animation count
+12 00 18 glyph count
+14 00 00 flags
GRADIENT TABLE (15 entries)
ANIMATION TABLE (13 entries)
GLYPH TABLE (24 entries) — each layer has fill / stroke / shape
PATH OPS M=0 L=1 C=2 Q=3 Z=4 (int16 coords in em units)Total: 3,468 bytes for all 24 glyphs.
License
MIT — do whatever you want with it.
