Skip to main content
Opal Editor is built as a local-first, zero-backend markdown editor and static site publisher. This guide explains the architectural decisions and core systems.

High-Level Architecture

Opal Editor follows a local-first architecture with no server dependencies:
┌─────────────────────────────────────────────────────────────┐
│                      Browser (Client)                        │
│                                                               │
│  ┌─────────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │   React UI  │  │ Service      │  │  Web Workers     │   │
│  │  (Vite SPA) │◄─┤ Worker       │◄─┤  (Build/Process) │   │
│  └──────┬──────┘  │ (Hono Router)│  └──────────────────┘   │
│         │         └──────┬───────┘                          │
│         ▼                ▼                                   │
│  ┌─────────────────────────────────────────────────────┐   │
│  │           Data Layer (Dexie/IndexedDB)              │   │
│  │  - Workspaces  - Builds  - Deployments              │   │
│  │  - Remote Auth - Destinations - History             │   │
│  └─────────────────────────────────────────────────────┘   │
│                          │                                   │
│         ┌────────────────┼────────────────┐                 │
│         ▼                ▼                ▼                 │
│  ┌──────────┐  ┌─────────────┐  ┌────────────┐             │
│  │ IndexedDB│  │    OPFS     │  │  LightningFS│             │
│  │  Disk    │  │ (Dir Mount) │  │  (Memory)   │             │
│  └──────────┘  └─────────────┘  └────────────┘             │
└─────────────────────────────────────────────────────────────┘
         │                │                 │
         └────────────────┴─────────────────┘

                  (Optional Remote)

              ┌───────────┴──────────┐
              ▼                      ▼
       ┌───────────┐         ┌─────────────┐
       │  GitHub   │         │  Netlify    │
       │   (Git)   │         │  Vercel     │
       └───────────┘         │  Cloudflare │
                             │  AWS S3     │
                             └─────────────┘

Core Technologies

Frontend Framework

  • React 19.2.0: UI framework with compiler-based optimizations
  • TypeScript 5.9.3: Type-safe development
  • Vite 6.3.5: Build tool and dev server (vite.config.ts:14)
  • Tanstack Router: File-based routing (main.tsx:8)
  • Tanstack Query: Server state management

UI Components

  • shadcn/ui: Built on Radix UI primitives
  • Tailwind CSS: Utility-first styling
  • Lucide React: Icon library
  • MDX Editor: WYSIWYG markdown editing
  • CodeMirror 6: Source code editing with Vim mode support

Data & Storage

  • Dexie 4.0.10: IndexedDB wrapper (src/data/index.ts:9)
  • IndexedDB: Primary persistence layer
  • OPFS: Origin Private File System for filesystem access
  • Lightning FS: In-memory filesystem fallback

Build & Processing

  • marked: Markdown parsing and rendering
  • gray-matter: Frontmatter parsing
  • rehype/remark: Unified ecosystem for content transformation
  • Eleventy (in-browser): Static site generation
  • Template Engines: Mustache, Nunjucks, Liquid, EJS

Git Integration

  • isomorphic-git: Pure JavaScript Git implementation
  • Octokit: GitHub API client

Deployment

  • Cloudflare SDK: Cloudflare Pages deployment
  • Vercel SDK: Vercel deployment
  • AWS SDK S3: S3 deployment
  • zip.js: Archive creation for deployments

Core Systems

1. Workspace System

The Workspace class (src/workspace/Workspace.ts:74) is the central orchestrator:
export class Workspace {
  imageCache: ImageCache;
  name: string;
  guid: string;
  private _disk: Disk;        // Virtual filesystem
  private _thumbs: Disk;       // Thumbnail storage
  private _repo: GitRepo;      // Git repository
  private _playbook: GitPlaybook;
  private _remoteAuths?: RemoteAuthDAO[];
  // ...
}
Key Responsibilities:
  • File management through virtual disk abstraction
  • Git operations via GitRepo
  • Image optimization and caching
  • Remote authentication for GitHub/deployment services

2. Virtual Filesystem (Disk Abstraction)

Opal uses a unified filesystem abstraction (src/data/disk/Disk.ts:36):
export abstract class Disk<TContext extends DiskContext = DiskContext> {
  remote: DiskEventsRemote;
  local: DiskEventsLocal;
  _fs: CommonFileSystem;      // Unified FS interface
  _fileTree: FileTree;         // In-memory tree structure
  abstract type: DiskType;
}
Disk Types:
  • IndexedDbDisk: Uses @isomorphic-git/lightning-fs backed by IndexedDB
  • OPFSDirMountDisk: Uses Origin Private File System for better performance
  • NullDisk: Fallback when no storage is available
