Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ measurement section below for the answer.
seeded sim in `pocket-character-core`.
- **Spring bones** (hair / hood / bust) from the model's VRM data, solved by
`pocket-vrm`'s verlet solver each tick.
- **Widget window**: 450×600 (airi's stage geometry), transparent,
- **Widget window**: 450×600 by default (airi's stage geometry; `--size WxH`
for any other footprint — the framing scales with the window), transparent,
undecorated, always-on-top, drag anywhere to move, frame-paced at 60 fps
(the loop sleeps; `--max-fps` to taste).
- **Guest policy bundle** (`app/main.ts` → QuickJS): the `character` surface
Expand Down
17 changes: 14 additions & 3 deletions crates/pocket-character/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! pocket-character: the airi-parity character widget on the Pocket runtime.
//!
//! Windowed mode is the product: a transparent, undecorated, always-on-top
//! 450×600 window (airi's stage geometry) rendering the VRM character.
//! window (450×600 by default — airi's stage geometry; `--size WxH` to
//! taste) rendering the VRM character.
//! `--headless-shot` drives the same [`Game`] object without a window and
//! saves an RGBA screenshot — CI-friendly parity checks.

Expand Down Expand Up @@ -34,6 +35,16 @@ fn main() -> Result<()> {
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.."));

// --size WxH (default 450x600, airi's stage geometry). The camera fov is
// vertical, so any size shows the same framing scaled; changing the aspect
// ratio crops horizontally.
let size: (u32, u32) = flag("--size")
.and_then(|s| {
let (w, h) = s.split_once('x')?;
Some((w.parse().ok()?, h.parse().ok()?))
})
.unwrap_or(SIZE);

let cfg = WidgetConfig {
model_path: flag("--model")
.map(PathBuf::from)
Expand All @@ -44,7 +55,7 @@ fn main() -> Result<()> {
bundle_path: flag("--bundle")
.map(PathBuf::from)
.unwrap_or_else(|| root.join("dist/character.js")),
size: SIZE,
size,
frames: flag("--frames").and_then(|s| s.parse().ok()),
};

Expand All @@ -63,7 +74,7 @@ fn main() -> Result<()> {
pocket3d::app::run(
AppConfig {
title: "pocket-character".into(),
size: SIZE,
size,
tick_hz: TICK_HZ,
capture_mouse: false,
transparent: true,
Expand Down