-
Notifications
You must be signed in to change notification settings - Fork 0
planning
- Platform: Linux-primary (X11, GTK4 — migrated from GTK3 June 2026)
- OCR/Translation: OpenRouter API → Gemini 2.0 Flash (multimodal); returns structured JSON
- UI: GTK4 floating lens window (Cairo + Pango), transparent RGBA, with x11rb fallbacks for X11-specific features
-
Capture: X11 root window via
x11rb(bypasses GPU-accelerated windows correctly) -
Overlay HUD: Separate Electron process (
lenzu_server) — transparent window, UDP IPC - Interpreter: MeCab morphological analysis for furigana/romaji (replaced kakasi); LLM for english translation
-
Config:
lenzu_config.jsonwithisolanglanguage codes andOverlayRenderModeenum -
Workspace: Cargo workspace at repo root; members:
lenzu(client) and prototypes;lenzu_serveris a separate Node/Electron project
Make Linux the primary platform with a robust, performant OCR lens that works across Wayland and X11, using open-source tools while maintaining the offline-first, privacy-respecting design.
-
Phase 2 — Process Lifecycle [COMPLETED: 2026-03-28]
-
lenzuspawns/killslenzu_server(Electron HUD) automatically
-
-
Phase 3 — Migrate Overlay HUD (Tauri → Electron) [COMPLETED]
- Tauri/WebKit2GTK dropped due to alpha compositing artefacts on X11; Electron confirmed clean
- Known limitation: thin white titlebar strip on some compositors (mitigated, not eliminated)
Branch:
feature/ocr-local-remote
Design spec:docs/technical-design.phase4-predetect.md
Each step below depends on the previous being working and tested before moving on.
Unblocks everything else — no point writing OCR code if the server won't start.
-
scripts/setup.shinstalls Docker, pullsollama/ollama, pullsgemma4:e2b(scripts written, needs smoke-test on clean machine) -
scripts/run.shstartslenzu-ollamacontainer before lenzu, stops on exit viatrap - Manual test:
docker psconfirms container running;curl http://localhost:11434/returns healthy - Unit test:
start_ollamaidempotent (running twice doesn't create duplicate containers) -
Done when:
./scripts/run.shreliably starts and stops the container with no orphans
Validate that Gemma actually produces usable OCR results before wiring fallback logic.
-
AppConfigdefaults change:llm_api_endpoint→http://localhost:11434/v1/chat/completions,llm_default_model→gemma4:e2b -
OcrClient::call_apiskipsAuthorizationheader whenapi_keyis empty (ollama needs none) -
OPENROUTER_API_KEYnot required to start lenzu (warn only) - Shift+Click capture → Gemma query → result displayed in HUD (happy-path manual QA)
- Unit test: empty
api_key→ noAuthorizationheader in built request - Unit test: old
lenzu_config.jsonwithout new fields still loads with defaults (backward compat) - Done when: Shift+Click shows a translation via local Gemma with OpenRouter key unset
Two trigger paths: automatic (Gemma gave no translation) and manual (user forces remote).
-
DualOcrClientstruct wraps primary (OcrClient→ ollama) + optional fallback (OcrClient→ OpenRouter) -
needs_fallback(results): true when result vec is empty or allenglishfields are blank/whitespace - Automatic fallback: primary fail or no translation → retry with OpenRouter, log to
/dev/shm/api_debug.txt -
Ctrl+Shift+Click— new hotkey: skips primary entirely, sends directly to OpenRouter- Detected in
main.rsinput handler alongside existingShift+Click(addCONTROL_MASKcheck) - Requires
OPENROUTER_API_KEYset; shows error in HUD if not configured - Useful for: comparing Gemma vs Gemini output, bypassing local when Gemma is slow
- Detected in
-
AppConfiggainsfallback_llm_api_endpoint+fallback_llm_modelwith#[serde(default)] - Unit tests for
needs_fallback(empty vec, all-null, whitespace, partial success) - Integration tests: primary no-translation → fallback fires; primary HTTP 503 → fallback fires; both fail → error (wiremock)
- Integration test:
Ctrl+Shift+Clickpath calls fallback directly, primary mock gets zero calls - Done when: automatic fallback works silently; Ctrl+Shift+Click forces remote visibly
Grayscale applies to all captures (local + remote); downscale applies only before remote calls.
-
raw_to_dynamic_image(raw, w, h) -> DynamicImageinutils.rs -
encode_as_grayscale(image) -> Stringinutils.rs: grayscale PNG, full resolution — used for primary (Gemma) path -
encode_for_fallback(image, max_dim) -> Stringinutils.rs: grayscale + proportional downscale — used for fallback (OpenRouter) path -
DualOcrClient::call_apisignature changes to accept&DynamicImage; callsencode_as_grayscalefor primary,encode_for_fallbackfor fallback -
AppConfiggainsfallback_max_dimension: u32(default800) — downscale limit for remote calls only - Save preprocessed fallback image to
/dev/shm/debug_lens_fallback.pngfor dev comparison - Unit tests: grayscale output confirmed via PNG colour type for both paths; downscale preserves aspect ratio; zero max-dim disables resize; fallback b64 smaller than primary b64 (downscale effect)
- Integration test: fallback request body measurably smaller than primary request body
-
Done when: local path sends grayscale full-res; fallback path sends grayscale downscaled; debug file confirms visually; token savings confirmed in
api_debug.txt
-
DBNet pre-detection + adaptive capture (
M7): find text bounding boxes locally before any API call. On every Shift+Click the capture area is an oversample (max(lens_size × 2, 640)px); DBNet finds text within the original lens region; the union bounding box of the detected text is the actual crop sent to OCR — smaller than the lens when text is small (token savings ~80–93%), larger than the lens when text extends past it. On Ctrl+Shift+Click the entire desktop is captured (lens window is hidden first to avoid obstruction), DBNet finds text nearest to the lens position, and the remote OCR backend is forced. Model:assets/stabrise-text_detection_dbnet_ml_v02_model.onnx(already committed). COCO YOLOv8n ruled out — no text/speech-bubble class. Design:docs/technical-design.phase4-predetect.md§3–4.
-
MeCab furigana + 3-phase progressive HUD (2026-04-12): After local OCR succeeds, a 3-phase pipeline updates the HUD progressively: (1) raw text instant, (2) MeCab furigana+romaji in ~5 ms (deterministic, context-aware morphological analysis — no LLM), (3) LLM english translation if
enrichment_enabled. MeCab replaces both kakasi (furigana) and LLM-based furigana (qwen2.5:3b produced garbage readings). Pure-Rust Hepburn romaji converter eliminates the kakasi CLI dependency entirely. Lens stays modal until final phase completes (no request stacking). Channel bounded(3) for 3-phase flow. Seelenzu/src/furigana.rs. -
Text-only LLM enrichment (2026-04-12): After local OCR succeeds, send raw text (not image) to local Ollama for english translation. Text-to-text only — fast, no vision model. Graceful degradation if Ollama is unavailable. Language-configurable via
{src}/{dest}/{extra_prompt}placeholders. Config:enrichment_enabled,enrichment_model,enrichment_timeout_secs.
- Overlay position: configurable top/bottom via
hud_config.json - Click-through mode for
lenzu_serverwindow (doesn't steal mouse events) -
Lens-box resize (manual): allow the user to dynamically resize the lens capture box (click-drag) so they can manually control the initial capture area. Box should never shrink below a configurable minimum. Note: automatic adaptive sizing (shrink/expand to detected text) is already part of Phase 4 DBNet design (
technical-design.phase4-predetect.md§4.7) — this item covers the manual resize UX on top of that.
-
OCR Engine Diversification
- Evaluate EasyOCR (Python) via subprocess for Linux (does NOT handle vertical, discard)
- Research manga-ocr integration (requires Python/PyTorch, heavy)
- Investigate
rust-ocrorpaddleocr-rsalternatives - Consider training custom Tesseract model with manga109s dataset
-
Advanced Features
- Text direction detection (vertical/horizontal auto)
- Multi-line reordering for vertical text (right-to-left → left-to-right)
- Dictionary lookup (jmdict, etc.)
- Copy-to-clipboard with furigana toggle
- History of recognized text
-
TTS playback (#10) — read recognized Japanese text aloud. Design decisions: (1) neural TTS (VITS/StyleTTS2, Fish Audio) takes raw
TranslationResult.originaldirectly — internal text-to-phoneme handling means no MeCab preprocessing for synthesis (MeCab stays only for HUD furigana/romaji annotation); (2) playback routing via VLC telnet bridge to a remote Windows laptop (synthesis on Linux → HTTP-server the WAV →enqueue/playvia VLC's telnet interface). Seetechnical-design.md§15.
-
Multi-monitor & HiDPI
- Detect all monitors and allow lens to span
- Handle scaling factors correctly on HiDPI displays
- Per-monitor DPI awareness
-
Wayland Security
- Work with portals (xdg-desktop-portal) for screen capture
- Fallback to XWayland compatibility mode if needed
- Request permission for screen capture gracefully
-
Alternative OCR Backends
- Google Cloud Vision (online, paid) via OAuth2
- Microsoft Azure Computer Vision (online, paid)
- Apple Vision framework (macOS port)
-
Machine Learning Integration
- On-device manga-specific model (tiny, fast)
- Text bubble detection with DBNet/ONNX Runtime (Phase 4; model already in assets)
- Preprocessing CNN for denoising and binarization
-
Accessibility Features
- Screen reader integration (Orca, speech-dispatcher)
- High contrast mode
- Configurable font sizes and colors
-
Community & Ecosystem
- Plugin system for interpreters (mecab is now built-in; kuromoji, juman++ as alternatives)
- Shared traineddata repository
- Translation backends (DeepL, Google Translate, offline dictionaries)
-
xfwm4 compositor ghosting (FIXED): Older Electron (36–41) left ghost pixels with xfwm4's built-in compositor. Updating to Electron 42+ resolves it — just ensure xfwm4 compositing is on (
xfconf-query -c xfwm4 -p /general/use_compositing -s true). -
lenzu_servermust be started beforelenzu(Phase 2 fixed this with auto-spawn) - Click-through not yet implemented (window intercepts mouse events)
-
Electron failed to install correctly: Error
Electron failed to install correctly, please delete node_modules/electron and try installing again.-
Resolution: Manually delete
lenzu_server/node_modulesandlenzu_server/pnpm-lock.yaml, then re-runlenzu_server/scripts/setup.sh. This ensures a clean reinstallation of Electron and its dependencies.
-
Resolution: Manually delete
- Full lens image sent on every capture — no pre-filtering yet
- Gemini 2.0 Flash is cheap (~$0.0006/hr in practice) but Phase 4 DBNet pre-detection will cut costs further (~80–93% token reduction per cropped region)
-
Gemma 4 E2B / E4B (Google open-weights VLM,
google/gemma-4-E2B-it/google/gemma-4-E4B-it): 140+ language native support, strong OCR and handwriting recognition, runs fully on-device. Ollama:gemma4:e2b/gemma4:e4b. GGUF (4-bit/8-bit) via Unsloth HuggingFace page. Viable as a zero-cost offline replacement for the remote API. Evaluation tracked in M7b.
- Wayland: not yet supported; X11 only via
x11rb - Multi-monitor: untested with monitors at non-zero offsets
-
Decision: GTK4 (
gtk4-rs0.11) — migrated from GTK3 in June 2026 -
Rationale: Prototype GTK4 migration succeeded (
lenzu-prototypesworkspace). X11 passive grabs (XGrabKey/XGrabButtonvia x11rb) replace GTK4's focus-gated event controllers foroverride_redirectwindows. Cairoset_draw_funconDrawingAreareplaces GTK3'sconnect_drawsignal. (Full migration reference atGTK-Migrations.md.)
-
Linux: Tesseract CLI (via
rusty-tesseractor custom wrapper) - Fallback: If Tesseract fails, try OCR with different PSM or grayscale vs color
- Future: Allow user to switch between engines (Tesseract, manga-ocr, gcloud)
Capture → Grayscale → Denoise (median filter) → Contrast stretch → Binarize (adaptive) → OCR
- Use
imageprocfor filters - Benchmark each step to ensure <100ms total overhead
- Primary: Flatpak (Sandboxed, includes all dependencies)
- Secondary: Debian/Ubuntu PPA
- Tertiary: AppImage for universal Linux distribution
All scripts (setup.sh, build.sh, prereqs.sh, run.sh, install.sh) target Debian-family Linux (apt, dpkg) as the only supported platform. This covers Ubuntu, Debian, Mint, Pop!_OS, and derivatives. Fedora-family (dnf/rpm) is a planned future target; no other distros are in scope. Scripts may assert this with a friendly error if /etc/debian_version is absent.
| Script | Purpose |
|---|---|
scripts/setup.sh |
APT packages + debug cargo build + calls lenzu_server/scripts/setup.sh + ollama/Docker setup |
lenzu_server/scripts/setup.sh |
nvm → Node → pnpm → pnpm install → Electron binary |
scripts/run.sh |
ollama lifecycle (start/stop container) + cargo build -p lenzu (debug) + run client |
Gap: no release build, no installable package, no .desktop entry, and lenzu resolves lenzu_server via CARGO_MANIFEST_DIR at compile time — which breaks outside a git checkout.
The core problem: end users don't want rustc, cargo, tsc, pnpm, or nvm. But ollama/Electron still need to be present at runtime. Splitting into four scripts keeps each one focused:
scripts/
├── prereqs.sh ← NEW: runtime downloader (ollama, model, Electron). No compiler.
├── setup.sh ← EXISTING: dev toolchain (APT, rustc, Node, pnpm). Calls prereqs.sh.
├── build.sh ← NEW: release builder + packager. Calls setup.sh → produces dist/
├── run.sh ← EXISTING: dev loop. Calls prereqs.sh for ollama, then cargo build + run.
└── install.sh ← NEW: end-user installer. Calls prereqs.sh, extracts dist package.
Dependency flow:
install.sh ──calls──► prereqs.sh
setup.sh ──calls──► prereqs.sh
build.sh ──calls──► setup.sh ──calls──► prereqs.sh
run.sh ──calls──► prereqs.sh (ollama lifecycle already inline; may refactor to call prereqs.sh)
Scope: developer scripts only (
setup.sh,build.sh,run.sh).install.shdoes NOT call this.
Idempotent (skips steps already done). No compiler logic. Shared to avoid duplicating the ollama/Docker decision tree that currently lives in both setup.sh and run.sh.
Responsibilities:
-
ollama (developer path — Docker or native, user's choice): same decision tree currently in
setup.sh/run.sh(Docker first, then native install) -
ollama model pull:
gemma4:e2bagainst whatever backend is running -
Electron binary: checks
lenzu_server/node_modules/electron/dist/electron; if absent, runsnode lenzu_server/node_modules/electron/install.js(Node must already be on PATH fromsetup.sh)
Does NOT install: rustc, cargo, node, pnpm, nvm, APT packages.
Flags: --skip-ollama (for CI or OpenRouter-only dev), --skip-electron (for CI builds where the Electron binary is irrelevant)
For developers and CI. Produces a redistributable dist/ package consumed by install.sh.
Steps:
- Call
scripts/setup.sh(ensures dev toolchain present;setup.shcallsprereqs.sh) cargo build --release -p lenzucd lenzu_server && pnpm install --frozen-lockfile && pnpm run build- Download the ollama Linux binary for
x86_64andaarch64from the ollama GitHub releases page intodist/— these become part of the package soinstall.shnever needs to figure out where to get ollama - Assemble
dist/lenzu-<version>/to match the installed layout exactly:Note: the directory is nameddist/lenzu-<version>/ ├── install.sh ← copy of scripts/install.sh (self-contained) ├── bin/ │ └── lenzu-core ← release binary ├── libexec/ │ └── ollama ← ollama binary for target arch (bundled, no Docker) └── share/ └── overlay/ ← HUD renderer (Electron app — internal name only) ├── dist/ ← esbuild output ├── src/ ← static assets └── node_modules/electron/dist/ ← bundled Electron runtime (~200 MB)overlay/in the dist package, notlenzu_server/, so the user-facing concept is "the overlay" not "the server". Internal code and developer docs may still uselenzu_serveras the project name. - Create
dist/lenzu-<version>-linux-x86_64.tar.gz(andaarch64variant)
The package is self-contained: no Docker, no Node, no pnpm, no system package manager needed to install.
Flags:
-
--skip-setup— skipsetup.sh(CI fast-path, toolchain already present) -
--skip-package— build only, no tarball (for local test runs)
Design principle: the user should not need to know what Docker, ollama, Node, cargo, or pnpm are. If they would have to search the internet to understand an error message, the script has failed. Model this on brew install and snap install: everything is managed silently, entirely in userspace, no sudo required.
Audience: anyone who can open a terminal and run a single command. Technical pre-knowledge: none.
What install.sh must never do:
- Ask the user about any software: Docker, ollama, Node, Electron, or anything else
- Require or request
sudo(one exception: if a system library is missing, it prints the exact command for the user to run — see step 3 below) - Detect or reuse any existing software the user may already have installed; lenzu's install is entirely self-contained
- Expose flags or options whose names require technical knowledge (
--skip-electron,--use-docker, etc.) — the only acceptable flags are human-language options like--prefixor--no-desktop-shortcut - Print error messages containing binary names, paths, or jargon that require interpretation
- Leave the user at a prompt asking “which option do you want?”
- Emit more than one screen of output for a successful install
Install layout — fully userspace, fully scoped to lenzu:
~/.local/
├── bin/
│ └── lenzu ← launcher (shell wrapper — the only file the user ever touches)
└── share/
└── lenzu/
├── bin/
│ └── lenzu-core ← main application binary
├── libexec/
│ └── ollama ← bundled AI runtime (private to lenzu)
├── ollama-models/ ← AI model storage (private to lenzu)
├── overlay/ ← HUD renderer (private to lenzu; user never interacts with this)
└── config/
└── lenzu_config.json ← user-editable settings
Everything under ~/.local/share/lenzu/ is implementation detail. The user sees one command: lenzu. All sub-processes (AI runtime, overlay renderer) are managed by lenzu itself — invisible to the user.
The AI runtime binary and model storage are private to lenzu. Lenzu does not share, detect, or conflict with anything the user may already have installed.
Steps:
- Detect arch (
uname -m); abort with a human message if unsupported (e.g.arm32) - Locate the release package:
- If the script is extracted from a tarball, the package is in the same directory
- Otherwise, download
lenzu-<latest>-linux-<arch>.tar.gzfrom the GitHub releases API (no auth required for public releases) with a visible progress bar
- Check for required system libraries (
libgtk-4.so,libcairo.so,libpango-1.0.so):- These are provided by the user's desktop environment — any GNOME, XFCE, or KDE system will have them
- If any are missing: print one friendly sentence (“Lenzu needs one system library. Please run the command below, then re-run this installer:”) followed by the exact
apt installcommand. Exit cleanly. Do not try to install them automatically (that requiressudo).
- Extract the package to
~/.local/share/lenzu/ - Write
~/.local/bin/lenzuas a thin shell wrapper:(The wrapper is how HUD path resolution and private ollama port are injected — no compile-time baking needed.)#!/bin/sh export LENZU_SERVER_PATH=”$HOME/.local/share/lenzu/lenzu_server” export OLLAMA_MODELS=”$HOME/.local/share/lenzu/ollama-models” export OLLAMA_HOST=”127.0.0.1:11435” # private port, avoids colliding with user's system ollama exec “$HOME/.local/share/lenzu/bin/lenzu-core” “$@”
- First-run model download (one time):
- Start the private ollama (
libexec/ollama serve) in the background - Pull
gemma4:e2bintoollama-models/with a human progress message (“Downloading AI model — this is ~2 GB and happens only once…”) - Stop private ollama
- Start the private ollama (
- Add
~/.local/binto PATH if missing: append to~/.bashrcand~/.zshrcsilently; print one note at the end - Optionally install
~/.local/share/applications/lenzu.desktop - Print a single success line:
Lenzu is ready. Type 'lenzu' to start.
The lenzu wrapper is also responsible at runtime for:
- Starting the private ollama before lenzu and stopping it on exit (mirrors what
run.shdoes for dev, but using the private binary and port) - This means
lenzu-corecan always assumeOLLAMA_HOSTis running — no Docker, no system-wide service
install.sh uses port 11435 (not 11434) for lenzu's private ollama. This avoids:
- Conflicts with a developer's own system ollama on
11434 - Any interaction with
run.sh's Docker container - The user needing to know why lenzu is “using” a port they already have occupied
AppConfig must support llm_api_endpoint pointing to http://127.0.0.1:11435/v1/chat/completions. The wrapper script sets OLLAMA_HOST and the default config is written to point at port 11435 during install.
| Decision | Options | Status |
|---|---|---|
| HUD path resolution | Thin shell wrapper at ~/.local/bin/lenzu sets LENZU_SERVER_PATH; lenzu-core reads it at runtime |
Decided — wrapper approach; no compile-time path baking |
| Electron bundling size | (A) ship node_modules/electron/dist/ as-is (~200 MB); (B) electron-builder AppImage (~120 MB) |
Option A first; Option B when Flatpak packaging begins |
| System library check | Check ldconfig -p for GTK4/Cairo/Pango; if missing, print exact sudo apt install libgtk-4-0 libcairo2 libpango-1.0-0 and exit |
Debian-family only (apt); Fedora (dnf) is a future target |
run.sh → build.sh refactor |
keep cargo build inline in run.sh (fast dev loop) vs. call build.sh --debug
|
Keep inline; revisit when build.sh lands |
| Model download progress |
ollama pull prints its own progress; wrap with a friendly preamble explaining the size |
Use ollama CLI directly, prepend message |
-
tesseract-ocr(>=5.0) withjpn_verttraineddata -
libgtk-4-dev(GTK4 >=4.14) -
pkg-configandbuild-essential
-
libwebkit2gtk-4.1-dev— removed from setup.sh; was required by the deprecated Tauri overlay (lenzu_client). Electron bundles its own Chromium — no system WebKit dependency needed.
-
opencv(for advanced preprocessing) - but heavy dependency -
leptonica(Tesseract dependency, usually bundled) -
mecab(alternative interpreter) -
jmdict(dictionary lookup)
- Tesseract Training: Investigate manga109s dataset format and training pipeline
-
Wayland Portals: Study
xdg-desktop-portalAPI for screen capture permissions - Electron overlay positioning: ArrowUp/Down key cycling (top/center/bottom) already implemented in lenzu_server
- Performance Profiling: Profile capture → OCR pipeline to identify bottlenecks
- M1: X11 capture works correctly (bypasses GPU-accelerated windows)
- M2: Structured OCR results via OpenRouter/Gemini multimodal API
- M3: GTK3 lens window with transparent overlay, spinner, flash feedback
- M4: Electron overlay HUD (
lenzu_server) integrated via UDP IPC (migrated from Tauri/WebKit2GTK due to alpha/transparency bugs) - M5: Configurable language pair, render mode, and prompt via
lenzu_config.json - M6:
lenzuauto-spawns/killslenzu_server(Phase 2) - M7b-1: Docker/ollama container lifecycle —
scripts/setup.sh+scripts/run.shstart/stoplenzu-ollamareliably - M7b-2:
OcrClient→ ollama (Gemma 4 E2B as sole backend, no API key required) - M7b-3:
DualOcrClient— automatic fallback to OpenRouter on no-translation;Ctrl+Shift+Clickmanual override to force remote - M7b-4: Fallback preprocessing — grayscale + proportional downscale before OpenRouter call (~70–80% token reduction)
- M7: YOLOv8 pre-detection — find text bounding boxes locally, send only cropped regions (deferred until M7b-4 stable; needs manga-specific ONNX model)
- M8: Wayland support via portals
- M9: Flatpak packaging
- M10:
scripts/prereqs.sh+scripts/build.sh+scripts/install.sh— release binary packaged with bundled Electron,~/.localinstall,PATH/.desktop, runtime HUD path resolution (see Installation — Script Architecture above)
- OCR pipeline with sample images (captured from manga)
- Text reordering algorithm (vertical → horizontal)
- Image preprocessing filters (verify output quality)
- Full capture → OCR → interpreter → render flow
- Multi-monitor setup (capture from secondary monitor)
- Wayland vs X11 backend detection
- Test on various manga styles (shonen, shojo, seinen)
- Different font sizes and qualities (scanned vs digital)
- Mixed vertical/horizontal text layouts
- Accuracy: >90% character recognition on clean manga panels
- Performance: <3s from capture to display on 1080p
-
Usability: Works out-of-the-box on Debian-family systems (Ubuntu 22.04+, Debian 12+, Mint, Pop!_OS, etc.); Fedora-family (
dnf) is a planned future target - Accessibility: Screen reader compatible (Orca)
- Privacy: No network traffic unless user enables online OCR
- GTK3 (gtk-rs): https://gtk-rs.org/gtk3-rs/stable/latest/
- Tesseract Training: https://tesseract-ocr.github.io/tessdoc/Training-Tesseract.html
- Wayland Portals: https://flatpak.org/xdg-desktop-portal/
- Manga109: http://www.manga109.org/
- MeCab: https://taku910.github.io/mecab/
Last Updated: 2026-04-12
Maintainer: Hideki AI
Status: Active development — feature/ocr-local-remote branch, Phase 4 M7b-1 next
Addendum: Notes added that should be later updated to other docs (including this doc):
- Q: How do we generate packages of both lenzu_client and lenzu_server, let alone, other dependency such as ollama, docker, etc?
CodeMonkeyNinja/lenzu · MIT
- technical-design
- technical-design.lens-window
- GTK-Migrations
- technical-design.OCR
- technical-design.manga-ocr
- technical-design.sarashina
- technical-design.phase4-predetect
- technical-design.cancel-inflight