Filesystem Layers:
  • TranslateFs: Path translation and routing
  • NamespacedFs: Namespace isolation for multi-workspace
  • MutexFs: Concurrency control
  • HideFs: Hide .git and other special directories

3. Service Worker Architecture

The service worker (src/lib/service-worker/sw-hono.ts:33) uses Hono as a router:
const app = new Hono<{ Variables: { workspaceName: string } }>();

// Routes:
app.post('/image/upload/:workspaceName/:imagePath', ...);  // Image uploads
app.get('/image/:workspaceName/*', ...);                    // Image serving
app.get('/md-render', ...);                                 // Markdown rendering
app.get('/search', ...);                                    // Content search
app.get('/download.zip', ...);                              // Workspace export
Why Service Worker?
  • Intercept and handle file:// requests
  • Enable offline functionality
  • Process images without server
  • Render markdown on-demand
  • Export workspaces as encrypted zips

4. Database Schema (Dexie)

The database (src/data/index.ts:12) stores application state:
export class ClientIndexedDb extends Dexie {
  workspaces!: EntityTable<WorkspaceRecord, "guid">;
  remoteAuths!: EntityTable<RemoteAuthRecord, "guid">;
  destinations!: EntityTable<DestinationRecord, "guid">;
  settings!: EntityTable<SettingsRecord, "name">;
  disks!: EntityTable<DiskRecord, "guid">;
  builds!: EntityTable<BuildRecord, "guid">;
  deployments!: EntityTable<DeployRecord, "guid">;
  historyDocs!: EntityTable<HistoryDAO, "edit_id">;
}
Key Tables:
  • workspaces: Workspace metadata, disk references, Git config
  • disks: Virtual disk configurations (type, paths, handles)
  • builds: Build history and artifacts
  • deployments: Deployment records linked to builds
  • remoteAuths: OAuth tokens for GitHub, Netlify, Vercel
  • destinations: Deployment targets (Netlify, Vercel, Cloudflare, S3)
  • historyDocs: Document edit history with operational transforms

5. Git Repository System

The GitRepo class (src/features/git-repo/GitRepo.ts:1) wraps isomorphic-git:
import GIT from 'isomorphic-git';
import http from 'isomorphic-git/http/web';

export class GitRepo {
  // Core operations:
  async init();
  async commit(message: string, author: GitRepoAuthor);
  async push(remote: string, branch: string);
  async pull(remote: string, branch: string);
  async checkout(ref: string);
  async merge(branch: string): Promise<MergeResult>;
  // ...
}
Features:
  • Full Git operations in the browser
  • GitHub integration via OAuth device flow
  • Conflict detection and resolution
  • Branch management
  • Remote sync with CORS proxy support

6. Build System

The build system (src/services/build/) generates static sites:
// BuildRunner factory creates strategy-specific runners
export class BuildRunnerFactory {
  static create(strategy: BuildStrategy, workspace: Workspace) {
    switch (strategy) {
      case 'eleventy':
        return new EleventyBuildRunner(workspace);
      case 'freeform':
        return new BuildRunner(workspace);
    }
  }
}
Build Strategies:
  • Freeform: Direct markdown-to-HTML with template engines
  • Eleventy: Full Eleventy 3.0 running in-browser via web worker
Template Engines Supported:
  • Mustache (mustache)
  • Nunjucks (nunjucks)
  • Liquid (liquidjs)
  • EJS (eta)
  • Markdown (marked + frontmatter)

7. Editor System

Opal provides multiple editor modes: Markdown Editor (src/editors/markdown/):
  • WYSIWYG editing via @mdxeditor/editor
  • Toolbar with formatting options
  • Image upload and embedding
  • Live preview
Source Editor (src/editors/source/):
  • CodeMirror 6 with syntax highlighting
  • Language support: JS, CSS, HTML, YAML, JSON, Markdown
  • Vim mode support
  • Template language syntax (Mustache, Liquid, Nunjucks, EJS)
History System (src/editors/history/):
  • Tracks document changes in IndexedDB
  • Operational transform for conflict resolution
  • Diff visualization

Data Flow

File Read Flow

