Skip to content

Commit c04828c

Browse files
AndrewAltimitAI Agent BotclaudeAI Review Agent
authored
feat(psp): runtime theme switcher + autorun script runner (#154)
* feat(psp): runtime theme switcher + autorun script runner Adds a Settings kiosk app to the PSP backend so themes can be swapped on the fly (mirrors the SDL3 Settings app, minus the resolution preset list since PSP is fixed at 480x272). Themes now repaint icons and the static gradient wallpaper too — not just the bars and bottom shaders — so each of the seven PSP presets is visibly distinct. To make the change testable end-to-end without flaky xdotool input simulation, this also adds a boot-time AUTORUN.txt script runner (feature `autorun-script`, off by default) that dispatches one command per frame from the main loop. Verbs: launch / press / cursor / skin / wait / screenshot / log / exit. Reuses cmd_server's INJECT_QUEUE and apply_skin_preset so TCP and AUTORUN drive the same code paths. The `screenshot` verb writes a sentinel file and blocks until the host harness deletes it; the host captures the PPSSPP window via scrot (needed because PPSSPP's GU emulation never syncs rendered pixels back to the PSP RAM mirror, so VRAM reads return only stale boot content). Settings UI: - Settings KioskApp variant + SettingsState (cursor + scroll) - views_sdi/settings.rs reuses list_view helpers; [*] marker on the active preset; "X = Apply, O = Back" hint - input handler: Up/Down navigate, X applies, O closes - shared skins::apply_skin_preset() consolidates the rebuild + persist path (terminal `skin NAME`, cmd_server, Settings UI) - views_sdi::hide_all gains a `settings_` prefix so SDI rows don't bleed through after exit Theme variation: - chrome::draw_dashboard takes &ActiveTheme; icon body / outline / fold / shadow / label / label_shadow now come from at.icon.* - per-preset apply_icon_palette() in skins.rs (RetroCGA black+cyan, HighContrast black+yellow, Solarized teal, Altimit navy+mint, etc.) - procedural::generate_gradient_with(w, h, &stops) takes a 5-stop palette; PspSkinPreset::gradient_stops() returns each preset's colors; main loop regenerates wallpaper texture on skin change so PSIX, Classic, and HighContrast each get a unique background Autorun runner: - crates/oasis-backend-psp/src/autorun.rs (parser + dispatcher) - cmd_server::request_skin_change made pub for cross-crate access - desktop::dashboard_icon_center reverses hit_test for `launch <app>` - main.rs: load AutorunRunner at boot, tick once per frame before poll_events_inner so injected events land same frame - docs/psp-autorun.md documents grammar + sentinel mechanics Test scripts: - scripts/test-settings-ppsspp.sh: build + drop AUTORUN.txt + watch for sentinels + scrot the PPSSPP window. Verifies the full Settings flow end-to-end. - scripts/test-all-themes-ppsspp.sh: cycles every preset via the `skin` verb, captures dashboard for each. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: address AI review feedback (iteration 1) Automated fix by Claude in response to AI review feedback. Iteration: 1/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 2) Automated fix by Claude in response to AI review feedback. Iteration: 2/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 3) Automated fix by Claude in response to AI review feedback. Iteration: 3/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 4) Automated fix by Claude in response to AI review feedback. Iteration: 4/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> * fix: address AI review feedback (iteration 5) Automated fix by Claude in response to AI review feedback. Iteration: 5/5 Co-Authored-By: AI Review Agent <noreply@anthropic.com> --------- Co-authored-by: AI Agent Bot <ai-agent@localhost> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: AI Review Agent <ai-review-agent@localhost>
1 parent 40a6e1b commit c04828c

23 files changed

Lines changed: 1385 additions & 57 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ outputs/
4949
# Screenshot test output (generated, not committed)
5050
screenshots/tests/
5151
screenshots/psp/
52+
screenshots/settings-test/
53+
screenshots/all-themes/
5254

5355
# WASM build output
5456
pkg/

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ Key documentation files for agents and contributors. Read these for deeper conte
231231
- [`docs/browser-backlog.md`](docs/browser-backlog.md) -- Browser engine backlog and roadmap
232232

233233
### Operations
234+
- [`docs/psp-autorun.md`](docs/psp-autorun.md) -- Boot-time script runner for deterministic PSP/PPSSPP integration tests
234235
- [`docs/troubleshooting.md`](docs/troubleshooting.md) -- Troubleshooting common issues
235236
- [`docs/security.md`](docs/security.md) -- Security policy and advisories
236237
- [`AGENTS.md`](AGENTS.md) -- Multi-agent system configuration and CI workflow

crates/oasis-backend-psp/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ kernel-me = ["psp/kernel"]
4545
# Used by PPSSPP-driven offline browser perf bisection. Disabled by
4646
# default to keep the EBOOT lean.
4747
auto-browse-wiki = []
48+
# Boot-time script runner. Reads `ms0:/PSP/GAME/OASISOS/AUTORUN.txt`
49+
# and dispatches one command per frame (launch / press / cursor /
50+
# skin / wait / screenshot / log / exit). Used for deterministic
51+
# integration tests in PPSSPP and on real hardware. Disabled by
52+
# default — production EBOOTs don't need the parser.
53+
autorun-script = []
4854

4955
[dependencies]
5056
psp = { path = "/home/mikunpc/Documents/repos/rust-psp/psp", features = ["std"] }

crates/oasis-backend-psp/src/app_states.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,28 @@ impl RadioState {
260260
}
261261
}
262262

263+
// ---------------------------------------------------------------------------
264+
// Settings
265+
// ---------------------------------------------------------------------------
266+
267+
/// Settings app: theme picker. Resolution is fixed at 480x272 on PSP, so
268+
/// only theme switching is exposed.
269+
pub(crate) struct SettingsState {
270+
/// Index into `PspSkinPreset::ALL`.
271+
pub(crate) selected: usize,
272+
/// Top row offset for scrolling.
273+
pub(crate) scroll: usize,
274+
}
275+
276+
impl SettingsState {
277+
pub(crate) fn new() -> Self {
278+
Self {
279+
selected: 0,
280+
scroll: 0,
281+
}
282+
}
283+
}
284+
263285
// ---------------------------------------------------------------------------
264286
// TV Guide
265287
// ---------------------------------------------------------------------------

0 commit comments

Comments
 (0)