baguette v0.1.92
Added
-
Motion —
baguette motion start|set|stop, and a walk that drives it.
Makes a simulator's apps readCMMotionActivity(walking, running,
cycling, automotive),CMPedometercounters, andCMMotionManager
samples. All three report unavailable in a stock simulator —
CoreMotion and locationd both gate on a hardware-capability bit derived
from the device's HW type, and a simulated device is an "Unsupported HW
type", so locationd refuses a motion-activity subscription outright. The
runtime even ships a simulation hook
(simulateMotionState:withState:withHint:) that locationd accepts and
that changes nothing, because the availability gate sits upstream of it.
So this works the way the virtual camera does:
by injecting a dylib into the app under test. Only apps launched after
motion startsee anything — dyld inserts at exec time.
Turn it on in the browser's Location card and the walk joystick and
route speeds it already posts classify the activity, so the preset you
picked (Walk 1.4 · Cycle 6 · Drive 13.4) is what your app observes;
pinning a point parks it as stationary, which is exactly when locationd
dropscourseto-1. Motion stays opt-in — moving the device never
arms a simulator-wideDYLD_INSERT_LIBRARIESon your behalf.
The ABI notes are the part worth keeping: those{fff}structs pass by
value (a pointer reads zeros and displaces the timestamp),
CMGyroData's initialiser takes degrees while its property returns
radians,CMDeviceMotion's quaternion is storedw,x,y,zagainst a
publicx,y,z,w, itsgravityis derived from attitude rather than set,
it ignores its owntimestamp:argument, andCMMotionActivitybuilt by
poking ivars reads back fine and then crashes in-description. A
load-time self-check verifies each surface and skips hooking any that
fails, so a future iOS leaves apps seeing the platform's honest
"unavailable" rather than fabricated garbage. Floor counting and the
magnetometer are refused on purpose. See
docs/features/motion.md. -
One output size for every capture —
--size appstore-6.9, and the
same words in the UI. Screenshots and recordings, 2D and 3D, browser
and CLI, now share one vocabulary: the App Store submission sizes
(appstore-6.9,appstore-6.5,appstore-ipad-13), the common ratios
(square,16:9,9:16,4:3,4:5), plus1920x1080and any bare
W:H. Pick "App Store 6.9″" from the toolbar chip once and reproduce
exactly those pixels in CI with--size appstore-6.9.A ratio grows rather than crops:
squareon a 1290 × 2796 phone
gives a 2796 × 2796 canvas with the whole phone centred, not a
1290 × 1290 cut through the middle of the screen. Cropping the device
out of a marketing shot is the one thing nobody asking for a square
wanted.--fit(contain/cover/stretch) and--background
say what fills the rest. Unknown sizes are rejected — baguette never
substitutes a nearby one. -
baguette record— video straight from the CLI. A booted simulator,
an--output, and either--durationorCtrl-C; the file is flushed
and playable either way. Takes--size/--fit/--fps/
--bitrate, writes.mp4or.mov(the extension picks the
container).docs/features/recording.mdhas argued for a while that server-side
recording was tried and rejected, and that argument still stands for
the live stream — a recorder attaching mid-stream never sees the
SPS/PPS the encoder emitted on its first IDR, and an N+1th
VideoToolbox session stutters every farm tile. Neither applies to a
standalone CLI run: it owns the encode from frame one and has no
competing viewer. So the design that was wrong as a passenger is the
right one on its own, and it is wired into nothing — no route, no WS
verb. -
PNG screenshots, and a bezelled one.
baguette screenshot --format png(inferred from a.png --output, so-o shot.pngcan
never quietly hold JPEG bytes), plusGET …/screenshot.pngand
GET …/screenshot-bezel.png— the frame composited inside its
DeviceKit chrome, which previously meant opening a browser and
cropping. All three routes take?size=&fit=&background=;
screenshot.jpgwith no new parameters returns byte-identical output
to before. -
A size chip on every capture surface, and a Record button where
there wasn't one. The focus-mode view had only ever had Screenshot; it
now records too, in both 2D and 3D — dropping the bezel in 3D, since
the rendered frame already contains a device. The legacy stream
sidebar and the device-farm focus pane get the same chip, each
remembering its own selection, and it drives Capture and Record alike:
a screenshot and a clip taken a second apart come out at the same
dimensions. Saved files are named for what they are —
…-appstore-6.9-1290x2796.png. -
The browser's 3D export is now lossless. It used to save
toDataURL()of the decoded video canvas — a ~960 px H.264 or MJPEG
frame. It now asks the server to re-render the same pose at the picked
size, soappstore-6.9really is 1290 × 2796 instead of an upscale of
a video still.render-3d --sizeand the route's"size"field take
preset names as well as literal pixels, and the live 3D stream accepts
size=. -
Deep links —
baguette openurl <url>andbaguette schemes. Opens a link
on a booted simulator, and lists the URL schemes its apps registered (ranked:
an app's own scheme before its reverse-DNS andexp+aliases). Unlike
simctl openurl/idb open/ Maestro,openurlwarns thathttps://lands
in Safari rather than your app — the simulator doesn't resolve associated
domains, so dispatch succeeds and your app never comes up. Schemes need two
reads:
simctl listappsgives the roster and each app'sPathbut not
CFBundleURLTypes, so those come from<Path>/Info.plist. Over HTTP as
POST /simulators/:udid/openurlandGET /simulators/:udid/schemes.json,
reachable by a plugin holding the newopen-urlcapability — which is apart
fromapps, since this only launches software that is already installed.
Seedocs/features/deep-links.md. -
A deep-link panel, as an installable official plugin. Not in the toolbar —
baguette ships the toolbar, this is a thing you choose:baguette bakery add tddworks/baguette baguette plugin install deeplink
This makes baguette's own repo a bakery. Only
a11ystill ships inside the
binary; everything else maintained alongside baguette is official and
installed on purpose. -
Plugin panels can be operated, not just read. A panel was a report: the
host ran a command and drew the rows. It can now carry a text field
(body.prompt) and tickable rows (body.control— switches, checkboxes,
radios, grouped so one panel can ask several questions). Both invoke the
panel's ownsourcecommand withargs, which is the pathrowAction: "run"
already took, so this adds widgets rather than an execution model — still no
plugin code in the page.The field completes as you type (
Tab/→to accept), remembers the last 25
submissions on↑/↓, filters the rows already on screen, and takes a row's
text on click viarowAction: "fill"— so a list of suggestions behaves like a
URL bar instead of a launcher. History is browser-side: a plugin sees what you
submit, never what you typed before.Ticks are local and batched — no subprocess per tick, and rows the device
hasn't confirmed are drawn pending until the submit returns. Every answer
rebuilds them from what the plugin reported, so a refused setting snaps back.
a11y's display panel uses this (1.2.0) and no longer writes"● Light"/
"○ Dark"into row titles. All of it is additive —apiVersionstays 1.
Changed
-
The plugins rail follows the focus-mode design system. The rail, its
flyout, the panel and the bakery modal were styled by a stylesheet
sim-plugins.jsinjected intodocument.head— and a stylesheet written
beside its module can't see the--nv-*theme tokens, which are defined on
#simNativeView. Every colour in it therefore carried a guessed fallback,
and the guesses were light-theme values: light-slate shadows with no dark
variant, a whitevar(--panel)text field inside a dark glass modal, and an
accent pulled fromsim.html's light-only--accentrather than
--nv-accent. It also invented its own geometry — 34×34 rail buttons at
radius 9 against the toolbar's 30×28 at radius 8, a600 10px/0.06emaccent
heading against the app's700 9.5px/0.10emfaint one, a fourth primary
button, and four 2px accent seams no other surface has.All of it now lives in
sim-native.htmlunder#simNativeView, beside the
panels it sits next to, with no fallbacks — the same arrangement the logs,
status-bar, location and a11y panels already use. The companion-screens rail
moved with it and the two now share every rule they had duplicated. The rails
being separate is the trust signal (seedocs/features/plugins.md); the
plugin rail keeps its accent emblem to say which is which, and drops the
second colour system that was layered on top.
Added
--nv-danger,--nv-warnand--nv-scrimtheme tokens, in both light and
dark. A panel reporting an error previously picked its own red, and the one
it picked was a light-theme#b91c1con a near-black page. Plugin row
severity is now adata-severityattribute the stylesheet colours, rather
than an inline hex the module carries.
What's Changed
- fix(web): style the plugins rail from the focus-mode design system by @hanrw in #48
- feat: add deep links and scheme completion for plugins by @crockalet in #50
- feat: size-aware stills in CaptureGallery by @hanrw in #51
- feat: size-aware recording and a bezel-less 3D mode by @hanrw in #52
- feat: lossless sized 3D capture in Sim3DPanel by @hanrw in #53
- feat: capture size picker on the legacy stream sidebar (Capture + Record) by @hanrw in #54
- feat: render-3d and the live 3D stream accept capture-size presets by @hanrw in #55
- feat: capture output size on the device farm focus pane by @hanrw in #56
- feat: --size / --fit / --background / --format for baguette screenshot by @hanrw in #57
- docs: document the shared capture-size vocabulary by @hanrw in #58
- Sized screenshots and recording in the native view by @hanrw in #59
- feat: sized screenshots, PNG output, and a server-side bezel composite by @hanrw in #60
- feat(motion): drive CMMotionActivity, CMPedometer and CMMotionManager from a walk by @crockalet in #61
- fix: composite bezel captures at framebuffer resolution, and grow ratios on render-3d by @hanrw in #62
- feat: baguette record — H.264 video from the CLI, at the shared capture sizes by @hanrw in #63
- feat: supersample the 3D stream when a capture size is picked by @hanrw in #64
- feat: fold the focus toolbar into context clusters by @hanrw in #65
Full Changelog: v0.1.91...v0.1.92