e76d88e0c7
Import the existing Electron + React + TypeScript app as the version-control baseline before the scanner rework (C# input/capture sidecar, resolution-anchored layout profiles, OCR preprocessing, eval harness, rescan-merge, GOOD interop). Housekeeping in this commit: - Remove orphaned temp_inputhelper_block.ts (duplicate of the input-helper script). - Ignore .claude/scheduled_tasks.lock local session state. - Add .gitattributes to normalize line endings (LF in repo). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
145 lines
8.7 KiB
Markdown
145 lines
8.7 KiB
Markdown
# Architecture
|
|
|
|
This document describes the structure, boundaries, flows, and technical rules of the system.
|
|
|
|
## High-Level Overview
|
|
|
|
Genshin Artifact Assistant is a local desktop application. Electron owns OS integration, screen capture, IPC, and overlay windows. React owns the interactive UI. Domain logic for OCR parsing, scoring, scanner state, and recommendations lives in TypeScript modules under `src/lib`.
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
User["User"]
|
|
Genshin["Genshin Impact Window"]
|
|
Electron["Electron Main Process"]
|
|
React["React Renderer"]
|
|
Parser["OCR Parser and Scoring"]
|
|
LocalData["Local Snapshot / Future SQLite"]
|
|
|
|
User --> React
|
|
React --> Electron
|
|
Electron --> Genshin
|
|
Electron --> React
|
|
React --> Parser
|
|
Parser --> React
|
|
React --> LocalData
|
|
```
|
|
|
|
## Architecture Style
|
|
|
|
| Field | Value |
|
|
| --- | --- |
|
|
| Style | Desktop modular monolith |
|
|
| Primary reason | One local app with tight UI, capture, and parsing feedback loops |
|
|
| Main trade-off | Faster iteration now, but scanner heuristics must stay isolated to avoid UI coupling |
|
|
|
|
## Folder Structure
|
|
|
|
```text
|
|
/
|
|
electron/ Electron main process and preload bridge
|
|
src/ React app, domain types, parser/scoring logic
|
|
data/ Seed or package data
|
|
docs/ Project documentation and decisions
|
|
dist/ Generated renderer build
|
|
dist-electron/ Generated Electron build
|
|
outputs/ Packaged app output
|
|
```
|
|
|
|
## Module Responsibilities
|
|
|
|
| Module | Responsibility |
|
|
| --- | --- |
|
|
| `electron/main.ts` | Window lifecycle, capture source listing, Smart Capture, OCR crop generation, overlay window IPC, persistent PowerShell input/capture helper, JSON artifact store |
|
|
| `electron/preload.cjs` | Safe renderer bridge exposed as `window.assistantApi` |
|
|
| `src/lib/artifactStore.ts` | Pure signature/id/record helpers for the persistent artifact store |
|
|
| `src/App.tsx` | Main app shell, scan view, triage view, build view, overlay preview |
|
|
| `src/lib/artifactOcrParser.ts` | Converts OCR output into a parsed artifact candidate with confidence and notes |
|
|
| `src/lib/fuzzyMatch.ts` | Generic fuzzy string matching for OCR text against known game data |
|
|
| `src/lib/scoring.ts` | Recommendation and build scoring logic |
|
|
| `src/lib/demoData.ts` | Temporary local demo snapshot |
|
|
| `src/data/genshinGameData.json` | Generated local dictionary of characters, artifact sets, slots, and stats |
|
|
| `scripts/generate-genshin-data.cjs` | Regenerates the local Genshin dictionary from `genshin-db` |
|
|
| `src/types/*` | Shared app, capture, and domain contracts |
|
|
|
|
## Dependency Rules
|
|
|
|
- Renderer code calls Electron only through the preload bridge.
|
|
- Electron main process must not import React renderer modules.
|
|
- Pure parsing and scoring modules must not depend on Electron APIs.
|
|
- OCR uncertainty must be represented in data, not hidden in UI only.
|
|
- Generated folders must not be treated as source of truth.
|
|
|
|
## Smart Capture Flow
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant UI as React Scan UI
|
|
participant Bridge as Preload Bridge
|
|
participant Main as Electron Main
|
|
participant Game as Genshin Window
|
|
participant OCR as OCR Worker
|
|
|
|
UI->>Bridge: captureSource(sourceId, 0, focusGenshin=true)
|
|
Bridge->>Main: IPC capture:captureSource
|
|
Main->>Main: Hide app window
|
|
Main->>Game: Focus Genshin window
|
|
Main->>Main: Capture primary screen via GDI
|
|
Main->>Main: Detect artifact detail panel
|
|
Main->>OCR: OCR focused crops
|
|
OCR-->>Main: Text and confidence
|
|
Main->>Main: Restore app window
|
|
Main-->>UI: Full capture, detail preview, crops, OCR results
|
|
UI->>UI: Parse candidate and show result
|
|
```
|
|
|
|
## Data Flow
|
|
|
|
| Data | Source | Owner | Consumers |
|
|
| --- | --- | --- | --- |
|
|
| Capture sources | Electron desktopCapturer | Electron main | Scan UI |
|
|
| Screenshot | Windows GDI / desktopCapturer | Electron main | Cropper, OCR, UI preview |
|
|
| OCR crops | Electron main | Electron main | Details modal, parser |
|
|
| Game dictionary | `genshin-db` generated JSON | `src/data/genshinGameData.json` | OCR parser |
|
|
| Parsed artifact candidate | OCR parser | Renderer domain logic | Result panel, future local DB |
|
|
| Review samples | User action in Scan UI | Electron userData `review-samples.jsonl` | Future regression tests and OCR training |
|
|
| Stored artifacts | Manual/automatic scans | Electron userData `artifact-store.json` (dedupe by content signature) | Future triage, recommendations, SQLite migration |
|
|
| Recommendations | Scoring module | Renderer domain logic | Triage and builds views |
|
|
|
|
## Scan Modes
|
|
|
|
**Manual scan** is read-only: the user clicks artifacts in Genshin, the app repeatedly runs Smart Capture, deduplicates by content signature, persists new artifacts to the local store, and saves review samples when crops/OCR are missing, total confidence is low, field confidence is low, or parser notes indicate incomplete data.
|
|
|
|
**Automatic grid scan** is user-triggered input automation limited to clicking detected inventory tiles and wheel-scrolling the inventory. Safety and reliability rules:
|
|
|
|
- All input goes through one persistent PowerShell helper process (`input-helper.ps1` in userData) that compiles the Win32 interop once and speaks JSON over stdin/stdout (ops: ping, focus, cursor, click, scroll, capture). Mouse movement is sent as iterated relative SendInput deltas (what a real mouse produces): Genshin tracks the cursor via raw input and snaps the OS cursor back to its own position every frame, so SetCursorPos/absolute moves silently stop working once the game owns the cursor. The helper verifies the cursor reached the target and refuses to click otherwise.
|
|
- Failsafe: before every click and scroll the renderer polls cursor position and ESC state. Holding ESC or moving the mouse away from the last automated position aborts the scan immediately; the Stop button also aborts. Only the `GetAsyncKeyState` held-down bit (0x8000) is used - the "pressed since last call" bit fires for stale ESC presses from normal Genshin menu navigation and caused false aborts.
|
|
- SendInput's return value is checked: zero injected events (UIPI, e.g. elevated Genshin vs. non-elevated app) aborts with an explicit hint instead of silently clicking into nothing.
|
|
- Click verification: after each click the parsed detail-panel signature should change. An unchanged signature is a soft miss (it can also mean two OCR-identical neighbor pieces, common among +0 artifacts), so it is retried once with a small offset, logged with the stuck artifact name, and then skipped - never fatal on its own. The scan aborts only when the first ~6 clicks of page 1 produce nothing new (diagnosis hint: elevated Genshin blocks SendInput via UIPI, or grid coordinates are wrong) or a later page yields zero new artifacts.
|
|
- Scan stats separate clicked (click attempts), parsed (readable captures), stored (persisted), review (review samples), duplicates, and misses, so "scanned" cannot be mistaken for "successfully read".
|
|
- Scrolling sends one wheel notch per grid row with the cursor anchored over the inventory (assumption: roughly one row per notch; overlap is absorbed by dedupe, and a page without new artifacts stops the scan).
|
|
- The scan never deletes, enhances, feeds, locks, or spends anything; it only selects tiles to read them.
|
|
|
|
Parsed artifacts from both modes are persisted into `artifact-store.json` keyed by a content signature that excludes the equipped character, so re-equipping updates a record instead of duplicating it. Leveling an artifact currently creates a new record (documented limitation until rescan-merge exists).
|
|
|
|
## Security And Safety
|
|
|
|
| Area | Policy |
|
|
| --- | --- |
|
|
| Game access | Screen capture only; no memory reads, hooks, or process injection |
|
|
| Automation | Future feature only, opt-in and reversible |
|
|
| Data privacy | Local-first; no upload path in scanner MVP |
|
|
| Secrets | No cookies or API tokens required for scanner MVP |
|
|
| Unsafe actions | Never delete, feed, enhance, or spend resources |
|
|
|
|
## Error Handling
|
|
|
|
- Capture failures should surface in the scan status row.
|
|
- Missing Electron bridge should explain that browser preview cannot capture Genshin.
|
|
- OCR failures should leave the capture available and mark parsed fields as unknown.
|
|
- Low-confidence data should go to review instead of silent acceptance.
|
|
- Parsed artifact fields carry individual confidence and source metadata so the UI can show uncertainty per field.
|
|
|
|
## Performance
|
|
|
|
Current OCR is prototype-grade and may be slower than the target scanner. Two batch-scan bottlenecks were removed: input/capture no longer spawn a PowerShell process (and recompile Win32 interop) per action, and the Tesseract worker is created once and reused across captures. The eventual batch scanner should still move expensive capture/OCR/build work into workers or a native sidecar.
|