ScreenShotComposer

CLI reference

sscc

Headless authoring and rendering for .screenshot documents. Every operation the macOS app performs — discovering catalogs, creating documents, mutating compositions and layers, validating, and rendering PNGs — exposed as a scriptable, agent-first interface.

Install

sscc ships with the ScreenShotComposer macOS app. The Mac app installs the binary at/usr/local/bin/sscc on first launch (you can disable this in Settings → Advanced).

If you cloned the repo to build from source:

bash
git clone https://github.com/luigiinred/ScreenShotComposer.git
cd ScreenShotComposer
bin/sscc --help

Confirm the API version your scripts target — sscc bumps it on every breaking change to the JSON envelope:

bash
sscc --api-version

Conventions

  • Address by UUID, never by title. Every command that mutates a composition or layer takes --id <uuid>. Capture UUIDs at create-time with --emit-id.
  • Add --json for machine-readable output. Every command returns a stable envelope — { "ok": true, "data": ... } on success, { "ok": false, "error": { "code", "message" } } on failure.
  • Mutations are atomic. Either the bundle is updated cleanly or it is untouched on disk. No partial writes.
  • Frames are X,Y,W,H in plate points, top-left origin. Negative origins are valid (for edge bleeds); use the = form so swift-argument-parser doesn’t mistake a leading - for a flag boundary: --frame=-200,300,800,1200.
  • Text accepts \n only. Pass it literally inside double-quoted bash strings; the CLI converts it at parse time. <br/> renders as the literal characters.
  • Image sizing is frame-only. There is no --scale flag. To grow an image, pass a bigger frame.

catalog

Enumerate live catalogs — templates, bezels, presets, fonts.

sscc catalog templates [--json]Every bundled template — id, label, supported platforms.
sscc catalog bezels [--platform <p>] [--json]Every device bezel — id, platform, inner rect coordinates.
sscc catalog presets [--json]Every ASC export preset — token, platform, pixel dimensions.
sscc catalog fonts [--json]Every installed font available to text layers — PostScript names + families.

These four catalogs are the source of truth for any id your scripts pass elsewhere. Always cross-check before freehand-typing a bezel id, font name, or preset token.

bash
# Pick the iPhone 17 Pro bezel from the live catalog.
sscc catalog bezels --platform iphone --json | jq -r '.data[].id' | head

schema

Emit JSON Schema for the document nodes. Use these to validate generated payloads, build editors, or teach an agent the field grammar.

sscc schema manifest [--json]Top-level info.json shape (schemaVersion, app, presets, sidebar order).
sscc schema composition [--json]One CompositionRecord — title, plateFill, preset, layers[].
sscc schema layer [--kind text|image|background|group] [--json]Layer record for one (or all) kinds.

new

Create a new .screenshot document.

bash
sscc new <path>
  [--template <id>]              # bundled template id (sscc catalog templates)
  [--platforms mac,iphone,ipad]  # default: all three
  [--overwrite]
  [--emit-id]                    # print only the absolute created path
  [--json]

Each requested platform gets a <platform>.json with an empty compositions: [].

info

Summarize what’s in a bundle.

bash
sscc info <path> [--json]

The JSON variant is the right way to assert composition counts in a scaffold script.

bash
sscc info MyApp.screenshot --json | jq '.data.compositions | map_values(length)'
# { "mac": 6, "iphone": 6, "ipad": 6 }

show

Print the full bundle (or one composition or one layer) as JSON.

bash
sscc show <path>
  [--composition <uuid>]   # limit to that composition
  [--layer <uuid>]         # limit to that layer
  [--json]

validate

Validate a bundle against the documented schema.

bash
sscc validate <path> [--strict] [--json]

--strict promotes warnings to errors. Run this after every batch of edits.

Note: validate proves the file is well-formed JSON; it does not prove the bundle will render correctly. For that, see the create-screenshot-file skill’s pre-render verify gate.

composition

Manage compositions inside a bundle.

