Skip to main content
VAssist’s Chrome extension uses a sophisticated multi-layer architecture to inject a 3D AI assistant into any webpage while maintaining complete isolation from the host page.

Multi-Layer Architecture

The extension operates across four isolated contexts, each with specific responsibilities:

1. Main World (React App)

Location: Injected <script> in host page
Access: Full DOM access, same origin as host page
Limitations: Cannot use chrome.* APIs directly
Responsibilities:
  • Render React UI in Shadow DOM
  • Handle user interactions
  • Manage 3D character (Babylon.js)
  • Display chat messages and animations
Communication:
The React app runs in the “Main World” (same JavaScript context as the host page) but renders UI inside a Shadow DOM for CSS isolation.

2. Content Script (Isolated World)

Location: extension/content/index.js
Access: Separate JavaScript context, same DOM
File: `/home/daytona/workspace/source/extension/content/index.js:1
Responsibilities:
  • Inject React app script into page
  • Bridge between Main World and Background
  • Manage Shadow DOM container
  • Handle injection lifecycle (show/hide/cleanup)
Key Features:
Message Bridge:
Content scripts bridge the gap between the Main World (which can’t access chrome.* APIs) and the Background Worker (which can).

3. Background Service Worker

Location: extension/background/index.js
Access: Full chrome.* API access, no DOM
Lifecycle: Persistent (kept alive during active sessions)
File: `/home/daytona/workspace/source/extension/background/index.js:1
Responsibilities:
  • Handle all AI/TTS/STT service requests
  • Manage per-tab state via TabManager
  • Route messages to appropriate handlers
  • Control offscreen document lifecycle
  • Make external API calls
Message Handler Pattern:
Tab Management:

4. Offscreen Document

Location: extension/offscreen/offscreen.js
Access: AudioContext, Web Workers, full processing power
Purpose: Heavy audio processing and Kokoro TTS
File: `/home/daytona/workspace/source/extension/offscreen/offscreen.js:1
Why Offscreen?
  • Service workers have limited runtime (30 seconds idle timeout)
  • AudioContext not available in service workers
  • Heavy processing (Kokoro TTS, lip sync) needs stable context
  • Can run for minutes without interruption
Responsibilities:
  • Kokoro TTS model loading and inference (1-2 minutes)
  • Audio decoding with AudioContext
  • VMD lip sync generation (10-20 seconds)
  • BVMD animation conversion
Example Handler:
The offscreen document only handles messages explicitly targeted to it (message.target === 'offscreen'), allowing it to coexist with other message listeners.

Message Passing System

Message Flow

Typical message flow for an AI chat request:

Streaming Messages

For streaming responses (AI chat, TTS):

Message Types

Defined in extension/shared/MessageTypes.js:

Shadow DOM Isolation

VAssist uses Shadow DOM to achieve zero CSS conflicts with host pages.

Architecture

Why Shadow DOM?

  • CSS Isolation: Host page styles can’t affect VAssist UI
  • JavaScript Isolation: Host page scripts can’t interfere
  • Clean Namespace: No ID/class conflicts
  • Scoped Tailwind: Tailwind styles only apply inside shadow root

Canvas Portal

The 3D canvas lives outside Shadow DOM because:
  • Babylon.js WebGL context needs direct browser access
  • Better performance without shadow boundary overhead
  • Positioned absolutely, so no layout conflicts

Per-Tab State Management

Each browser tab maintains completely isolated state:

Tab State Structure

Per-Tab Services

Automatic Cleanup

Service Worker Lifecycle

Keepalive Strategy

Service workers can terminate after 30 seconds of inactivity. VAssist keeps the worker alive during:
  • Active AI chat sessions
  • TTS/STT processing
  • Kokoro model loading (1-2 minutes)
  • VMD generation (10-20 seconds)

Offscreen Document Lifecycle

Security Considerations

Content Security Policy

  • 'wasm-unsafe-eval': Required for Transformers.js (Kokoro TTS)
  • 'self': Only load scripts from extension origin

Permissions

Host Permissions

Testing the Extension

Loading Unpacked Extension

1

Build the extension

2

Open Chrome Extensions page

Navigate to chrome://extensions/ and enable “Developer mode”
3

Load unpacked

Click “Load unpacked” and select the dist/extension folder
4

Test on websites

Visit any website and click the extension icon to toggle VAssist

Multi-Tab Testing

  1. Open VAssist in Tab A
  2. Start a conversation
  3. Open VAssist in Tab B
  4. Start a different conversation
  5. Switch between tabs - each should maintain independent state

Debugging Tips

  • Check all consoles: Main page, background worker, offscreen document
  • Use Logger prefixes: [Content], [Background], [Offscreen]
  • Monitor message flow: Add breakpoints in message bridges
  • Test cleanup: Close tabs and verify state cleanup

Next Steps