Step through your code like a movie — a time-travel debugger that lives in a link.
Live Site · How It Works · FAQ · MIT
Lemma is a zero-installation time-travel debugger for JavaScript, Python, Go, Rust, and C++ that runs entirely in your browser. Write or paste code, click "Record," and get a scrubbable timeline of your program's execution. Inspect variable states, explore syntax trees, and then share the entire interactive session as a single, self-contained URL.
Why? To make debugging, teaching, and understanding code visual, intuitive, and instantly shareable.
- Open the Lab and select a language.
- Write or paste your code into the Monaco-powered editor.
- Click Record.
- For JavaScript, the code executes, and a timeline is generated from every
console.log()snapshot. - For other languages, the code is parsed, and an AST is generated with linting feedback.
- For JavaScript, the code executes, and a timeline is generated from every
- Drag the timeline scrubber to travel through time, watching variables change in the side panel.
- Click Share → a compressed hash (
#h:...) appears in the URL bar. - Copy the URL and send it to someone. When they open it, the exact debugging session is reconstructed in their browser.
- (Optional) Shorten the link using the Supabase-powered shortener.
- True Time-Travel (for JS): It's not a simulation. Scrubbing the timeline shows the actual state of all global variables at that specific point in execution.
- WASM-Powered Core: The JS VM (
quickjs-emscripten), the multi-language parser (web-tree-sitter), and the linter all run as WebAssembly, making analysis fast and entirely client-side. - Privacy by Default: Your code is never sent to a server. Execution, parsing, and sharing via URL hash all happen locally. Nothing leaves your device unless you explicitly create a short link.
- Frictionless Sharing: No sign-ups, no accounts, no backends. Just copy the URL.
https://lemma-anchor.vercel.app/lab#h:<base64-gzipped-project-state>
│
└─ starts with h: (hash).
https://lemma-anchor.vercel.app/s/<nanoid>
│
└─ starts with s: (short link).
Short link flow:
/s/XYZ123 --(Next.js Middleware)--> [Fetches from Supabase] --(302 Redirect)--> /lab#h:<veryLongPayload>
- The project state (code, language) is serialized to a JSON string.
- The string is compressed using
pako(Gzip). - The compressed bytes are Base64 encoded and placed in the URL fragment after
#h:. - On page load, the process is reversed: the hash is read, decoded, decompressed, and used to hydrate the application's state.
- JS Execution: The code runs in a QuickJS VM. A custom
console.logfunction is injected, which captures a snapshot of the VM's entire global scope at that moment, creating a "step" on the timeline. - AST Parsing: For other languages, Tree-sitter WASM parsers generate a syntax tree, which is then analyzed by a lightweight linter.
| Area | Purpose |
|---|---|
| Code Strip | Monaco editor with language selection and Vim mode toggle. |
| Timeline Strip | A scrubbable timeline with ticks for each execution step and badges for linter issues. |
| Variables Strip | For JS: a live view of the global scope, with changed values highlighted. For others: an AST explorer. |
| Toolbar | Main controls: Record, Stop, Reset, and Share. |
| Share Dialog | Generates the shareable link, provides a Supabase shortener, and offers a Markdown badge. |
- Execution & Time-Travel: JavaScript / TypeScript
- AST Parsing & Linting: Python, Go, Rust, C++
To add static analysis for a new language, you would need to:
- Obtain a pre-compiled
tree-sitter-<lang>.wasmgrammar file. - Place it in the
/public/wasm/directory. - Add the language to the
LANGUAGESarray insrc/types/index.ts. - (Optional) Add new linting rules for it in
src/lib/linter.ts.
- URL Length: Very large projects (over ~10MB) can create URLs that are too long for some browsers or platforms. The UI is designed to guide users toward GitHub Gists (a planned feature) for these cases.
- JS Execution: The QuickJS sandbox has no network or file system access for security. Execution is limited to a few seconds to prevent infinite loops.
- The URL fragment (
#...) is not sent in HTTP requests. The server never sees your code when sharing via hash. - No analytics are performed on editor contents.
- Using the optional Supabase shortener sends only the long URL (containing the compressed code) to Supabase to create the link.
Q: Can I collaborate in real time?
A: Not yet. Lemma is designed for asynchronous sharing.
Q: Can I execute Python, Go, etc.?
A: No. Execution with time-travel is currently only supported for JavaScript. Other languages receive static analysis (AST parsing and linting).
Q: How big can a project be?
A: The URL hash method is reliable up to about 10MB. Beyond that, a planned Gist export feature will be recommended.
Q: Why not just use JSFiddle or CodePen?
A: Lemma's focus is not on live web output, but on the internal execution flow. It's a debugging and learning tool designed to make the process of code execution transparent.
The sharing pipeline is simple and robust:
{ code, language } → JSON.stringify()
→ pako.gzip()
→ base64Encode() → #h:<payload>
The Supabase shortener stores the entire long URL (e.g., https://...#h:payload) in a single text column, keyed by a nanoid. The Next.js middleware reads this and issues a 302 redirect, making the short link ephemeral.
MIT — See LICENSE.
Next.js · Monaco Editor · Tree-sitter · QuickJS · Supabase · Zustand · Framer Motion · The open source community.
Open for local development & contribution details
git clone https://github.com/your-username/lemma.git
cd lemma
npm installCreate a .env.local file in the project root and add your Supabase credentials for the URL shortener feature.
NEXT_PUBLIC_SUPABASE_URL=...
NEXT_PUBLIC_SUPABASE_ANON_KEY=...
The web-tree-sitter library requires its core WASM and JS files to be manually available as static assets.
- Copy
node_modules/web-tree-sitter/tree-sitter.wasm→/public/tree-sitter.wasm - Copy
node_modules/web-tree-sitter/tree-sitter.js→/public/tree-sitter.js
npm run devThe site will be available at http://localhost:3000.
- In your Supabase project, create a table named
lemma_short_links. - Columns:
id(type:text, is primary key)long_url(type:text)created_at(type:timestamptz, default:now())
- Deploy the Edge Function located at
supabase/functions/shorten-url/index.tsto your Supabase project.
Made with ❤️ by Anchor