Skip to content

Add screen-size command - #2

Open
jfperusse wants to merge 6 commits into
mainfrom
screen-size
Open

jfperusse wants to merge 6 commits into
mainfrom
screen-size

Conversation

@jfperusse

@jfperusse jfperusse commented Sep 22, 2026

Copy link
Copy Markdown

Issue

Agents driving Codea through codea could screenshot a project only at whatever
size the viewer happened to be. Checking a layout at another size or orientation
meant changing the viewer by hand on the device, which is exactly what the CLI
exists to avoid.

Fix

Adds codea screen-size [preset] over the setScreenSize/getScreenSize MCP
tools, accepting the five viewer preset ids verbatim:

codea screen-size                     # Screen size: tv — TV (16:9), 1920 × 1080
codea screen-size iphone-landscape    # set it

Shaped after idle-timer/paused rather than runtime: the presets apply to
the viewer, not to a project, so there is no project argument. Preset ids are
validated client-side, so a typo fails with the valid list and no round trip,
and the id → display name mapping lives in the CLI so the reported id stays the
contract.

Reading the size is a live query, not a stored setting. getScreenSize
returns {"preset": id} plus width and height once the viewer has laid
out, and those are its laid-out bounds rather than the preset's nominal size.
Under match-display it should therefore follow the window, though that is an
expectation rather than something observed — see Tests. Dimensions are omitted
rather than null before first layout, so the command prints the preset alone in
that case.

No --json flag: this CLI has none anywhere, and adding one here would have
made screen-size the odd command out.

Depends on

Do not merge before the app half ships, or a released codea advertises a
command no shipped Codea answers. The MCP tools exist only in
codea PR #440,
so until that merges and reaches a build, this command fails with an
unknown-tool MCP error for everyone.

Tests

cargo fmt clean, no new clippy warnings, 13 unit tests pass — the parser is
covered for dimensions present, omitted, half-present and fractional, and for a
bare id or a missing preset now being an error.

Verified on an iPad Pro (iPad14,5, iOS 26.7) against a local build of #440,
re-run after the read contract changed to JSON. All five presets, read back
through the parser:

preset reported
match-display 1590 × 1192
iphone-portrait 393 × 852
iphone-landscape 852 × 393
tv 1920 × 1080
square 1112 × 1112

These agree to the pixel with WIDTH/HEIGHT read inside Lua in an earlier
run — two independent sources. That the size comes from laid-out bounds rather
than a preset table is also proven directly: ResizableRenderer.Preset.width
is 0 for tv, square and matchWindow, yet tv reports 1920 × 1080.

Both reachable failures print their message and exit 1: no project running, and
an unknown preset, the latter rejected client-side with no round trip.

Two branches are deliberately untested because neither can be reached here.
The non-Pro path is unreachable by design — the Air Code server only starts for
Pro subscribers, so a non-Pro user cannot reach any MCP tool at all. The
absent-dimensions path has never been seen to fire: polling after codea run
returns "no project is running" until the size is already present. Both are
kept anyway, since reporting a wrong or zero size would be worse than handling
a case that may occur on a slower device. Likewise, match-display following
the window is expected from the renderer tracking view bounds but was not
observed — the two levers available remotely, viewer.mode = FULLSCREEN and
sliding the output pane, both overlay the viewer rather than inset it, and a
real resize needs Stage Manager or split view.

Also folds in a changelog and cargo release configuration, and removes the
[package.metadata.release] section from Cargo.toml so release.toml is the
only home for that config: cargo-release 1.1.6 gives the Cargo.toml section
precedence, so editing the duplicated keys in release.toml silently did
nothing. Verified by dry run that the tag, the changelog replacements,
publish = false and allow-branch all behave from release.toml alone.

🤖 Generated with Claude Code

https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ

jfperusse and others added 2 commits September 21, 2026 22:32
Adds `codea screen-size [preset]` over the setScreenSize/getScreenSize MCP
tools, so a project can be screenshotted at different sizes and orientations
without editing it.

Modelled on `idle-timer`/`paused` rather than `runtime`: the presets apply to
the viewer, not to a project, so there is no project argument. The five preset
ids are validated client-side, which rejects a typo without a round trip, and
the display name is mapped locally since the device returns the bare id.

The device half is not implemented yet, so this errors against current Codea
builds until it ships.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ
The Air Code server only runs for Pro subscribers, so every `codea` command
already requires Pro and a non-Pro user cannot reach `screen-size` to be told
about it. Singling this command out as Pro-gated, and promising an error
instead of a paywall, described a path that cannot happen.

Replaces it with the two failures that are reachable — no project running, and
a non-viewer host such as the standalone Runner — and notes that WIDTH/HEIGHT
change with the preset, confirmed on device across all five presets.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ
@jfperusse
jfperusse requested a review from simsaens September 22, 2026 03:40
jfperusse and others added 4 commits September 21, 2026 23:51
Records the history back to 0.1.0 from the tags, and configures cargo-release
to move the Unreleased section and its compare links to the new version on
bump. Distribution is by cargo-dist from the pushed tag, so publishing to
crates.io stays off.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TqPb55Kii6dZHot2PPGMFq
release.toml duplicated publish, allow-branch and pre-release-commit-message
from [package.metadata.release] in Cargo.toml, and cargo-release 1.1.6 gives
the Cargo.toml section precedence: with tag-name set in both, a dry run tags
from Cargo.toml. The values matched, so nothing behaved differently, but
editing release.toml — the obvious place to look — would have silently done
nothing for those three keys.

Removes the Cargo.toml section so release.toml is the only source, and notes
in the file why that section must stay gone. Verified by dry run: the tag is
v0.1.7 from release.toml, publish = false is honoured (no packaging or upload
step, unlike publish = true), and allow-branch still refuses a topic branch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ
getScreenSize now returns {"preset": id} plus width and height once the viewer
has laid out, rather than the bare preset id, so a future custom size with an
arbitrary width and height needs no second change to the wire format. Changing
it now costs nothing because neither half has shipped.

The dimensions are the viewer's live bounds, not the preset's nominal size, so
under match-display they follow the window and reading the size is a query
rather than a stored setting; the docs say so. They are omitted rather than
null before first layout, so a lone width or height, or neither, prints the
preset alone. setScreenSize is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ
The reported size demonstrably comes from laid-out bounds rather than a table
of preset sizes: ResizableRenderer.Preset.width is 0 for tv, square and
matchWindow, yet tv reports 1920 x 1080, and the five presets cross-check to
the pixel against WIDTH/HEIGHT read inside Lua. That part stands.

Following the window under match-display does not: it is a sound inference
from the renderer tracking view bounds, but resizing the window needs Stage
Manager or split view and hands on the device, so it has not been observed.
The absent-dimensions branch has never fired either — polling after a run
returns "no project running" until the size is already there. Both now read as
expected rather than tested, and the changelog states only what shipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014kJYH24sqV9xNvhVb86bMZ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant