Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
30e24d3
first iteration untested
codingfrog27 Jun 22, 2026
cdfed23
feat(playground): redesign Express template demo
rijulshrestha Jun 26, 2026
bced8c1
feat(playground): redesign Nextjs template demo
rijulshrestha Jun 26, 2026
6165057
feat: bump bp version to 2.12.1
rijulshrestha Jun 29, 2026
c48365d
fix: absolute asset/fetch paths for nested /agents routes
rijulshrestha Jun 29, 2026
5d3a8b1
refactor(ide): extract mode-agnostic IdeShell from /ide route
rijulshrestha Jun 30, 2026
4a4c4eb
feat(ide): add GitHub repo tree fetch helper
rijulshrestha Jun 30, 2026
8ecf1a5
feat(ide): boot the playground from a GitHub repo + landing
rijulshrestha Jun 30, 2026
0ede79f
refactor(ide): use plain shallow clone for GitHub boot
rijulshrestha Jul 1, 2026
3cd9919
feat(ide): animated liquid preview loader
rijulshrestha Jul 1, 2026
e4da26a
refactor(ide): move framework switching into a header project switcher
rijulshrestha Jul 2, 2026
4437834
UI first pass experimental
GabrielaReyna Jul 3, 2026
3c8684d
feat(ide): swap the playground editor from CodeMirror to Monaco
rijulshrestha Jul 6, 2026
2387bff
refactor(ide): unify terminal tabs into one 'Terminal' model
rijulshrestha Jul 6, 2026
27342ff
feedback fixes, agents blanket, ui tour fix, agents message
GabrielaReyna Jul 7, 2026
b6b1a25
feat(ide): add file/folder create, rename, and delete to the file tree
rijulshrestha Jul 7, 2026
32b3832
Merge origin/ui-experimental into playground_integration
rijulshrestha Jul 7, 2026
c999f2e
chore(ide): drop project-switcher leftovers after ui-experimental merge
rijulshrestha Jul 7, 2026
7a2cd61
feat(ide): open multiple files as editor tabs
rijulshrestha Jul 8, 2026
69d39d7
feat(ide): open files as editor tabs with single-click preview
rijulshrestha Jul 8, 2026
0f678bb
chore(playground): standardize template metadata, Vite versions, and …
rijulshrestha Jul 9, 2026
a73d754
feat(playground): add BrowserPod badge to Vite demo templates
rijulshrestha Jul 9, 2026
2ef34ff
feat(playground): rebuild Nuxt demo with BrowserPod branding
rijulshrestha Jul 9, 2026
f2495d7
ui styling
GabrielaReyna Jul 10, 2026
7c5d97b
home page animations
Jul 10, 2026
1d8ddc3
reduced disturbance radius
Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .claude/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": "0.0.1",
"configurations": [
{
"name": "dev",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "dev"],
"port": 5173,
"autoPort": true
}
]
}
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ bun.lockb

# Miscellaneous
/static/
.claude/
218 changes: 218 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## What is BrowserCode?

BrowserCode is a web-based IDE that runs entirely in the browser using WebAssembly. It has two experiences: a **playground IDE** at `/ide` (editor + file tree + terminals + live preview, with per-framework starter templates) and **AI coding CLIs** (Claude Code, Gemini CLI) at `/agents/[tool]`. Both are built on BrowserPod, which provides a sandboxed Node.js environment with persistent filesystem storage, POSIX CLI tools (bash, git, npm), and instant app previews via WebAssembly-based portal URLs.

See `docs/codebase-guide.md` for a full structural tour.

## Quick Start

```bash
npm install # Install dependencies
npm run dev # Start development server at http://localhost:5173
npm run check # Run type checking and Svelte validation
npm run lint # Check code style with ESLint and Prettier
npm run format # Auto-format code with Prettier
npm run build # Build for production
npm run preview # Preview production build locally
```

## Tech Stack

- **Framework**: SvelteKit 2.50.2 (Svelte 5.51.0)
- **Build**: Vite 7.3.1
- **Styling**: Tailwind CSS 4.1.18
- **Runtime**: BrowserPod 2.8.0 (WebAssembly Node.js environment)
- **Type System**: TypeScript 5.9.3 (strict mode)
- **Icons**: Iconify + mingcute icon set
- **Code Quality**: ESLint 9.39.2, Prettier 3.8.1

## High-Level Architecture

### User-Facing Flow

```
User visits browsercode.io
/ redirects to /ide (playground); agents live at /agents/claude, /agents/gemini
+layout.svelte renders: Sidebar + Main Content Area
/ide: ide/+page.svelte → IdeSession.boot() hydrates a framework template into a pod
/agents/[tool]: agents/[tool]/+page.svelte → bootCLI() boots the tool's disk image
Terminal renders stdio output; Portal iframes live previews
```

### Routing & Tool Selection

The app is a client-rendered SPA (`adapter-static`, `ssr = false`, `200.html` fallback), so all redirects below run client-side.

