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.

View as Markdown

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.

ArgumentReachUse it for
style.layoutThe whole panel composition, in one wordStart here. It settles the reserved headline region, the device size and the device position together.
styleOne shared device style for every phone, plus the background and the captionsThe ordinary case: one device treatment, one background, per-panel words.
lookPer-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:

  • standard is safe. 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.
  • bleed is conventional. What the shipped App Store market looks like, and what a neutral quality word means here — professional, polished, store-ready.
  • top-bleed is expressive. 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.
  • Holdhold_look pins 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_look clears 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.