6.1 KiB
Phokus UI Lab
Phokus UI Lab is a browser-only development mode for visual work on the real
Phokus frontend. It runs the same App.tsx, Zustand store, components, and CSS
as the Tauri app, but installs Tauri JavaScript mocks before the app imports.
This gives UI agents and contributors a stable browser target without launching the Rust backend or a Tauri window.
Run It
pnpm dev:ui
Then open:
http://127.0.0.1:1422
The script runs Vite in the custom ui mode:
vite --mode ui --host 127.0.0.1 --port 1422 --strictPort
The normal app development commands are unchanged:
pnpm dev:app # Tauri app + Rust backend
pnpm dev:vite # frontend dev server for Tauri dev
Scenarios
UI Lab reads ?scenario= from the URL. If no scenario is provided, it uses
rich.
| URL | Purpose |
|---|---|
/?scenario=rich |
Default realistic library with folders, albums, ratings, favorites, tags, images, and videos |
/?scenario=empty |
Empty library with no folders or media (onboarding already completed) |
/?scenario=new-user |
True first run: onboarding tour open, empty library, no tagger model downloaded |
/?scenario=just-updated |
Rich library that has just been updated — the "What's new" toast fires on launch |
/?scenario=busy |
Background workers with pending thumbnail, metadata, embedding, caption, and tagging jobs |
/?scenario=duplicates |
Duplicate Finder opened with duplicate groups already available |
/?scenario=album |
Gallery opened directly into an album |
/?scenario=errors |
Broken thumbnails, folder scan errors, failed embeddings, failed tagging, and metadata issues |
/?scenario=huge |
Large mock library for virtualization and layout checks |
Examples:
http://127.0.0.1:1422/?scenario=duplicates
http://127.0.0.1:1422/?scenario=errors
http://127.0.0.1:1422/?scenario=huge
Changelog Previews
The What's New modal adapts its layout to release size (compact single column
for small releases, a two-pane section rail for large ones). UI Lab reads
?changelog= to override which entry the modal shows:
| URL | Purpose |
|---|---|
/?changelog=unreleased |
The in-progress [Unreleased] notes — large release, rail layout |
/?changelog=small |
Synthetic hotfix-sized entry — compact single-column layout |
/?changelog=0.1.1 |
Any specific released version |
Open the modal via the demo panel: Ctrl+Shift+D → Open "What's new" modal.
Combine with the scenario above to walk the whole post-update greeting for the
next release: /?scenario=just-updated&changelog=unreleased.
How It Works
src/main.tsx bootstraps the app asynchronously. In ui mode it imports
src/dev/setupMockTauri.ts first, then imports the real App.
That order matters because static imports are hoisted. The Tauri mocks must be
installed before App, the store, the title bar, or visual components import
Tauri APIs.
The mock setup installs:
mockWindows("main")for window APIs used by the title barmockConvertFileSrc("windows")as a baseline Tauri file URL mockmockIPC(..., { shouldMockEvents: true })forinvoke,listen, andemit
The in-memory backend lives in:
src/dev/mockBackend.ts
src/dev/mockFixtures.ts
src/dev/mockScenarios.ts
src/dev/applyMockScenario.ts
Happy-path fixture media is generated from existing onboarding images and website screenshots into:
public/dev-media/fixture-*.webp
The pack is deliberately small and deterministic, but varied enough for browser
screenshots: square, portrait, landscape, monochrome, tinted, framed, and
interface-like crops. Synthetic or deliberately broken fixture paths can still
use the mock:// scheme described below.
Mock Media
Visual components should use mediaSrc(...) instead of calling
convertFileSrc(...) directly:
import { mediaSrc } from "../lib/mediaSrc";
const src = mediaSrc(image.thumbnail_path);
In normal Tauri modes, mediaSrc delegates to convertFileSrc. In UI Lab,
root-relative asset URLs such as /dev-media/fixture-01.webp are returned
as-is. Paths beginning with mock:// are also served from public/dev-media:
mock://thumb-1.svg -> /dev-media/thumb-1.svg
Use mediaSrc when adding components that render thumbnails, album covers,
preview images, or video posters.
Adding A Mock Command
If the browser console logs an unmocked command, add it to
src/dev/mockBackend.ts.
Prefer returning realistic data for commands that affect visible UI. For actions that would touch the machine, return a safe no-op:
case "open_app_data_folder":
return null;
When adding fixture data, keep it shaped like the real store/Rust contracts.
Most frontend-facing types are exported from src/store.ts, so the mocks can
stay type-checked against the real UI.
Adding A Scenario
- Add the scenario name to
MockScenarioandSCENARIOSinsrc/dev/mockScenarios.ts. - Adjust fixture creation in
src/dev/mockFixtures.ts. - If the scenario should open a specific view, add that behavior in
src/dev/applyMockScenario.ts. - Visit
http://127.0.0.1:1422/?scenario=your-scenarioand check for console errors.
What UI Lab Is For
UI Lab is intended for:
- visual iteration on the real app shell
- layout and responsive checks
- state-heavy views like Explore, Timeline, Duplicates, albums, and Settings
- AI-agent screenshot/browser inspection
- safe UI work without filesystem or Rust-side effects
It is not a replacement for Tauri app testing. Validate native behavior with
pnpm dev:app when touching:
- file or folder pickers
- filesystem permissions
- real thumbnail/video loading
- window drag, minimize, maximize, or close behavior
- Rust backend performance
- updater installation
- WebView2-specific behavior
Verification
Useful checks after changing UI Lab:
pnpm exec tsc --noEmit
pnpm build:vite
pnpm dev:ui
Then smoke-test at least:
http://127.0.0.1:1422/?scenario=rich
http://127.0.0.1:1422/?scenario=empty
http://127.0.0.1:1422/?scenario=duplicates
http://127.0.0.1:1422/?scenario=errors
http://127.0.0.1:1422/?scenario=huge