- **Root**: `/` redirects to `/ide` (`src/routes/+page.ts`)
- **Playground IDE**: `/ide`, framework selected via `?framework=<id>` (registry in `lib/config/frameworks.ts`; templates in `static/templates/`)
- **Agent Pages**: `/agents/[tool]` (`routes/agents/[tool]/+page.svelte`)
- **Legacy URLs**: `/claude`, `/gemini`, … redirect to `/agents/<tool>` (`routes/[tool]/+page.ts`)
- **Supported Tools** (lib/config/tools.ts):
- Claude Code: enabled, uses claude_20260506 disk image
- Gemini CLI: enabled, uses gemini_20260430_2 disk image
- Codex, OpenCode: disabled (coming soon)

Tool/IDE switching uses full page loads (`window.location.href`) on purpose — that is the teardown mechanism for the running pod.

### Component Hierarchy

**+layout.svelte** (root layout)

- Renders Sidebar (left) + main content (right)
- Manages tool validation and active tool state
- Sets up OG meta tags for social sharing

**agents/[tool]/+page.svelte** (agent application)

- Terminal component (simple div#console container)
- Portal component (preview iframe + controls)
- Desktop: split layout with drag-to-resize (portalFraction state)
- Mobile: tab navigation between Terminal and Preview views
- Handles portal updates from BrowserPod callbacks

**ide/+page.svelte** (playground application)

- Dispatches to IdeLanding (bare `/ide`) or IdeShell (framework/GitHub boot); IdeShell composes the icon rail, resizable FileTreePanel side panel, a header project switcher (template + GitHub clone), EditorPane (Monaco), TerminalTabs (boot/dev-server terminal + closeable extra bash terminals via "+"), Portal preview
- Pod lifecycle and file/portal state live in `lib/ide/session.svelte.ts` (IdeSession); pod file I/O helpers in `lib/ide/pod-fs.ts`
- `lib/components/ide/EditorPane.svelte` + `lib/components/ide/monaco.ts` are the only files importing `monaco-editor` — they are designed to be replaced by VS Code Web later; session/pod-fs/frameworks survive that migration

**Portal.svelte**

- iFrame displaying preview URLs
- Port selector (if multiple services running)
- Menu for copy URL, QR code, open in new tab
- QR code generation using qrcode library

**Sidebar.svelte**

- Fixed-width nav (desktop only, hidden mobile)
- Tool buttons, GitHub/Discord links, Help button
- Uses Iconify icons with hover tooltips

**Stepper.svelte**

- Onboarding tutorial modal
- State managed via stepperState store

### Data Flow: BrowserPod & Portals

```
lib/utils/main.ts: bootCLI()
1. Detects iOS (unsupported platform)
2. Initializes BrowserPod with VITE_API_KEY env var
3. Creates terminal linked to #console div
4. Sets up portal listener (pod.onPortal callback)
5. Creates /home/user/project directory
6. Copies optional project file (CLAUDE.md or GEMINI.md)
7. Runs CLI: node /path/to/cli.js in /home/user/project

BrowserPod callbacks:
- Portal events: { port, url } → portalUpdate state → Portal component
- Open events: Optional custom handler (e.g., OAuth URL rewriting for Claude)
```

**Portal Updates**: When a service starts on a port, BrowserPod emits `{ port, url, active: true }`. This is collected in the `portals` array (state in [tool]/+page.svelte), and the selected portal renders in the iFrame.

### Storage & Persistence

- Each tool has a `storageKey` (e.g., `claude_20260506`) that maps to a BrowserPod disk image URL
- BrowserPod caches the WebAssembly filesystem locally (IndexedDB)
- Changes persist across sessions within the same storage key
- Disk images are versioned; updating the version syncs a new baseline

### Configuration

**lib/config/tools.ts** defines:

- Tool metadata (id, label, icon, disabled flag)
- CLI configurations: disk image URL, storage key, command, args, optional project file, optional open callback

To add a new tool:

1. Add to `toolItems` array
2. Add config to `cliConfigs` object
3. Ensure disk image is available at the WSS URL

## Development Workflow

### Adding a Component

1. Create a `.svelte` file in `src/lib/components/`
2. Use `<script lang="ts">` with `$props()` for type-safe props (Svelte 5 rune syntax)
3. Use `$derived()` for reactive computed values
4. Styling: Tailwind classes with `prettier-plugin-tailwindcss` auto-sorting

### Modifying Tool Configuration

Edit `src/lib/config/tools.ts`:

- Update disk image URLs when new versions are released
- Change `projectFile` path to copy a different CLAUDE.md/GEMINI.md
- Implement custom `openCallback` for OAuth or URL routing

### Responsive Design

- **Mobile breakpoint**: `max-width: 768px` (Tailwind's `md:` prefix)
- **Mobile view**: Tab-based navigation (terminal, preview, help tabs)
- **Desktop view**: Sidebar + resizable split layout
- **Safe area insets**: `env(safe-area-inset-bottom)` for notched devices

### CORS & Security

- **vite.config.ts**: Dev server headers set COEP, COOP, CSP for browserpod.io iframes
- **static/\_headers**: Production headers (served with the built `dist/`) enforce COOP/COEP/CSP, allow BrowserPod framing
- These are critical for BrowserPod to work; do not remove

## Key Files & Their Purposes

| File | Purpose |
| --------------------------------------- | -------------------------------------------------------- |
| `src/routes/+page.ts` | Root route, redirects to /ide |
| `src/routes/[tool]/+page.ts` | Legacy /claude, /gemini → /agents/\* redirects |
| `src/routes/+layout.svelte` | Main layout shell, sidebar, tool switching |
| `src/routes/agents/[tool]/+page.svelte` | Terminal + preview portal interface (agents) |
| `src/routes/ide/+page.svelte` | Playground IDE layout and composition |
| `src/lib/components/*.svelte` | UI components (Sidebar, Terminal, Portal, Stepper, etc.) |
| `src/lib/components/ide/*.svelte` | IDE components (EditorPane, FileTreePanel, TerminalTabs) |
| `src/lib/config/tools.ts` | Tool definitions, CLI args, disk image URLs |
| `src/lib/config/frameworks.ts` | Playground framework registry (templates, commands) |
| `src/lib/utils/main.ts` | `bootCLI()` function, BrowserPod initialization (agents) |
| `src/lib/ide/session.svelte.ts` | IdeSession: playground pod lifecycle and state |
| `src/lib/ide/pod-fs.ts` | Pod filesystem read/write helpers |
| `src/lib/stores/stepper.svelte.ts` | Tutorial modal state |
| `static/templates/<id>/` | Framework starter templates + manifest.txt |
| `vite.config.ts` | Build config, dev CORS headers, Tailwind plugin |
| `svelte.config.js` | SvelteKit static adapter (SPA, 200.html fallback) |
| `tailwind.config.ts` | Custom theme colors (dark mode sidebar/panel/terminal) |
| `static/_headers` | Production CORS headers |

## Code Style & Conventions

- **Formatting**: Prettier with tabs (not spaces), 100 char line width
- **Plugins**: `prettier-plugin-svelte` + `prettier-plugin-tailwindcss` (auto-sorts Tailwind classes)
- **Linting**: ESLint with TypeScript and Svelte rules, no auto-fixes; use `npm run lint` to check
- **Type Safety**: Strict mode enabled; prefer `$props()` and type annotations over `let` with implicit types
- **Event Handlers**: Inline `onclick`/`onchange` attributes (Svelte convention)
- **Reactive**: Use `$derived()` for computed values, `$effect()` for side effects (Svelte 5 runes)

## Deployment

- **Adapter**: `@sveltejs/adapter-static` (client-rendered SPA, `200.html` fallback)
- **Build output**: `dist/` directory
- **Headers**: `static/_headers` configures headers for Netlify/Cloudflare
- **Environment**: `VITE_API_KEY` required at build/runtime (BrowserPod API key)

## Known Limitations (from README)

- iOS is not supported (detected at boot, shows `IosUnsupportedModal.svelte`)
- Safari is not fully supported — use a Chromium browser for maximum compatibility
- TCP networking is unavailable
- Native binaries are not supported (see [BrowserPod docs](https://browserpod.io/docs/guides/native-binaries))
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,13 @@ This is BrowserCode beta. Don't be kind to it. Stretch it, bend it, find out wha
- Networking over TCP isn't available
- For maximum compatbility, please use a Chromium browser. Safari currently isn't supported


<h2 id="roadmap">Roadmap</h2>

| | CLI | Status |
| :---: | --- | --- |
| <img src="./static/readme/gemini.webp" alt="Gemini CLI" width="32" height="32" /> | **Gemini CLI** | ✅ Beta open now |
| | CLI | Status |
| :--------------------------------------------------------------------------------: | --------------- | ---------------- |
| <img src="./static/readme/gemini.webp" alt="Gemini CLI" width="32" height="32" /> | **Gemini CLI** | ✅ Beta open now |
| <img src="./static/readme/claude.webp" alt="Claude Code" width="32" height="32" /> | **Claude Code** | ✅ Beta open now |
| <img src="./static/readme/codex.webp" alt="Codex" width="32" height="32" /> | **Codex** | 🚧 Coming soon |
| <img src="./static/readme/opencode.webp" alt="OpenCode" width="32" height="32" /> | **OpenCode** | 🚧 Coming soon |

| <img src="./static/readme/codex.webp" alt="Codex" width="32" height="32" /> | **Codex** | 🚧 Coming soon |
| <img src="./static/readme/opencode.webp" alt="OpenCode" width="32" height="32" /> | **OpenCode** | 🚧 Coming soon |

<p align="right">(<a href="#readme-top">back to top</a>)</p>
Loading