UI Component

Workspace.disk.readFile(path)

Disk._fs.readFile(path)          // Virtual FS

TranslateFs → NamespacedFs → MutexFs

LightningFS / OPFS / IndexedDB   // Physical storage

Build & Deploy Flow

User clicks "Build"

BuildRunner.build()

Web Worker (EleventyBuildRunner)  // Off main thread

Template Engine Processing

Generated files → memfs

BuildRecord saved to IndexedDB

[User clicks "Deploy"]

DeployService (Netlify/Vercel/CF/S3)

Zip creation → Upload

DeployRecord saved to IndexedDB

Image Upload Flow

User pastes/drops image

Editor (MDX or CodeMirror)

POST /image/upload/:workspace/:path (Service Worker)

handleImageUpload()

WebP conversion (if needed)

Workspace.disk.writeFile()

ImageCache.set()              // Thumbnail generation

Markdown updated with image reference

File System Architecture

Opal’s filesystem is designed for flexibility and browser compatibility:

Storage Options

  1. IndexedDB (Default)
    • Works everywhere
    • Uses @isomorphic-git/lightning-fs
    • Good performance for small-to-medium workspaces
  2. OPFS Directory Mount (Recommended)
    • Best performance
    • Uses native filesystem APIs
    • Chrome/Edge only (requires FileSystemDirectoryHandle API)
  3. Memory (Fallback)
    • When IndexedDB is unavailable
    • Data lost on page refresh

Virtual Filesystem Layers

Each Disk wraps the base filesystem with transformation layers:
// Example: Workspace disk setup
const fs = new HideFs(
  new MutexFs(
    new NamespacedFs(
      lightningFs,
      `/workspace-${guid}`
    )
  ),
  ['.git', '.opal']
);
Layer Purposes:
  • HideFs: Hide directories from file tree (.git, .opal)
  • MutexFs: Prevent concurrent access issues
  • NamespacedFs: Isolate workspaces by prepending namespace to paths
  • TranslateFs: Map virtual paths to physical paths

Event System

Opal uses a typed event system for cross-component communication:
// TypeEmitter for local events
class WorkspaceEventsLocal extends CreateSuperTypedEmitterClass<
  WorkspaceRemoteEventPayload
>() {}

// Channel for cross-context events (main ↔ service worker)
class WorkspaceEventsRemote extends Channel<
  WorkspaceRemoteEventPayload
> {}
Event Types:
  • DiskEvents: File create, update, delete, rename
  • WorkspaceEvents: Workspace rename, delete
  • GitRepoEvents: Commit, push, pull, branch changes

Security Considerations

Data Privacy

  • All data stored locally: No server means no data leaves your browser
  • Encryption: Workspace export supports AES and ZipCrypto encryption
  • OAuth tokens: Stored in IndexedDB, only sent to official APIs

Remote Auth

  • GitHub: OAuth device flow
  • Netlify/Vercel/Cloudflare: Personal access tokens
  • AWS S3: Access key + secret (encrypted in IndexedDB)

Content Security

  • DOMPurify for sanitizing rendered HTML
  • Service Worker same-origin enforcement
  • No eval() or dangerous dynamic code execution

Performance Optimizations

React Compiler

Automatic memoization via babel-plugin-react-compiler eliminates manual useMemo/useCallback.

Code Splitting

Vite automatically splits code by route using dynamic imports.

Web Workers

  • Build processes run off main thread
  • Image conversion in workers
  • Git operations non-blocking

Virtual Scrolling

  • File tree uses @tanstack/react-virtual
  • Large file lists render only visible items

Debounced Operations

  • Auto-save debounced to 500ms
  • Search debounced to 300ms
  • File tree indexing batched

Development Philosophy

Local-First

All features work offline. Remote features (Git, deploy) are optional enhancements.

Zero Backend

No server infrastructure means:
  • No hosting costs
  • No server maintenance
  • No downtime
  • Complete data ownership

Progressive Enhancement

  • Core features work in all modern browsers
  • OPFS enhances performance where available
  • Service workers enable advanced features

Next Steps

Now that you understand the architecture:
  1. Explore the Development Setup to start contributing
  2. Check the src/ directory structure to find specific implementations
  3. Read inline code comments for detailed logic explanations
The codebase uses TypeScript extensively. Type definitions in src/types/ provide excellent documentation for data structures and interfaces.

Build docs developers (and LLMs) love