Extension Architecture
Relevant source files
The following files were used as context for generating this wiki page:
Oddity 1 is a Chrome Manifest V3 (MV3) extension built with Vite and CRXJS. It creates an annotation layer on top of Long Language Model (LLM) conversations and prose content to amplify critical thinking through AI-generated insights and manual user notes. The system operates across three primary environments: the Background Service Worker, Content Scripts, and the Popup Dashboard.
Sources: README.md:12-22, extension/manifest.config.ts:13-17
Core Components
The extension architecture divides responsibilities between three main execution contexts to ensure performance and security.
Background Service Worker
The Service Worker acts as the central orchestrator. It manages authentication sessions via Supabase and Google OAuth, routes messages between the popup and content scripts, and interfaces with the backend API. It also handles specialized tasks like PDF detection and Google Docs API communication.
Sources: extension/src/background/index.ts:101-140, README.md:13-14
Content Scripts
Content scripts manage the Document Object Model (DOM) of the host page. They detect "reading regions" (prose-heavy areas), monitor text stability on dynamic sites like ChatGPT or Claude, and render the annotation UI. The UI includes an overlay layer for highlights and a Shadow DOM-based margin notes system to prevent host-page CSS interference.
Sources: extension/src/content/index.ts:1008-1065, README.md:15-16
Popup and UI Layers
The popup provides a dashboard for user controls, statistics, and profile management. It uses a refined design with a warm light background and pill-shaped buttons.
Sources: extension/src/popup/index.html:13-100, CHANGELOG.md:6-14
Architecture Overview
The following diagram illustrates the relationship between these components and the external backend.
The diagram shows the Service Worker acting as a hub for internal and external communication.
Sources: README.md:12-26, extension/src/background/index.ts:192-220
Annotation Lifecycle
The extension follows a structured pipeline to generate and display annotations.
- Detection: The content script identifies prose regions using a 3-tier fallback (Site Adapter → Readability → Heuristic).
- Stability: On dynamic sites, a
StabilityWatcherensures text has stopped streaming before requesting annotations. - Request: The Service Worker sends the content hash and text to the backend.
- Rendering: The content script injects anchor spans and renders highlights in an overlay layer.
- Interactivity: Hovering or clicking anchors opens detailed insights in the margin notes.
Sources: extension/src/content/index.ts:1020-1080, README.md:210-220
Annotation Data Flow
This sequence shows how the extension handles the flow from detecting text changes to rendering the final UI.
Sources: extension/src/content/index.ts:1330-1450, extension/src/background/index.ts:285-350
Google Docs Integration
Oddity 1 includes a specialized pipeline for Google Docs, which uses a Canvas-based editor. Because traditional DOM-based anchors are not possible, the extension uses pretext-based rect detection to place synthetic anchors and overlays at specific pixel coordinates.
- Synthetic Anchors: The extension injects fixed-position
<span>elements that track with the scroll container. - Coordinate Correction: It listens for cursor movements and text shifts to adjust highlight positions in real-time.
- API Mode: It utilizes
chrome.identityto interact directly with the Google Docs API for native highlight synchronization.
Sources: extension/src/content/index.ts:770-850, extension/src/background/index.ts:145-185
PDF Management
The extension handles PDF files through two distinct methods:
| Feature | Description | File Source |
|---|---|---|
| Detection | tabs.onUpdated detects PDF URLs and triggers scripting.executeScript. | background/index.ts |
| Conversion | Fetches PDF binary and sends it to the backend for Datalab Marker API conversion to HTML. | content/index.ts |
| Export | Generates a print-optimized PDF with Tufte-style float sidenotes for annotations. | content/export-pdf.ts |
Sources: extension/src/background/index.ts:101-125, extension/src/content/index.ts:630-670, extension/src/content/export-pdf.ts:250-300
Permissions and Security
The extension requires specific permissions to operate across the web and manage user data securely.
| Permission | Purpose |
|---|---|
activeTab | Accesses the current tab URL for context-aware annotations. |
storage | Persists user preferences and cached annotations (30-day TTL). |
identity | Required for Google OAuth and Google Docs API access. |
scripting | Programmatically injects scripts into PDF views or blob URLs. |
host_permissions | Allows the content script to run on <all_urls> for site-agnostic prose detection. |
Sources: extension/manifest.config.ts:24-35, README.md:120-135
Technical Implementation Details
Concurrency and Optimization
The extension implements a per-tab concurrency limiter (MAX_CONCURRENT_PER_TAB = 3) to prevent API rate limit bursts. It uses AbortController to cancel stale in-flight requests when the same region is re-annotated or during SPA navigation.
Sources: extension/src/background/index.ts:50-70
SPA Navigation Fix
To support Single Page Applications (SPAs) like ChatGPT or Claude, the extension monitors history.pushState and popstate events. Upon navigation, it triggers resetAnnotationState(), which tears down all observers and DOM artifacts to prevent state leakage between pages.
Sources: extension/src/content/index.ts:580-620, tasks/todo.md:175-195
Shadow DOM Isolation
Margin notes and popovers are rendered within a closed Shadow DOM. This ensures that the host page's CSS does not leak into the Oddity UI and that Oddity's styles do not break the host page's layout.
Sources: tasks/todo.md:75-85, extension/src/content/index.ts:1060-1070
The extension architecture prioritizes UI stability and cross-site compatibility while leveraging a powerful background layer for authentication and API management.