Concepts
Looks and versions
What a Look composes, how layout templates sit on top of it, what a saved version means, and when Hold stops a project following the latest styling.
A Look is the styling of a strip, saved per project and versioned. It is reusable precisely because it holds no words: the copy that ships is per-render input from your own repository, and no ShotOps tool will ever hand it to you as if it were part of the design.
#Style and Look
Three arguments carry styling, and choosing between them is most of what there is to know.
| Argument | Reach | Use it for |
|---|---|---|
style.layout | The whole panel composition, in one word | Start here. It settles the reserved headline region, the device size and the device position together. |
style | One shared device style for every phone, plus the background and the captions | The ordinary case: one device treatment, one background, per-panel words. |
look | Per-panel and per-device styling through shots[] | The only way two phones in the same panel get different colours. |
shots[] is flattened in panel order, one entry per screenshot, and devices sharing a panel repeat
the same panelId. A look is validated, not merely accepted: an unknown key is rejected rather than
silently rendering something wrong.
They compose, and every real App Store strip needs them to. Pass look for the devices and the
background and style.captions for the words, in one call. A style.shotLook or style.background
alongside a look is redundant — the look wins, and the response says so in a note.
Numeric fields are range-checked. A value outside its range is refused with the range and the fix, and never quietly clamped to the nearest legal number.
Two things that look like styling and are not: caption text, which is per-render input the caller
owns, and panelPresetId, which picks the App Store panel size (r69, r65, r55) and belongs
to the output rather than the design.
#Layout templates
standard, bleed and top-bleed are the three compositions. Pick from the longest headline in
the set — past roughly 36 characters, bleed is the one that fits.
When nobody has told you how the strip should look, the choice is not taste. Every template declares
a character — the kind of request it is the right answer to — and describe_look returns it
beside the blurb:
standardissafe. It crops nothing, so it cannot lose screen content the user cares about. Take it when nothing was said about style, or when the request is only about wording.bleedisconventional. What the shipped App Store market looks like, and what a neutral quality word means here — professional, polished, store-ready.top-bleedisexpressive. An opinionated composition, for someone who asked to stand out.
A request that names a composition outright — "run the device off the bottom edge" — beats the character. Where several templates share one, the longest-headline rule above breaks the tie. The web app's own AI chooses on this same axis from this same catalog, so a project styled by conversation here and a project styled in Studio answer the same words the same way.
A template is applied as a pure macro. It expands into ordinary values first, so anything you also
pass explicitly — shotLook.phoneHeight, hOffset, vOffset, a caption's sizePt or maxWidth —
wins over what the template produced. Nudging a template is safe; setting placement by hand with no
template is the escape hatch off the road rather than the road.
No template id is ever stored. A project records the values, not the name. The layout block on
every render and on read_project is derived from those values, which is what makes it impossible for
it to go stale: it can say the strip is on bleed, or that it is on bleed with one field that
differs and by how much, or that it is close to nothing at all. It answers per panel too, because a
strip may honestly mix compositions.
#Saving a version
save_look persists the composed styling on a project and appends a new version.
Every save appends, and versions are retained on every plan. Save this version in the web app does
the same thing — which is what lets a designer tune a strip by eye and an agent reproduce exactly that
design with no manual step in between.
read_look returns the current saved look along with its history.
render_strip re-applies a saved look through useSavedLook, and version: N
renders one specific version.
Browsing history is a Pro capability. On Free, read_look still returns the current saved look but
omits versions and heldVersion and explains why in a structured history denial. An explicit
historical-version request is answered exactly or refused; ShotOps never substitutes the latest Look.
#Hold and Follow latest
A project is in one of two states, and the difference matters the moment two people work on it.
- Follow latest — the default. Renders use whatever look was saved most recently, so a designer's 4pm experiment is what an agent renders at 5pm.
- Hold —
hold_lookpins one version as the project default. Renders use the pinned version no matter what gets saved afterwards, which is what lets a designer keep experimenting while a pipeline keeps shipping the approved design.release_lookclears the pin and the project follows latest again.
A Hold set while on Pro is retained through a downgrade and becomes active again on upgrading — it is not lost, only unreadable in the meantime.
Pin before a release, release the pin after. Run it in CI treats this as one of the inputs a repeatable job has to fix.
#Which clip setting wins
Panels have no hard divider between them. A phone pushed past its panel edge with a large hOffset
overflows into the neighbouring panel, and the strip reads as one continuous swipe-through image. That
is a deliberate design, so the question of what clips is a real one.
An explicit top-level clip: "strip" or clip: "panel" wins over every shot: "strip" forces
continuous overflow, and "panel" clips every device to its own panel. Omit clip and each shot's own
clipToFrame is honoured; when that is missing or false, overflow is allowed.
Clipping a device clips its complete composite — body, screen, shadow and reflection — not just the phone.
#Finding every field
describe_look is the exhaustive catalog, and it stays that way. It returns the
palette presets, the three layout templates, the two-question intake script, every styling field with
its range and its default, and the caption guardrails — at runtime, from the server you are actually
connected to, which is the only version of that list that can never be out of date.
Call it when nobody has said how the strip should look. Skip it when they already told you, when the project has a saved look, or when you are iterating on a strip you already rendered.
The per-tool argument and result shapes live in the tool reference. This page deliberately does not reproduce either.