local-lens

Local Lens

A privacy-first Chrome extension that OCRs any selected region of a web page. Both OCR engines are bundled (PaddleOCR PP-OCRv5 + PP-DocLayoutV3) — no model downloads, no network calls.

What it does

Install from source

Requires Node 20+.

npm install
npm run build

Then in Chrome: chrome://extensions → enable Developer mode → Load unpacked → select the dist/ folder.

Development

npm run dev        # Vite dev server (for working on UI in isolation)
npm run build      # production build into dist/

The build emits three entry points (background, content, offscreen) and copies static assets from public/ (manifest, icons, offscreen HTML, bundled model files).

Testing

npm test                  # unit + browser tests (fast engine, parsers, island UI)
npm run test:watch        # watch mode
npm run test:structured   # structured engine browser tests
npm run test:ui-snapshots # FloatingIsland / GhostOverlay visual snapshots
npm run test:ui-update    # update snapshot baselines
npm run test:bench        # PP-OCRv5 timing tests (downloads fp32 rec for comparison)
npm run test:bench-parity # fp32 vs int8 recognition parity only

Browser tests run headless Chromium via @vitest/browser-playwright. Test fixtures live in test_pictures/ and expected outputs in tests/expected/.

Benchmarks

Numbers from tests/bench/RESULTS.md (headless Chromium, swiftshader, WASM SIMD threaded; WebGPU is not measurable in this environment so the “WebGPU” rows fall back to WASM):

See tests/bench/RESULTS.md for the full table, caveats around process-warm WASM, and the limitations of the parity gate (small high-contrast English fixtures only).

Real-world latency (Ryzen 7 5800HS, plugged in, performance mode)

End-to-end inference, measured on a real Chrome install (not headless). Currently all inference runs on WASM — WebGPU is not yet wired up in practice, so these numbers are a ceiling, not a floor.

Project layout

src/
  background.ts   service worker — toolbar action, lifecycle
  content.ts      injected into pages — selection overlay + island host
  offscreen.ts    offscreen document — runs OCR engines off the main thread
  overlay.ts      drag-to-select rectangle UI
  island/         floating result panel (React 19; engine switcher, copy, status)
  engine/         fast.ts (PP-OCRv5), structured.ts (PP-DocLayoutV3 + PP-OCRv5), table/ (SLANet_plus), parser/
public/
  manifest.json       MV3 manifest
  offscreen.html      host for the offscreen OCR worker
  paddle_engine/      bundled PP-OCRv5 ONNX models + ORT WASM runtime
  structured_engine/  bundled PP-DocLayoutV3 + SLANet_plus ONNX models + table dict

Privacy

No network calls. All OCR models ship with the extension. See PRIVACY.md.