The itch that started it

Every JavaScript framework asks you to learn its dialect of JavaScript — JSX here, a template syntax there, a signals API that's almost like the last one but not quite. None of that is wrong. But after enough projects, the pattern becomes visible: the framework is a layer of ceremony sitting on top of a much smaller set of real ideas — state, reactivity, and a tree of elements.

Kittine started from a simple bet: what if the syntax for those ideas was designed first, and the implementation underneath was borrowed from something already excellent — rather than the other way around?

The core decision: Kittine is not a from-scratch runtime. A .kitty file compiles to idiomatic Leptos 0.7 Rust source, which then compiles to WebAssembly through the normal Rust toolchain. Kittine owns the syntax. Leptos owns the reactivity engine, the renderer, and the routing. We didn't want to reinvent either of those — we wanted a friendlier front door to them.

Why not just use Leptos directly?

Leptos is genuinely excellent — a fine-grained reactive UI framework for Rust that compiles to WebAssembly, competitive with React and Solid on performance. But writing raw Leptos means writing Rust: explicit signal types, move || closures wrapped around anything reactive, lifetime-aware component props, and JSX-flavored macros that still carry Rust's syntax weight.

That's a reasonable cost for a systems-minded Rust team. It's a real barrier for a small business, a solo builder, or a fast-moving client project where the priority is shipping a feature, not managing borrow-checker friction in a view template.

Kittine's syntax reads closer to a lightweight scripting language — Python-style indentation for control flow, plain HTML elements sitting directly next to Kittine's own tags, and a signal declaration that reads like an assignment: <{count}> >> #n 0. The compiler resolves that down to the exact same let (count, set_count) = signal(0.0); a hand-written Leptos file would use — nothing is hidden, nothing is magic, it's just written in fewer, plainer symbols.

Not a from-scratch ecosystem, on purpose

A lot of custom languages fail the moment a project needs something the language's author didn't think of. Kittine's answer to that: plain HTML elements, and real Leptos/Rust items like leptos_router's components, are first-class inside a .kitty file right alongside Kittine's own syntax. You're never boxed in. If Kittine doesn't have a construct for something yet, you reach past it into the framework underneath — the same framework every generated file already compiles down to.

That single decision is why Kittine could stay small while still being useful for real applications — a signal-backed counter, conditional rendering with if>/orif>/else>, list rendering with a spin loop, dynamic routes read from use_params_map(), structs and generics via litter/breed/claw — all of it compiling to Rust a Leptos developer would recognize on sight.

Compiling to WebAssembly, not interpreting

Kittine doesn't ship an interpreter to the browser. The pipeline is: .kitty source → kittine-compiler (a Rust CLI: lexer → parser → codegen) → a generated .rs file → compiled by cargo/rustc to wasm32-unknown-unknown → post-processed by wasm-bindgen into browser-ready JS glue and a .wasm binary. By the time a user's browser sees any of it, there's no Kittine runtime left at all — just compiled Rust running as WebAssembly, with the exact performance characteristics that implies.

What this actually buys a client project

For BuildsByBuchanan, Kittine isn't a research toy sitting apart from client work — it's one option in the same toolbox as React, Next.js, and Node. When a project's priority is raw runtime performance, a small bundle, or a UI that needs to stay fast on lower-end devices, Kittine is a serious candidate: WebAssembly-compiled Rust under the hood, a syntax that's fast to write and easy to read, and zero lock-in to a custom runtime since the generated output is just Leptos.

The language is also still growing through actual use rather than a roadmap written in a vacuum — when a real project hits a wall Kittine can't yet express, the fix goes into the compiler itself, not around it. That's a deliberate stance: a language stays honest when it's shaped by the software being built with it.

0.7Leptos version Kittine compiles down to
5parts in the monorepo — compiler, Vite plugin, CSR & SSR examples, VS Code extension
Rustis what actually ships to the browser as WebAssembly

Where to go from here

The rest of this series walks through specific parts of Kittine in more depth — how string interpolation grew out of a real client project's need, how the compiler pipeline actually works end to end, and how the same .kitty source serves both a client-rendered app and a server-rendered one. The language reference, formal grammar, and getting-started guide all live in the public repository linked below.