Write, compile and run code online. A zero-backend online coding environment
CodeLab brand mark — public/favicon.png / favicon.ico
- What is CodeLab?
- Live Preview / Screens
- How It Works — Diagrams & Flows
- Repository Structure
- Tech Stack
- Features (FR-01–FR-10)
- Getting Started
- Usage & Code Snippets
- Embed URL Contract (OneCompiler)
- Design System
- Configuration
- Deployment
- Testing, Security, Performance
- Known Issues
- Roadmap
- Documentation Suite (
documents/) - Contributing / Development Guidelines
- License & Acknowledgements
CodeLab is a static, zero-backend online compiler shell:
- Next.js App Router route
/(codelab/src/app/page.tsx+layout.tsx) renders a single full-viewport window. CodeEditorcomponent (codelab/src/components/CodeEditor.tsx) draws the macOS-style window chrome (traffic-light dots + title + status) and embeds the real editor/runner in an<iframe id="onecompiler">.- OneCompiler does all the work — editing, compiling, running. CodeLab servers never touch user code. There is no API route, database, auth, or state store in this repo (verified — see
documents/latex/sections/technical-requirements.tex).
Two frontends exist in the repo:
| Surface | Location | Description |
|---|---|---|
| Static prototype | ../index.html |
Single-file Inter + custom CSS prototype. Centered card (16px radius + deep shadow), hero + 3 features + footer. Embed URL: https://onecompiler.com/embed/?theme=dark&hideTitle=true&codeChangeEvent=true. |
| Production Next.js app | ./src/ |
Full-bleed h-dvh layout, Tailwind chrome, Geist fonts, typed buildOneCompilerSrc() URL builder. Default route / renders <CodeEditor /> with defaults. |
Scope honesty (per
documents/README.md): PRD/roadmap items are reconstructions, performance claims are INFERRED (no measurements), and BRD / backend / DB / ERD / API reference / auth / CI-CD / AEO-GEO docs are intentionally omitted — no evidence in repo.
| Asset | Path (relative to repo root) | Used in |
|---|---|---|
| App icon (PNG) | favicon.png / codelab/public/favicon.png |
Browser tab, README header above |
| App icon (ICO) | favicon.ico / codelab/public/favicon.ico |
layout.tsx metadata.icons + manual <link> |
| Template SVGs (unused) | codelab/public/{file,globe,next,vercel,window}.svg |
Dead weight from create-next-app — unreferenced, safe to prune |
<!-- How the logo is wired (codelab/src/app/layout.tsx) -->
export const metadata: Metadata = {
title: "CodeLab — Online Compiler",
description: "Write, compile and run code online with CodeLab.",
icons: { icon: "/favicon.ico" },
};┌─────────────────────────────────────────────────┐
│ ● ● ● Code Lab Compiler 🟢 Ready to compile │ ← CodeEditor header
├─────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ OneCompiler iframe (#onecompiler) │ │
│ │ - language picker (theirs) │ │
│ │ - editor + stdin + Run button (theirs) │ │
│ │ - output / result pane (theirs) │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────┘
Full-viewport h-dvh, bg #070b12
Prototype (index.html) differs: centered min(1400px, 100%-32px) card, border-radius: 16px, hero headline + badge + 3 feature cards. The Next.js port intentionally went full-bleed (no radius/shadow).
Mermaid sources live in documents/latex/diagrams/*.mmd. GitHub renders the blocks below natively; run mmdc to bake PNGs for Word/PDF builds (see Documentation Suite).
flowchart LR
User([User browser]) --> Next["Next.js static route /<br/>layout + page + CodeEditor chrome"]
User --> OC["OneCompiler embed (iframe)<br/>editor + runner"]
Next -. "no user code<br/>touches server" .-> Server[(No CodeLab backend)]
OC -- "executes user code<br/>third-party" --> OC
Read it as: browser fetches a static page from CodeLab, then talks directly to onecompiler.com inside the iframe. CodeLab never sees keystrokes or run output.
flowchart TD
A["Open /"] --> B["See full-viewport<br/>editor window"]
B --> C["Type code<br/>(inside OneCompiler iframe)"]
C --> D["Run (OneCompiler UI)"]
D --> E["See output<br/>(inside iframe)"]
There is no CodeLab-side Run button, save, login, or share step — all interaction after paint happens inside the third-party iframe.
flowchart TD
P["page.tsx<br/>Home"] --> C["CodeEditor<br/>props"]
C --> B["buildOneCompilerSrc()<br/>language, codeId, theme,<br/>fontSize, 12 flags"]
B --> URL["embed URL string"]
S["src prop (optional override)"] -. "bypasses builder" .-> URL
URL --> IF["iframe#onecompiler"]
C --> HD["header chrome<br/>title + status (static)"]
One-way data flow only: props → iframeSrc string → iframe src attribute. CodeEditor is a React Server Component (no "use client", no hooks, no listeners).
sequenceDiagram
participant B as Browser
participant N as Next.js / route
participant O as OneCompiler embed
B->>N: GET /
N-->>B: layout + page + CodeEditor HTML + iframe src URL
B->>O: GET https://onecompiler.com/embed?... (iframe)
O-->>B: editor + runner UI
Note over B,O: Type → Run → Output stays inside iframe.<br/>CodeLab chrome never re-renders.
codelab/ ← git root
├── index.html ← static prototype (Inter, custom CSS, hero+features)
├── favicon.ico / favicon.png ← brand mark (mirrored in codelab/public/)
├── codelab/ ← Next.js 16 App Router app (this README lives here)
│ ├── src/
│ │ ├── app/
│ │ │ ├── layout.tsx ← <html> shell, Geist fonts, metadata
│ │ │ ├── page.tsx ← route / → <CodeEditor />
│ │ │ └── globals.css ← @import "tailwindcss" (+ unused template vars)
│ │ └── components/
│ │ └── CodeEditor.tsx ← chrome + buildOneCompilerSrc() + iframe
│ ├── public/
│ │ ├── favicon.ico / favicon.png ← <img src="./public/favicon.png"> (you are looking at it ↑)
│ │ └── *.svg ← unused create-next-app leftovers
│ ├── package.json / next.config.ts / tsconfig.json / eslint.config.mjs
│ └── AGENTS.md ← Next.js agent rules (breaking-changes notice)
└── documents/ ← LaTeX doc suite (see below)
├── README.md ← suite index + build instructions + gaps
├── latex/
│ ├── main.tex / preamble.tex / metadata.tex
│ ├── sections/ ← 22 .tex section files
│ └── diagrams/ ← system-context.mmd, user-flow.mmd, component-flow.mmd
└── output/ ← generated DOCX/PDF go here (git-ignored)
Verified against manifests on 2026-10-10 (documents/latex/sections/technical-requirements.tex):
| Category | Technology | Evidence |
|---|---|---|
| Framework | Next.js 16.4.0 (App Router) |
codelab/package.json; next.config.ts enables cacheComponents, partial prefetching |
| UI runtime | React 19.3.0 + react-dom 19.3.0 |
package.json |
| Language | TypeScript 5, strict |
tsconfig.json (strict:true, jsx:react-jsx, @/* alias) |
| Styling | Tailwind CSS 4 via @tailwindcss/turbopack |
globals.css → @import "tailwindcss" |
| Fonts | Geist + Geist Mono via next/font |
layout.tsx (prototype used Inter via Google Fonts) |
| Lint | ESLint 9 + eslint-config-next |
eslint.config.mjs, npm run lint |
| Runtime embed | OneCompiler iframe | CodeEditor.tsx → EMBED_BASE = "https://onecompiler.com/embed" |
Explicitly absent (verified by file search — documenting them would be fabrication): backend/API routes, database/ORM, auth, state library, test runner, CI/CD/Docker, .env config.
Traceable to code (documents/latex/sections/functional-requirements.tex):
| ID | Requirement | Evidence |
|---|---|---|
| FR-01 | Full-viewport compiler window on / |
page.tsx → CodeEditor in h-dvh overflow-hidden |
| FR-02 | Embed OneCompiler via iframe | CodeEditor.tsx:174-181, iframe#onecompiler |
| FR-03 | Hide remote title + enable code-change events by default | hideTitle=true, codeChangeEvent=true |
| FR-04 | Pre-select language via URL path | language prop → /embed/{language} |
| FR-05 | Preload saved code via code id | codeId prop → /embed/{language}/{codeId} |
| FR-06 | Theme + font-size selection | theme, fontSize (clamped 8–32) |
| FR-07 | Hide chrome elements | hideNew, hideRun, hideStdin, hideResult, … |
| FR-08 | Full URL override | src prop bypasses builder |
| FR-09 | Static window title + status | title="Code Lab Compiler", statusText="Ready to compile" |
| FR-10 | Hide status on narrow screens | max-sm:hidden |
Out of scope: persistence, CodeLab-side Run, server compilation.
Prerequisites: Node.js + npm (versions not pinned — recommended: add .nvmrc or packageManager field).
# 1. Move into the Next.js app (NOT the repo root)
cd codelab
# 2. Install
npm install
# 3. Develop (http://localhost:3000)
npm run dev
# 4. Lint (quality gate)
npm run lint
# 5. Production build + type-check
npm run build
# 6. Serve the production build
npm startOther package managers (same scripts):
yarn dev # or: pnpm dev / bun devStatic prototype (no build needed):
# open directly, or serve to allow the iframe + fonts:
npx serve C:/Dev/codelab -l 8080
# → http://localhost:8080/index.html
next buildstatically prerenders/as static content (verified 2026-10-10). No Dockerfile / CI / platform manifest exists — hosting (Vercel, Netlify, self-hosted Node) is an operator choice.
// src/app/page.tsx (actual code)
import CodeEditor from "@/components/CodeEditor";
export default function Home() {
return (
<div className="flex h-dvh w-full flex-col overflow-hidden bg-[#070b12] font-sans text-slate-50 antialiased">
<main className="m-0 flex min-h-0 w-full flex-1 flex-col p-0">
<CodeEditor />
</main>
</div>
);
}Renders iframe src (defaults): https://onecompiler.com/embed?theme=dark&hideTitle=true&codeChangeEvent=true — plus availableLanguages/listenToEvents depending on caller (see Known Issues).
<CodeEditor language="python" title="Python Playground" />
// → https://onecompiler.com/embed/python?theme=dark&hideTitle=true&codeChangeEvent=true<CodeEditor language="javascript" codeId="3wyne344h" />
// → https://onecompiler.com/embed/javascript/3wyne344h?theme=dark&...<CodeEditor theme="light" fontSize={16} statusText="Python 3.12 • Ready" />fontSize is clamped to 8–32 (clampFontSize); omitted → OneCompiler default (14).
<CodeEditor
language="python"
hideLanguageSelection
hideNew
hideNewFileOption
hideEditorOptions
disableCopyPaste
/><CodeEditor
title="Pinned snippet"
src="https://onecompiler.com/embed/python/3wyne344h?theme=dark&hideTitle=true"
/>import { buildOneCompilerSrc } from "@/components/CodeEditor";
const url = buildOneCompilerSrc({
language: "java",
theme: "dark",
fontSize: 99, // → clamped to 32
hideRun: true,
codeChangeEvent: true,
});
console.log(url);
// https://onecompiler.com/embed/java?theme=dark&fontSize=32&hideTitle=true&hideRun=true&...
⚠️ Known quirk:buildOneCompilerSrc()defaultsavailableLanguages=true, listenToEvents=true, but the<CodeEditor>component defaults both tofalse. Helper output ≠ default render URL. Align before relying on it in docs/tests.
| Prop | Type | Default | Notes |
|---|---|---|---|
title |
string |
"Code Lab Compiler" |
Window header text |
statusText |
string |
"Ready to compile" |
Static — never updates (see issues) |
src |
string |
— | Full override; ignores all builder props |
language |
string |
"" |
Sanitized (/ stripped) → /embed/{language} |
codeId |
string |
"" |
Sanitized → /embed/{language}/{codeId} |
theme |
"dark" | "light" |
"dark" |
?theme= |
fontSize |
number |
— | 8–32, else clamped; omitted = default 14 |
hideTitle / hideLanguageSelection / hideNew / hideRun / hideNewFileOption / hideEditorOptions / hideStdin / hideResult |
boolean |
hideTitle=true, rest false |
Appended as ?flag=true when true |
disableCopyPaste / disableAutoComplete |
boolean |
false |
Same ?flag=true pattern |
availableLanguages / codeChangeEvent / listenToEvents |
boolean |
component: false/true/false; helper: true/true/true |
|
id / className |
string |
"compiler" / "" |
Section anchor + extra classes |
Single integration in the repo. Public options reference: https://onecompiler.com/apis/embed-editor.
https://onecompiler.com/embed[/<language>[/<codeId>]]?theme=<dark|light>&fontSize=<8-32>&<flag>=true...
| Flag | Effect |
|---|---|
hideTitle |
Hide OneCompiler title bar |
hideLanguageSelection |
Lock language picker |
hideNew / hideNewFileOption |
Hide new-file affordances |
hideRun |
Hide their Run button |
hideEditorOptions |
Hide editor settings |
hideStdin / hideResult |
Hide stdin / output panes |
disableCopyPaste / disableAutoComplete |
Restrict editing aids |
availableLanguages |
Advertise language list |
codeChangeEvent |
Embed posts code-change events |
listenToEvents |
Embed accepts incoming messages |
DOM contract: <iframe id="onecompiler" title="Online Code Compiler" loading="lazy" allow="clipboard-read; clipboard-write">. Programmatic API today is intent flags only — no window.onmessage receiver and no postMessage sender exist in this repo.
If onecompiler.com is unreachable the chrome still renders with an empty editor area — no fallback UI (tracked in Known Issues).
Values extracted verbatim from code (no Figma/token file exists):
| Token | Value / Location |
|---|---|
| Page bg | #070b12 (page.tsx; prototype added indigo/cyan radial gradients) |
| Editor surface | #0f172a header @85% + iframe surround (CodeEditor.tsx) |
| Borders | white/[0.08] hairline under header |
| Dots | bg-slate-600 10px circles; status bg-green-500 + green glow |
| Typography | Title 14px semibold slate-50; status 12px slate-400; Geist sans via next/font (prototype: Inter) |
| Header metrics | px-18px / py-15px desktop, p-3 mobile; backdrop-blur-14px |
| Radius / shadow | Full-bleed — none (prototype: 16px radius + deep shadow card) |
| Breakpoints | Tailwind defaults; explicit max-sm (640px) adaptations |
No button/input/card/modal/table/icon subsystem exists in the app.
| Item | Status |
|---|---|
Env vars (.env*) |
None — no .env* files; .gitignore merely ignores them |
| Runtime config | All behavior via component props (see table above) |
| Next.js flags | cacheComponents: true, partialPrefetching: true, Turbopack CSS rule (next.config.ts) |
| Fonts | Geist + Geist_Mono (layout.tsx) |
cd codelab
npm install
npm run build # → "Static prerendered as static content" for /
npm start # serve production| Concern | Status |
|---|---|
| Hosting target | Operator choice (Vercel / Netlify / self-hosted Node / static export) — no manifest in repo |
| DB migrations / rollback | NOT APPLICABLE |
| Prod env config | NOT APPLICABLE |
| CI / Docker / IaC | NOT APPLICABLE — none present |
- Testing: NOT APPLICABLE as-implemented — no test files, scripts, or configs. Recommended strategy (from
documents/): unit-testbuildOneCompilerSrc(incl.clampFontSize+/-stripping + default parity) + smoke-test/rendersiframe#onecompilerwith expectedsrc. - Security: static page + third-party iframe. Review table in
documents/latex/sections/security.tex. Key notes:allow="clipboard-read; clipboard-write"is the only permission;language/codeIdstrip/before interpolation; no secrets to leak (no env). User code executes on OneCompiler infrastructure, never on CodeLab hosts. - Performance: INFERRED only — no measurements exist. Static prerender +
loading="lazy"iframe + Geist subsetting are the only factual optimizations; do not quote metrics.
Verified in code on 2026-10-10 (documents/latex/sections/known-issues.tex):
| Issue | Severity | Impact / Recommendation |
|---|---|---|
Helper/component default mismatch (availableLanguages, listenToEvents) |
Medium | Helper-direct URLs differ from default render. → Align defaults + add unit tests. |
Static statusText |
Low | "Ready to compile" implies liveness. → Drive from embed events or relabel. |
Misplaced <link> in layout.tsx |
Low | Manual favicon tag duplicates icons.icon. → Remove manual tag. |
| Unused template styling/assets | Low | globals.css vars + public/*.svg unreferenced. → Prune or adopt. |
| No embed fallback | Medium | Blank area when OneCompiler unreachable. → Detect iframe failure + guidance UI. |
Per documents/latex/sections/roadmap.tex — split by evidence level:
- EXISTING (in repo): full-viewport embed, URL builder, theme/font-size, hide-flags,
srcoverride. - RECOMMENDED (gaps): default-parity fix + tests, embed-failure UI, live status via embed events, prune dead assets, pin Node version, remove manual
<link>. - POTENTIAL (not committed): multi-file layouts, shareable links, auth/persistence — would require a backend that does not exist today.
The LaTeX suite is the source of truth for claims in this README. Referenced throughout as documents/latex/sections/*.tex.
# PDF (requires TeX Live / MiKTeX)
cd ../documents/latex
latexmk -pdf main.tex # → main.pdf
# Word (Pandoc; standard headings/tables/lists, no custom macros/images by design)
pandoc main.tex -o ../output/CodeLab-Documentation.docx --toc
# Diagrams → PNGs for print builds (Mermaid CLI)
mmdc -i diagrams/system-context.mmd -o diagrams/system-context.png
mmdc -i diagrams/user-flow.mmd -o diagrams/user-flow.png
mmdc -i diagrams/component-flow.mmd -o diagrams/component-flow.pngContents: executive summary, overview, product description, PRD (reconstructed), FR/NFR/technical requirements, software + frontend architecture, integrations, configuration, UI/UX, design system, security, performance, testing, deployment, SEO, known issues, tech debt, roadmap, dev guidelines, glossary. See ../documents/README.md for the section/status table and known gaps.
(documents/latex/sections/development-guidelines.tex doubles as contribution guide.)
cd codelab
npm install
npm run dev # iterate on src/app/page.tsx / src/components/CodeEditor.tsx
npm run lint # must pass before PR
npm run build # must pass (build includes type-check)- App Router conventions;
CodeEditorstays a Server Component unless interactivity is genuinely needed. - Props → URL-string discipline: keep
buildOneCompilerSrcpure and tested;srcremains the escape hatch. - Tailwind utilities for chrome; avoid reviving prototype custom-CSS unless scoped.
- Do not add backend/auth/DB without a design doc — it contradicts the zero-backend architecture above.
- No
LICENSEfile exists in the repo at time of writing — add one before public distribution. - Editor + execution: OneCompiler Embed API.
- Bootstrapped with
create-next-app; fonts vianext/font(Geist). - Brand mark:
./public/favicon.png(favicon.icofallback) — shown at the top of this file via relative path so it renders on GitHub and any static mirror.
This README was drafted from ../documents/README.md + direct code reads (page.tsx, CodeEditor.tsx, layout.tsx, index.html, package.json, *.mmd) on 2026-10-10. Claims without repo evidence are labeled as such — see the documentation suite for the full audit trail.