Add: windows mvp - transparent bugs not fixed
This commit is contained in:
80
docs/API_SPEC.md
Normal file
80
docs/API_SPEC.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Sprimo Frontend API Specification (v1)
|
||||
|
||||
Base URL: `http://127.0.0.1:<port>`
|
||||
|
||||
Auth: `Authorization: Bearer <token>` required on all endpoints except `/v1/health`.
|
||||
|
||||
## Endpoints
|
||||
|
||||
### `GET /v1/health`
|
||||
|
||||
- Auth: none
|
||||
- Response `200`:
|
||||
|
||||
```json
|
||||
{
|
||||
"version": "0.1.0",
|
||||
"build": "dev",
|
||||
"uptime_seconds": 12,
|
||||
"active_sprite_pack": "default",
|
||||
"capabilities": {
|
||||
"supports_click_through": true,
|
||||
"supports_transparency": true,
|
||||
"supports_tray": true,
|
||||
"supports_global_hotkey": true,
|
||||
"supports_skip_taskbar": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `GET /v1/state`
|
||||
|
||||
- Auth: required
|
||||
- Response `200`: current frontend snapshot.
|
||||
- Response `401`: missing/invalid token.
|
||||
- Includes optional `last_error` diagnostic field for latest runtime command-application error.
|
||||
|
||||
### `POST /v1/command`
|
||||
|
||||
- Auth: required
|
||||
- Body: one command envelope.
|
||||
- Response `202`: accepted.
|
||||
- Response `400`: malformed JSON.
|
||||
- Response `401`: missing/invalid token.
|
||||
- Runtime note for `SetSpritePack`:
|
||||
- successful load switches sprite atlas immediately.
|
||||
- failed load keeps current in-memory sprite/animation unchanged and reports the failure via `/v1/state.last_error`.
|
||||
|
||||
### `POST /v1/commands`
|
||||
|
||||
- Auth: required
|
||||
- Body: ordered array of command envelopes.
|
||||
- Response `202`: accepted.
|
||||
- Response `400`: malformed JSON.
|
||||
- Response `401`: missing/invalid token.
|
||||
- Commands are applied in-order by the frontend runtime after transport acceptance.
|
||||
|
||||
## Command Envelope
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "2d95f8a8-65cc-4309-8f76-4881949d7f4b",
|
||||
"ts_ms": 1737000000000,
|
||||
"command": {
|
||||
"type": "set_state",
|
||||
"payload": {
|
||||
"state": "active",
|
||||
"ttl_ms": null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Response
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "unauthorized",
|
||||
"message": "missing or invalid bearer token"
|
||||
}
|
||||
```
|
||||
43
docs/ARCHITECTURE.md
Normal file
43
docs/ARCHITECTURE.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Sprimo Frontend Architecture
|
||||
|
||||
## Workspace Layout
|
||||
|
||||
- `crates/sprimo-app`: process entrypoint and runtime wiring.
|
||||
- `crates/sprimo-api`: axum-based localhost control server.
|
||||
- `crates/sprimo-config`: config schema, path resolution, persistence.
|
||||
- `crates/sprimo-platform`: platform abstraction for overlay operations.
|
||||
- `crates/sprimo-protocol`: shared API/state/command protocol types.
|
||||
- `crates/sprimo-sprite`: sprite pack manifest loading and fallback logic.
|
||||
|
||||
## Runtime Data Flow
|
||||
|
||||
1. `sprimo-app` loads or creates `config.toml`.
|
||||
2. App builds initial `FrontendStateSnapshot`.
|
||||
3. App starts `sprimo-api` on a Tokio runtime.
|
||||
4. API authenticates commands and deduplicates IDs.
|
||||
5. Commands are bridged from Tokio channel to Bevy main-thread systems.
|
||||
6. Bevy systems apply commands to sprite state, window/platform operations, and config persistence.
|
||||
7. Shared snapshot is exposed by API via `/v1/state` and `/v1/health`.
|
||||
|
||||
## Sprite Reload Semantics
|
||||
|
||||
- `SetSpritePack` uses a two-phase flow:
|
||||
1. Validate and build candidate pack runtime (manifest + clips + atlas layout + texture handle).
|
||||
2. Commit atomically only on success.
|
||||
- On reload failure, current pack remains active and snapshot `last_error` is updated.
|
||||
|
||||
## Threading Model
|
||||
|
||||
- Main task: startup + shutdown signal.
|
||||
- API task: axum server.
|
||||
- Bridge task: forwards API commands into Bevy ingest channel.
|
||||
- Bevy main thread: rendering, animation, command application, and window behavior.
|
||||
- Optional hotkey thread (Windows): registers global hotkey and pushes recovery events.
|
||||
- Snapshot is shared via `Arc<RwLock<_>>`.
|
||||
|
||||
## Design Constraints
|
||||
|
||||
- Bind API to localhost only.
|
||||
- Token auth by default for mutating and state endpoints.
|
||||
- Keep protocol crate renderer-agnostic for future backend/frontend reuse.
|
||||
- Keep platform crate isolated for per-OS implementations.
|
||||
45
docs/CONFIG_REFERENCE.md
Normal file
45
docs/CONFIG_REFERENCE.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Sprimo Config Reference
|
||||
|
||||
File location:
|
||||
|
||||
- Windows: `%APPDATA%/sprimo/config.toml`
|
||||
- macOS: `~/Library/Application Support/sprimo/config.toml`
|
||||
- Linux: `~/.config/sprimo/config.toml`
|
||||
|
||||
## Schema
|
||||
|
||||
```toml
|
||||
[window]
|
||||
x = 200.0
|
||||
y = 200.0
|
||||
monitor_id = ""
|
||||
scale = 1.0
|
||||
always_on_top = true
|
||||
click_through = false
|
||||
visible = true
|
||||
|
||||
[animation]
|
||||
fps = 30
|
||||
idle_timeout_ms = 3000
|
||||
|
||||
[sprite]
|
||||
selected_pack = "default"
|
||||
sprite_packs_dir = "sprite-packs"
|
||||
|
||||
[api]
|
||||
port = 32145
|
||||
auth_token = "generated-uuid-token"
|
||||
|
||||
[logging]
|
||||
level = "info"
|
||||
|
||||
[controls]
|
||||
hotkey_enabled = true
|
||||
recovery_hotkey = "Ctrl+Alt+P"
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- `auth_token` is generated on first run if config does not exist.
|
||||
- `window.x`, `window.y`, `window.scale`, and flag fields are persisted after matching commands.
|
||||
- On Windows, `recovery_hotkey` provides click-through recovery even when the window is non-interactive.
|
||||
497
docs/FRONTEND_REQUIREMENTS.md
Normal file
497
docs/FRONTEND_REQUIREMENTS.md
Normal file
@@ -0,0 +1,497 @@
|
||||
## Frontend Requirements Document — **sprimo-frontend**
|
||||
|
||||
**Document type:** Product + Engineering requirements (frontend scope only)
|
||||
**Version:** v0.1
|
||||
**Date:** 2026-02-12
|
||||
**Scope:** Bevy-based overlay renderer + local control server + minimal UI.
|
||||
**Out of scope:** Backend detection/rules engine (assumed external), cloud services.
|
||||
|
||||
---
|
||||
|
||||
# 1. Overview
|
||||
|
||||
The frontend is a **desktop overlay pet renderer** implemented in Rust (Bevy). It presents an animated character in a **transparent, borderless window** that can be **always-on-top** and optionally **click-through**. It receives control instructions from a local backend process via **localhost REST API**, applies them to its animation/state machine, and persists user preferences locally.
|
||||
|
||||
The frontend must be able to run standalone (idle animation) even if the backend is not running.
|
||||
|
||||
---
|
||||
|
||||
# 2. Goals
|
||||
|
||||
> Note: Windows and Linux should be first-hand support, macOS support is optional.
|
||||
|
||||
1. **Render a cute animated character overlay** with smooth sprite animation.
|
||||
2. Provide a **stable command interface** (REST) for backend control.
|
||||
3. Offer **essential user controls** (tray/menu + hotkeys optional) to avoid “locking” the pet in click-through mode.
|
||||
4. Persist **window position, scale, sprite pack choice, and flags**.
|
||||
5. Be **cross-platform** (Windows/macOS/Linux) with documented degradations, especially on Linux Wayland.
|
||||
|
||||
---
|
||||
|
||||
# 3. Non-Goals (Frontend v0.1)
|
||||
|
||||
* Tool activity detection (backend responsibility).
|
||||
* Online sprite gallery, accounts, telemetry.
|
||||
* Complex rigged animation (Live2D/3D). Sprite atlas only.
|
||||
* Full settings UI panel (tray + config file is enough for v0.1).
|
||||
|
||||
---
|
||||
|
||||
# 4. User Stories
|
||||
|
||||
## Core
|
||||
|
||||
* As a user, I can see the pet on my desktop immediately after launch.
|
||||
* As a user, I can drag the pet to a preferred location.
|
||||
* As a user, I can toggle click-through so the pet doesn’t block my mouse.
|
||||
* As a user, I can toggle always-on-top so the pet stays visible.
|
||||
* As a user, I can change the character (sprite pack).
|
||||
|
||||
## Backend control
|
||||
|
||||
* As a backend process, I can instruct the frontend to play specific animations and switch states via REST.
|
||||
* As a backend process, I can update position/scale/visibility.
|
||||
* As a backend process, I can query frontend health/version.
|
||||
|
||||
## Safety
|
||||
|
||||
* As a user, I can always recover control of the pet even if click-through is enabled (hotkey/tray item).
|
||||
|
||||
---
|
||||
|
||||
# 5. Functional Requirements
|
||||
|
||||
## 5.1 Window & Overlay Behavior
|
||||
|
||||
### FR-FW-1 Borderless + transparent
|
||||
|
||||
* Window must be **borderless** and **no title bar**.
|
||||
* Background must be **transparent** so only the pet is visible.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Screenshot shows only pet pixels; underlying desktop visible.
|
||||
* No OS window chrome visible.
|
||||
|
||||
### FR-FW-2 Always-on-top
|
||||
|
||||
* Support always-on-top toggle.
|
||||
* Default: ON (configurable).
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* When ON, window stays above normal windows.
|
||||
|
||||
### FR-FW-3 Click-through (mouse pass-through)
|
||||
|
||||
* Support enabling/disabling click-through:
|
||||
|
||||
* ON: mouse events pass to windows underneath.
|
||||
* OFF: pet receives mouse input (drag, context menu).
|
||||
* Must provide a **failsafe** mechanism to disable click-through without clicking the pet.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* With click-through enabled, user can click apps behind pet.
|
||||
* User can disable click-through via tray or hotkey reliably.
|
||||
|
||||
### FR-FW-4 Dragging & anchoring
|
||||
|
||||
* When click-through is OFF, user can drag the pet.
|
||||
* Dragging updates persisted position in config.
|
||||
* Optional: snapping to screen edges.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Drag works smoothly, without major jitter.
|
||||
* Relaunch restores position.
|
||||
|
||||
### FR-FW-5 Multi-monitor + DPI
|
||||
|
||||
* Window positioning must respect:
|
||||
|
||||
* multiple monitors
|
||||
* per-monitor DPI scaling
|
||||
* Position stored in a device-independent way where possible.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Pet stays at expected corner after moving between monitors.
|
||||
|
||||
### FR-FW-6 Taskbar/Dock visibility
|
||||
|
||||
* Prefer not showing a taskbar entry for the overlay window (where supported).
|
||||
* If not feasible cross-platform, document behavior.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* On Windows/macOS: overlay window ideally hidden from taskbar/dock.
|
||||
* If not implemented, doesn’t break core usage.
|
||||
|
||||
### Platform notes (requirements)
|
||||
|
||||
* **Windows:** click-through uses extended window styles (WS_EX_TRANSPARENT / layered), always-on-top via SetWindowPos.
|
||||
* **macOS:** NSWindow level + ignoresMouseEvents.
|
||||
* **Linux:** best effort:
|
||||
|
||||
* X11: possible with shape/input region.
|
||||
* Wayland: click-through may be unavailable; document limitation.
|
||||
|
||||
---
|
||||
|
||||
## 5.2 Rendering & Animation
|
||||
|
||||
### FR-ANI-1 Sprite pack format
|
||||
|
||||
Frontend must load sprite packs from local disk with:
|
||||
|
||||
* `manifest.json` (required)
|
||||
* atlas image(s) (PNG; required)
|
||||
* optional metadata (author, license, preview)
|
||||
|
||||
**Manifest must define:**
|
||||
|
||||
* sprite sheet dimensions and frame rects (or grid)
|
||||
* animations: name → ordered frame list + fps
|
||||
* anchor point (pivot) for positioning
|
||||
* optional hitbox (for drag region)
|
||||
* optional offsets per frame (advanced)
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Default bundled pack loads with no config.
|
||||
* Invalid packs fail gracefully with error message/log and fallback to default pack.
|
||||
|
||||
### FR-ANI-2 Animation playback
|
||||
|
||||
* Play loop animations (idle/dance).
|
||||
* Support one-shot animations (celebrate/error) with:
|
||||
|
||||
* duration or “until frames complete”
|
||||
* return-to-previous-state behavior
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Switching animations is immediate and consistent.
|
||||
|
||||
### FR-ANI-3 FPS control
|
||||
|
||||
* Configurable target FPS for animation updates (e.g., 30/60).
|
||||
* Rendering should remain stable.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Low CPU usage when idle animation running.
|
||||
|
||||
### FR-ANI-4 Layering
|
||||
|
||||
* Single character is mandatory for v0.1.
|
||||
* Optional: accessory layers (future).
|
||||
|
||||
---
|
||||
|
||||
## 5.3 State Machine & Command Application
|
||||
|
||||
### FR-STM-1 Core states
|
||||
|
||||
Frontend supports at minimum:
|
||||
|
||||
* `Idle`
|
||||
* `Active`
|
||||
* `Success`
|
||||
* `Error`
|
||||
* `Dragging` (internal)
|
||||
* `Hidden` (window hidden but process alive)
|
||||
|
||||
Each state maps to a default animation (configurable by sprite pack):
|
||||
|
||||
* Idle → idle animation
|
||||
* Active → typing/dance
|
||||
* Success → celebrate then return to Active/Idle
|
||||
* Error → upset then return
|
||||
|
||||
### FR-STM-2 Transition rules
|
||||
|
||||
* Backend commands can:
|
||||
|
||||
* set state directly
|
||||
* request specific animation with priority
|
||||
* Frontend must implement:
|
||||
|
||||
* debouncing/cooldown (avoid flicker)
|
||||
* priority arbitration (e.g., Error overrides Active)
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Repeated Active commands don’t restart animation constantly.
|
||||
* Error state overrides Active for N seconds.
|
||||
|
||||
### FR-STM-3 Local autonomy (no backend)
|
||||
|
||||
* If backend is absent:
|
||||
|
||||
* frontend stays in Idle with periodic idle animation
|
||||
* user controls still function
|
||||
* If backend connects later, commands apply immediately.
|
||||
|
||||
---
|
||||
|
||||
## 5.4 REST Control Server (Frontend-hosted)
|
||||
|
||||
### FR-API-1 Local binding only
|
||||
|
||||
* HTTP server must bind to `127.0.0.1` by default.
|
||||
* Port configurable; recommended default fixed port (e.g., 32145).
|
||||
|
||||
### FR-API-2 Authentication token
|
||||
|
||||
* Frontend generates a random token on first run.
|
||||
* Stored in local config directory.
|
||||
* Backend must provide `Authorization: Bearer <token>` for all non-health endpoints.
|
||||
* Health endpoint may be unauthenticated (optional).
|
||||
|
||||
### FR-API-3 Endpoints (v0.1)
|
||||
|
||||
**Required:**
|
||||
|
||||
* `GET /v1/health`
|
||||
|
||||
* returns: version, build, uptime, active_sprite_pack
|
||||
* `POST /v1/command`
|
||||
|
||||
* accept a single command
|
||||
* `POST /v1/commands`
|
||||
|
||||
* accept batch of commands
|
||||
* `GET /v1/state` (debug)
|
||||
|
||||
* current state, current animation, flags, position/scale
|
||||
|
||||
**Command types required:**
|
||||
|
||||
* `SetState { state, ttl_ms? }`
|
||||
* `PlayAnimation { name, priority, duration_ms?, interrupt? }`
|
||||
* `SetSpritePack { pack_id_or_path }`
|
||||
* `SetTransform { x?, y?, anchor?, scale?, opacity? }`
|
||||
* `SetFlags { click_through?, always_on_top?, visible? }`
|
||||
* `Toast { text, ttl_ms? }` (optional but recommended)
|
||||
|
||||
### FR-API-4 Idempotency & dedupe
|
||||
|
||||
* Commands include:
|
||||
|
||||
* `id` (ULID/UUID)
|
||||
* `ts_ms`
|
||||
* Frontend must ignore duplicate command IDs for a short window (e.g., last 5k IDs or last 10 minutes).
|
||||
|
||||
### FR-API-5 Error handling
|
||||
|
||||
* Invalid commands return 400 with error details.
|
||||
* Auth failure returns 401.
|
||||
* Server never crashes due to malformed input.
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* Fuzzing basic JSON payload does not crash.
|
||||
|
||||
---
|
||||
|
||||
## 5.5 User Controls
|
||||
|
||||
### FR-CTL-1 Tray/menu bar controls (preferred)
|
||||
|
||||
Provide tray/menu bar items:
|
||||
|
||||
* Show/Hide
|
||||
* Toggle Click-through
|
||||
* Toggle Always-on-top
|
||||
* Sprite Pack selection (at least “Default” + “Open sprite folder…”)
|
||||
* Reload sprite packs
|
||||
* Quit
|
||||
|
||||
If tray is too hard on Linux in v0.1, provide a fallback (hotkey + config).
|
||||
|
||||
### FR-CTL-2 Hotkeys (failsafe)
|
||||
|
||||
At minimum one global hotkey:
|
||||
|
||||
* Toggle click-through OR “enter interactive mode”
|
||||
|
||||
Example default:
|
||||
|
||||
* `Ctrl+Alt+P` (Windows/Linux), `Cmd+Option+P` (macOS)
|
||||
|
||||
**Acceptance**
|
||||
|
||||
* User can recover control even if pet is click-through and cannot be clicked.
|
||||
|
||||
### FR-CTL-3 Context menu (optional)
|
||||
|
||||
Right click pet (when interactive) to open a minimal menu.
|
||||
|
||||
---
|
||||
|
||||
## 5.6 Persistence & Configuration
|
||||
|
||||
### FR-CFG-1 Config storage
|
||||
|
||||
* Store config in OS-appropriate directory:
|
||||
|
||||
* Windows: `%APPDATA%/sprimo/config.toml`
|
||||
* macOS: `~/Library/Application Support/sprimo/config.toml`
|
||||
* Linux: `~/.config/sprimo/config.toml`
|
||||
|
||||
### FR-CFG-2 Config fields
|
||||
|
||||
* window:
|
||||
|
||||
* position (x,y) + monitor id (best-effort)
|
||||
* scale
|
||||
* always_on_top
|
||||
* click_through
|
||||
* visible
|
||||
* animation:
|
||||
|
||||
* fps
|
||||
* idle_timeout_ms
|
||||
* sprite:
|
||||
|
||||
* selected_pack
|
||||
* sprite_packs_dir
|
||||
* api:
|
||||
|
||||
* port
|
||||
* auth_token
|
||||
* logging:
|
||||
|
||||
* level
|
||||
|
||||
### FR-CFG-3 Live reload (nice-to-have)
|
||||
|
||||
* v0.1: reload on tray action (“Reload config”).
|
||||
* v0.2+: auto reload.
|
||||
|
||||
---
|
||||
|
||||
## 5.7 Logging & Diagnostics
|
||||
|
||||
### FR-LOG-1 Logging
|
||||
|
||||
* Log to file + console (configurable).
|
||||
* Include:
|
||||
|
||||
* API requests summary
|
||||
* command application
|
||||
* sprite pack load errors
|
||||
* platform overlay operations outcomes
|
||||
|
||||
### FR-LOG-2 Diagnostics endpoint (optional)
|
||||
|
||||
* `GET /v1/diag` returns recent errors and platform capability flags.
|
||||
|
||||
---
|
||||
|
||||
# 6. Non-Functional Requirements
|
||||
|
||||
## Performance
|
||||
|
||||
* Idle: < 2% CPU on typical dev laptop (target).
|
||||
* Memory: should not grow unbounded; texture caching bounded.
|
||||
|
||||
## Reliability
|
||||
|
||||
* Should run for 8 hours without crash under command load.
|
||||
* If REST server fails to bind port, show clear error and fallback behavior.
|
||||
|
||||
## Security
|
||||
|
||||
* Localhost only binding.
|
||||
* Token auth by default.
|
||||
* No file system access beyond sprite/config/log directories.
|
||||
|
||||
## Compatibility
|
||||
|
||||
* Windows 10/11
|
||||
* macOS 12+ recommended
|
||||
* Linux:
|
||||
|
||||
* X11 supported
|
||||
* Wayland: documented limitations, still runs
|
||||
|
||||
---
|
||||
|
||||
# 7. Platform Capability Matrix (deliverable)
|
||||
|
||||
Frontend must expose in logs (and optionally `/v1/health`) capability flags:
|
||||
|
||||
* `supports_click_through`
|
||||
* `supports_transparency`
|
||||
* `supports_tray`
|
||||
* `supports_global_hotkey`
|
||||
* `supports_skip_taskbar`
|
||||
|
||||
Example:
|
||||
|
||||
* Windows: all true
|
||||
* macOS: all true
|
||||
* Linux X11: most true
|
||||
* Linux Wayland: click-through likely false, skip-taskbar variable
|
||||
|
||||
---
|
||||
|
||||
# 8. Acceptance Test Plan (v0.1)
|
||||
|
||||
## Window
|
||||
|
||||
1. Launch: window appears borderless & transparent.
|
||||
2. Drag: with click-through OFF, drag updates position; restart restores.
|
||||
3. Click-through: toggle via hotkey; pet becomes non-interactive; toggle back works.
|
||||
4. Always-on-top: verify staying above typical apps.
|
||||
|
||||
## Animation
|
||||
|
||||
1. Default pack: idle animation loops.
|
||||
2. Command: `PlayAnimation("dance")` plays immediately.
|
||||
3. One-shot: `Success` plays then returns to previous.
|
||||
|
||||
## API
|
||||
|
||||
1. Health returns correct version/build.
|
||||
2. Auth required for commands; invalid token rejected.
|
||||
3. Batch endpoint applies multiple commands in order.
|
||||
4. Malformed JSON returns 400, app remains running.
|
||||
|
||||
## Persistence
|
||||
|
||||
1. Settings persist across restart.
|
||||
2. Missing sprite pack falls back to default.
|
||||
|
||||
---
|
||||
|
||||
# 9. Implementation Constraints / Suggested Stack (not mandatory but recommended)
|
||||
|
||||
* Renderer/engine: **Bevy 2D**
|
||||
* REST server: **axum + tokio** in background thread
|
||||
* Shared protocol: `protocol` crate with `serde` structs
|
||||
* Platform overlay: separate crate/module with per-OS implementations:
|
||||
|
||||
* Windows: `windows` crate (Win32 APIs)
|
||||
* macOS: `objc2`/`cocoa` bindings
|
||||
* Linux X11: `x11rb` (best effort)
|
||||
* Config: `toml`
|
||||
* IDs: `ulid` or `uuid`
|
||||
|
||||
---
|
||||
|
||||
# 10. Open Questions (Frontend)
|
||||
|
||||
1. Do we require Linux Wayland support beyond “runs but limited overlay features”?
|
||||
2. Do we want multiple pets (multiple windows) in v0.1 or later?
|
||||
3. Do we embed a default sprite pack (license?), or ship an empty skeleton?
|
||||
|
||||
---
|
||||
|
||||
If you want, I can turn this into:
|
||||
|
||||
* a `docs/FRONTEND_REQUIREMENTS.md`
|
||||
* plus a concrete **REST API spec** (OpenAPI-like) and a **sprite-pack manifest schema** with examples (JSON).
|
||||
26
docs/IMPLEMENTATION_STATUS.md
Normal file
26
docs/IMPLEMENTATION_STATUS.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Sprimo Frontend Implementation Status
|
||||
|
||||
Date: 2026-02-12
|
||||
|
||||
## MVP Vertical Slice
|
||||
|
||||
| Area | Status | Notes |
|
||||
|------|--------|-------|
|
||||
| Workspace split | Implemented | `sprimo-app`, `sprimo-api`, `sprimo-config`, `sprimo-platform`, `sprimo-protocol`, `sprimo-sprite` |
|
||||
| Local REST server | Implemented | `/v1/health`, `/v1/state`, `/v1/command`, `/v1/commands`; localhost bind and bearer auth |
|
||||
| Command/state pipeline | Implemented | Command queue, state snapshot updates, transient state TTL rollback |
|
||||
| Config persistence | Implemented | `config.toml` bootstrap/load/save with generated token |
|
||||
| Sprite pack contract | Implemented | `manifest.json` loader and selected->default fallback |
|
||||
| Platform abstraction | Implemented | Windows adapter now applies click-through/top-most/visibility/position using Win32 APIs |
|
||||
| Overlay rendering | Implemented (MVP) | Bevy runtime with transparent undecorated window, sprite playback, command bridge |
|
||||
| Global failsafe | Implemented (Windows) | Global recovery hotkey `Ctrl+Alt+P` disables click-through and forces visibility |
|
||||
| Embedded default pack | Implemented | Bundled under `assets/sprite-packs/default/` using `sprite.png` (8x7, 512x512 frames) |
|
||||
| Build/package automation | Implemented (Windows) | `justfile` and `scripts/package_windows.py` generate portable ZIP + SHA256 |
|
||||
| QA/documentation workflow | Implemented | `docs/QA_WORKFLOW.md`, issue/evidence templates, and `scripts/qa_validate.py` with `just qa-validate` |
|
||||
|
||||
## Next Major Gaps
|
||||
|
||||
1. Tray/menu controls are still not implemented.
|
||||
2. Linux/macOS overlay behavior remains best-effort with no-op platform adapter.
|
||||
3. `/v1/state` diagnostics are minimal; error history is not persisted beyond latest runtime error.
|
||||
4. Issue 1 runtime after-fix screenshot evidence is still pending before closure.
|
||||
62
docs/ISSUE_TEMPLATE.md
Normal file
62
docs/ISSUE_TEMPLATE.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Issue Template (`issues/issueN.md`)
|
||||
|
||||
## Title
|
||||
|
||||
## Severity
|
||||
|
||||
## Environment
|
||||
|
||||
- OS:
|
||||
- App version/build:
|
||||
- Renderer/backend details:
|
||||
|
||||
## Summary
|
||||
|
||||
## Reproduction Steps
|
||||
|
||||
1.
|
||||
2.
|
||||
|
||||
## Expected Result
|
||||
|
||||
## Actual Result
|
||||
|
||||
## Root Cause Analysis
|
||||
|
||||
## Fix Plan
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
## Verification
|
||||
|
||||
### Commands Run
|
||||
|
||||
- [ ] `cargo check --workspace`
|
||||
- [ ] `cargo test --workspace`
|
||||
- [ ] `just qa-validate`
|
||||
|
||||
### Visual Checklist
|
||||
|
||||
- [ ] Before screenshot(s): `issues/screenshots/issueN-before-YYYYMMDD-HHMMSS.png`
|
||||
- [ ] After screenshot(s): `issues/screenshots/issueN-after-YYYYMMDD-HHMMSS.png`
|
||||
|
||||
### Result
|
||||
|
||||
- Status:
|
||||
- Notes:
|
||||
|
||||
## Status History
|
||||
|
||||
- `YYYY-MM-DD HH:MM` - `<actor>` - `Reported` - note
|
||||
|
||||
## Closure
|
||||
|
||||
- Current Status: `Reported`
|
||||
- Close Date:
|
||||
- Owner:
|
||||
- Linked PR/commit:
|
||||
|
||||
## Original Report (if migrated)
|
||||
|
||||
Paste the initial report verbatim when migrating legacy issues.
|
||||
|
||||
41
docs/MVP_ACCEPTANCE.md
Normal file
41
docs/MVP_ACCEPTANCE.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# MVP Acceptance Checklist
|
||||
|
||||
## API
|
||||
|
||||
- [x] `GET /v1/health` returns version/build/uptime and active sprite pack.
|
||||
- [x] `GET /v1/state` requires bearer token.
|
||||
- [x] `POST /v1/command` requires bearer token and returns `202` for valid command.
|
||||
- [x] `POST /v1/commands` accepts batch in-order.
|
||||
- [x] malformed JSON returns `400`, server remains alive.
|
||||
|
||||
## Command Pipeline
|
||||
|
||||
- [x] duplicate command IDs are ignored within dedupe window.
|
||||
- [x] `SetState` updates state and default animation mapping.
|
||||
- [x] transient state with `ttl_ms` returns to durable state.
|
||||
- [x] `SetTransform` persists x/y/scale.
|
||||
- [x] `SetFlags` persists click-through/always-on-top/visible.
|
||||
|
||||
## Config
|
||||
|
||||
- [x] first run bootstraps `config.toml`.
|
||||
- [x] `auth_token` generated and reused across restarts.
|
||||
|
||||
## Sprite
|
||||
|
||||
- [x] selected sprite pack loads when present.
|
||||
- [x] missing selected pack falls back to `default`.
|
||||
- [x] runtime `SetSpritePack` successfully switches pack without restart.
|
||||
- [x] failed runtime `SetSpritePack` keeps current visuals and reports error in state snapshot.
|
||||
|
||||
## Platform
|
||||
|
||||
- [x] capability flags are exposed in `/v1/health`.
|
||||
- [x] non-supported platform operations do not crash the process.
|
||||
|
||||
## Evidence
|
||||
|
||||
- `cargo test --workspace` passes.
|
||||
- API auth coverage exists in `crates/sprimo-api/src/lib.rs` tests.
|
||||
- Config bootstrap and roundtrip coverage exists in `crates/sprimo-config/src/lib.rs` tests.
|
||||
- Sprite fallback coverage exists in `crates/sprimo-sprite/src/lib.rs` tests.
|
||||
17
docs/PLATFORM_CAPABILITY_MATRIX.md
Normal file
17
docs/PLATFORM_CAPABILITY_MATRIX.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Platform Capability Matrix (MVP)
|
||||
|
||||
Date: 2026-02-12
|
||||
|
||||
| Capability | Windows | Linux X11 | Linux Wayland | macOS |
|
||||
|------------|---------|-----------|---------------|-------|
|
||||
| `supports_click_through` | true (implemented) | false (current) | false | false (current) |
|
||||
| `supports_transparency` | true | true | true | true |
|
||||
| `supports_tray` | false (current) | false (current) | false (current) | false (current) |
|
||||
| `supports_global_hotkey` | true (implemented) | false (current) | false (current) | false (current) |
|
||||
| `supports_skip_taskbar` | true (target) | false (current) | false (current) | false (current) |
|
||||
|
||||
## Notes
|
||||
|
||||
- Current code applies real Win32 operations for click-through, visibility, top-most, and positioning.
|
||||
- Non-Windows targets currently use a no-op adapter with conservative flags.
|
||||
- Wayland limitations remain an expected degradation in v0.1.
|
||||
38
docs/QA_EVIDENCE_TEMPLATE.md
Normal file
38
docs/QA_EVIDENCE_TEMPLATE.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# QA Evidence Template
|
||||
|
||||
Use this block inside `issues/issueN.md` under `## Verification`.
|
||||
|
||||
```md
|
||||
### Commands Run
|
||||
|
||||
- [ ] `cargo check --workspace`
|
||||
- [ ] `cargo test --workspace`
|
||||
- [ ] `just qa-validate`
|
||||
|
||||
### Command Output Summary
|
||||
|
||||
- `cargo check --workspace`: pass/fail, key notes
|
||||
- `cargo test --workspace`: pass/fail, key notes
|
||||
- `just qa-validate`: pass/fail, key notes
|
||||
|
||||
### Screenshots
|
||||
|
||||
- Before:
|
||||
- `issues/screenshots/issueN-before-YYYYMMDD-HHMMSS.png`
|
||||
- After:
|
||||
- `issues/screenshots/issueN-after-YYYYMMDD-HHMMSS.png`
|
||||
|
||||
### Visual Assertions
|
||||
|
||||
- [ ] Overlay is transparent where expected
|
||||
- [ ] Window size/placement behavior matches expected result
|
||||
- [ ] Sprite/background alpha behavior matches expected result
|
||||
|
||||
### Reviewer Record
|
||||
|
||||
- Date:
|
||||
- Verified by:
|
||||
- Final result:
|
||||
- Notes:
|
||||
```
|
||||
|
||||
85
docs/QA_WORKFLOW.md
Normal file
85
docs/QA_WORKFLOW.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Sprimo QA and Documentation Workflow
|
||||
|
||||
## Purpose
|
||||
|
||||
This workflow defines how bug reports, runtime evidence, and documentation updates are
|
||||
maintained so every issue is auditable from first report to closure.
|
||||
|
||||
## Issue Lifecycle
|
||||
|
||||
All issues use a single file: `issues/issueN.md`.
|
||||
|
||||
Allowed lifecycle states:
|
||||
|
||||
1. `Reported`
|
||||
2. `Triaged`
|
||||
3. `In Progress`
|
||||
4. `Fix Implemented`
|
||||
5. `Verification Passed`
|
||||
6. `Closed`
|
||||
|
||||
Each state transition must include:
|
||||
|
||||
- local timestamp (`YYYY-MM-DD HH:MM`)
|
||||
- actor
|
||||
- short note
|
||||
- evidence links when available
|
||||
|
||||
## Evidence Requirements
|
||||
|
||||
Screenshots are stored under `issues/screenshots/`.
|
||||
|
||||
Naming convention:
|
||||
|
||||
- before: `issueN-before-YYYYMMDD-HHMMSS.png`
|
||||
- after: `issueN-after-YYYYMMDD-HHMMSS.png`
|
||||
- optional checkpoint suffix: `-step1`, `-step2`
|
||||
|
||||
For UI/runtime behavior bugs:
|
||||
|
||||
- at least one before screenshot is required at report/triage time
|
||||
- at least one after screenshot is required before `Verification Passed` or `Closed`
|
||||
|
||||
Legacy reports may keep `issues/screenshots/issueN.png` as before evidence.
|
||||
|
||||
## Verification Gate
|
||||
|
||||
Before marking an issue `Closed`, all conditions must be met:
|
||||
|
||||
1. Relevant checks/tests are recorded:
|
||||
- `cargo check --workspace`
|
||||
- `cargo test --workspace` (or documented rationale for targeted tests)
|
||||
2. Visual checklist is completed with before/after screenshot references.
|
||||
3. Docs are synchronized:
|
||||
- `issues/issueN.md` lifecycle and verification sections updated
|
||||
- impacted files under `docs/` updated when behavior/spec/status changed
|
||||
|
||||
## Documentation Sync Rules
|
||||
|
||||
Update these files when applicable:
|
||||
|
||||
- `docs/IMPLEMENTATION_STATUS.md` for milestone-level implementation status
|
||||
- `docs/RELEASE_TESTING.md` when release/manual QA steps change
|
||||
- `docs/API_SPEC.md`, `docs/CONFIG_REFERENCE.md`, or other contracts if behavior changed
|
||||
|
||||
## Command Checklist
|
||||
|
||||
Minimum command set for fix validation:
|
||||
|
||||
```powershell
|
||||
cargo check --workspace
|
||||
cargo test --workspace
|
||||
just qa-validate
|
||||
```
|
||||
|
||||
For runtime behavior issues, include screenshot capture paths in the issue file.
|
||||
|
||||
## Definition of Done
|
||||
|
||||
An issue is done only when:
|
||||
|
||||
- lifecycle state is `Closed`
|
||||
- verification gate passed
|
||||
- evidence links resolve to files in repository
|
||||
- `just qa-validate` passes
|
||||
|
||||
72
docs/RELEASE_TESTING.md
Normal file
72
docs/RELEASE_TESTING.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Release Packaging and Behavior Testing (Windows)
|
||||
|
||||
## Artifact Layout
|
||||
|
||||
Current release package type: portable ZIP.
|
||||
|
||||
Expected contents:
|
||||
|
||||
- `sprimo-app.exe`
|
||||
- `assets/sprite-packs/default/manifest.json`
|
||||
- `assets/sprite-packs/default/sprite.png`
|
||||
- `README.txt`
|
||||
|
||||
Generated outputs:
|
||||
|
||||
- `dist/sprimo-windows-x64-v<version>.zip`
|
||||
- `dist/sprimo-windows-x64-v<version>.zip.sha256`
|
||||
|
||||
## Commands
|
||||
|
||||
Use `just` for command entry:
|
||||
|
||||
```powershell
|
||||
just check
|
||||
just test
|
||||
just build-release
|
||||
just package-win
|
||||
just smoke-win
|
||||
```
|
||||
|
||||
`just package-win` calls `scripts/package_windows.py package`.
|
||||
`just smoke-win` calls `scripts/package_windows.py smoke`.
|
||||
|
||||
## Behavior Test Checklist (Packaged App)
|
||||
|
||||
Run tests from an unpacked ZIP folder, not from the workspace run.
|
||||
|
||||
1. Launch `sprimo-app.exe`; verify default sprite renders.
|
||||
2. Verify no terminal window appears when launching release build by double-click.
|
||||
3. Verify global hotkey recovery (`Ctrl+Alt+P`) forces interactive mode.
|
||||
4. Verify click-through and always-on-top toggles via API commands.
|
||||
5. Verify `/v1/health` and `/v1/state` behavior with auth.
|
||||
6. Verify `SetSpritePack`:
|
||||
- valid pack switches runtime visuals
|
||||
- invalid pack keeps current visuals and sets `last_error`
|
||||
7. Restart app and verify persisted config behavior.
|
||||
8. Confirm overlay background is transparent (desktop visible behind non-sprite pixels).
|
||||
9. Confirm no magenta matte remains around sprite in default pack.
|
||||
|
||||
## Test Log Template
|
||||
|
||||
- Date:
|
||||
- Artifact:
|
||||
- Commit:
|
||||
- Tester:
|
||||
- Result:
|
||||
- Notes:
|
||||
|
||||
## Issue Evidence Gate
|
||||
|
||||
Before release sign-off for a bug fix:
|
||||
|
||||
1. Link the issue file (`issues/issueN.md`) in the test log.
|
||||
2. Ensure before/after screenshot evidence is referenced from the issue:
|
||||
- before: `issues/screenshots/issueN-before-YYYYMMDD-HHMMSS.png`
|
||||
- after: `issues/screenshots/issueN-after-YYYYMMDD-HHMMSS.png`
|
||||
3. Record verification commands and outcomes in the issue:
|
||||
- `cargo check --workspace`
|
||||
- `cargo test --workspace`
|
||||
- `just qa-validate`
|
||||
|
||||
Legacy issues may reference `issues/screenshots/issueN.png` as before evidence.
|
||||
66
docs/SPRITE_PACK_SCHEMA.md
Normal file
66
docs/SPRITE_PACK_SCHEMA.md
Normal file
@@ -0,0 +1,66 @@
|
||||
# Sprite Pack Manifest Schema (MVP)
|
||||
|
||||
Path: `<pack_dir>/manifest.json`
|
||||
|
||||
## Required Fields
|
||||
|
||||
- `id` (string): unique sprite pack ID.
|
||||
- `version` (string): schema/pack version label.
|
||||
- `image` (string): atlas image filename, e.g. `atlas.png`.
|
||||
- `frame_width` (u32): frame width in pixels.
|
||||
- `frame_height` (u32): frame height in pixels.
|
||||
- `animations` (array): list of animation definitions.
|
||||
- `anchor` (object): sprite anchor/pivot.
|
||||
|
||||
## Animation Definition
|
||||
|
||||
- `name` (string)
|
||||
- `fps` (u16)
|
||||
- `frames` (array of u32 frame indices)
|
||||
- `one_shot` (optional bool)
|
||||
|
||||
## Anchor Object
|
||||
|
||||
- `x` (f32)
|
||||
- `y` (f32)
|
||||
|
||||
## Example
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "default",
|
||||
"version": "1",
|
||||
"image": "atlas.png",
|
||||
"frame_width": 64,
|
||||
"frame_height": 64,
|
||||
"animations": [
|
||||
{ "name": "idle", "fps": 8, "frames": [0, 1, 2, 3] },
|
||||
{ "name": "success", "fps": 12, "frames": [20, 21, 22], "one_shot": true }
|
||||
],
|
||||
"anchor": { "x": 0.5, "y": 1.0 }
|
||||
}
|
||||
```
|
||||
|
||||
## Runtime Fallback Behavior
|
||||
|
||||
- The selected pack is attempted first.
|
||||
- If selected pack is missing/invalid, frontend falls back to `default`.
|
||||
- If `default` is missing/invalid, loading fails with error.
|
||||
|
||||
## Alpha Handling
|
||||
|
||||
- If the source image already has an alpha channel, runtime uses it directly.
|
||||
- If the source image is RGB-only, runtime can apply chroma-key conversion:
|
||||
- default key color: `#FF00FF`
|
||||
- matching pixels become transparent.
|
||||
- Manifest optional fields:
|
||||
- `chroma_key_color` (string `#RRGGBB`)
|
||||
- `chroma_key_enabled` (bool)
|
||||
|
||||
## Grid Derivation Rule
|
||||
|
||||
- Runtime derives atlas grid from image dimensions:
|
||||
- `columns = image_width / frame_width`
|
||||
- `rows = image_height / frame_height`
|
||||
- Image dimensions must be divisible by frame dimensions.
|
||||
- Every animation frame index must be `< columns * rows`.
|
||||
Reference in New Issue
Block a user