sscc composition add <path> --platform <p> [--title <t>] [--plate-color <#hex>] [--preset <token>] [--emit-id]Append a composition to a platform bucket. Returns the new UUID.
sscc composition set <path> --id <uuid> [--title <t>] [--plate-color <#hex>] [--preset <token>]Mutate composition metadata.
sscc composition remove <path> --id <uuid>Remove a composition.
sscc composition reorder <path> --platform <p> --order <uuid,uuid,...>Reorder compositions inside a platform bucket.

Heads up: composition add auto-creates one empty backgroundlayer per composition. Don’t add another via layer add background — see Known quirks.

layer

Manage layers (text, image, background, group) inside a composition.

sscc layer add text --composition <uuid> --content <str> [--style headline|body|caption] [--font-size N] [--font-weight <token>] [--frame X,Y,W,H] [--color <#hex>] [--align H,V] [--emit-id]Add a text layer. Use \n for line breaks.
sscc layer add image --composition <uuid> --source <png> [--bezel <id>] [--frame X,Y,W,H] [--radius N] [--inset N] [--border W,#hex] [--rotation deg] [--emit-id]Add a (optionally bezeled) image layer.
sscc layer add background --composition <uuid> [--source <png>]Add a plate-filling background layer. (Avoid — use layer set on the auto-created bg.)
sscc layer add group --composition <uuid> [--title <t>]Group nested layers.
sscc layer set --id <uuid> [--content <str>] [--source <png>] [--frame ...] [--color <#hex>] [--font-size N] [--font-weight <t>] [--align H,V] [--style <s>] [--bezel <id>|none] [--rotation deg]Mutate any field on an existing layer.
sscc layer remove --id <uuid>Remove a layer.
sscc layer reorder --composition <uuid> --order <uuid,uuid,...>Re-stack layers inside a composition (sets sortOrder).
sscc layer move --id <uuid> [--composition <uuid>] [--parent-group <uuid>|none]Move a layer between compositions or in/out of a group.

asset

Manage embedded image assets inside a bundle.

sscc asset embed <path> --source <file> [--id <id>]Copy an external image into the bundle's assets/ dir.
sscc asset list <path>Enumerate every asset — id, byte size, references.
sscc asset clear <path> [--dry-run]Remove orphan assets that no layer references.

export

Render PNGs for every composition (or a filtered subset).

bash
sscc export <path> --output <dir>
  [--platform mac|iphone|ipad]   # restrict to one bucket
  [--composition <uuid>]         # repeatable
  [--format png]                 # default & only option today
  [--opaque]                     # alpha-stripped RGB PNG (ASC-friendly)
  [--at-preset <token>]          # render-time preset override
  [--naming preset|uuid|title-slug]
  [--overwrite]
  [--json]

--at-preset is a render-time override; the document on disk keeps its original presets, so the same source can produce every ASC slot:

bash
# Largest required sizes for every platform.
sscc export MyApp.screenshot --output ship/largest \
  --opaque --naming title-slug --json > ship/largest/manifest.json

# Plus an additional iPhone 6.5" slot.
sscc export MyApp.screenshot --output ship/iphone-6.5 \
  --platform iphone --at-preset 1284x2778 --opaque

Heads up: --opaque currently paints a gray transparency-checkerboard into plain (non-bezel) image layers that have alpha. Drop --opaque when your bundle has stickers, badges, or other transparent decorations. See Known quirks.

Exit codes & --json envelope

Every command exits 0 on success and a non-zero code on a known error class:

  • 0— ok
  • 2— usage error (bad / missing flag)
  • 3— not found (path, composition, layer, asset)
  • 4— validation error
  • 5— render error
  • 10— internal error

On success, --json emits:

json
{
  "ok": true,
  "apiVersion": 1,
  "data": { /* command-specific payload */ },
  "warnings": [
    { "code": "FONT_FALLBACK", "message": "..." }
  ]
}

On failure:

json
{
  "ok": false,
  "apiVersion": 1,
  "error": { "code": "NOT_FOUND", "message": "Layer ABC… not found" }
}

Parse the envelope, never the human text. Codes are stable across minor versions.

Known quirks

sscc is shipping in phases. These behaviours bite agents and humans equally — if you write a scaffold script, read this list once first.

layer add background --source is silently dropped

The flag is accepted but never written to the JSON; renders fall back to the plate fill color, so every panel looks like a flat background. Workaround: each composition is born with one empty background layer — read its UUID from <bundle>/<platform>.json and attach the wallpaper with sscc layer set --id <bg> --source bg.png.

composition add auto-creates an empty background layer

Treat that as the canonical bg. Calling layer add background on top produces two stacked bg layers per composition.

Negative --frame origins parse as flag boundaries

Use the = form: --frame=-100,700,2264,3019.

Text layers don't interpret HTML entities

<br/> renders as literal characters. Use \n inside double-quoted bash strings; the CLI converts it at parse time.

No --scale flag for image layers

Resize by editing the frame: sscc layer set --id <id> --frame X,Y,W,H.

--rotation on image layers is a Phase 0 stub

Bake the rotation into the source PNG.

export --opaque paints a checkerboard into transparent regions of plain image layers

Drop --opaque for any bundle with plain (non-bezel) image layers that have alpha (stickers, badges, decorations). Bezeled images are unaffected.

GenerateImage may bake the transparency checkerboard as opaque pixels

Some image-generation tools produce RGB PNGs (no alpha) where the “transparent” checkerboard is opaque gray. Verify with magick identify -format "%[channels]". For crisp transparent stickers (rounded rectangles, polygons, short text), build the PNG procedurally with ImageMagick.