| name | screenshot-format |
| description | Reference for the `.screenshot` document format used by ScreenShotComposer (the macOS package bundle, JSON manifest, per-platform composition lists, layer schema, asset packaging, export pixel sizes, and bezel catalog). Read this whenever authoring or editing a `.screenshot` file by hand, generating one from a script or test fixture, building a template that produces compositions, or debugging save/load issues for `CompositionRecord`, `CompositionLayerRecord`, `EmbeddedImageAsset`, `PlateAxisAlignedFrame`, or `ScreenshotPackageSerialization`. |
.screenshot document format
ScreenShotComposer documents are macOS package bundles with the UTI com.garrabrant.screenshot (conforms to public.package). Finder shows the bundle as a single file; "Show Package Contents" reveals plain JSON plus an assets/ directory of raster files. Read/write goes through ScreenShotComposer/ScreenshotPackageSerialization.swift (CW-50). The on-disk JSON is the source of truth — base64 image bytes never go inside JSON.
Use this skill when:
- Hand-writing or scripting a
.screenshot file (test fixtures, golden files, demo content).
- Authoring a new code-side template (use the template-author skill, which depends on this reference).
- Debugging migration/serialization (legacy
headline/caption/image -> layers, plate-frame migration, asset rehydration).
- Writing parsers/exporters in another language.
Bundle layout
MyDocument.screenshot/ directory bundle (UTType .screenshotDocument)
info.json manifest (schemaVersion, app, about, export presets, sidebar order)
mac.json { "platform": "mac", "compositions": [ CompositionRecord, ... ] }
iphone.json same shape, "platform": "iphone"
ipad.json same shape, "platform": "ipad"
assets/
mac-01-<slug>-image-02.png raster bytes for one EmbeddedImageAsset
iphone-01-<slug>-background-01.jpg ...
QuickLook/
Preview.png first non-empty image in sidebar order; lets Finder/Quick Look preview without an extension
Hard caps: 10 compositions per platform (ScreenshotFilePayload.maxCompositionsPerPlatform). Each platform always has one <platform>.json (empty compositions: [] is fine).
Where the canonical types live
| Concept | Swift type | File |
|---|
| Top-level payload | ScreenshotFilePayload | ScreenShotComposer/ScreenshotDocumentFormat.swift |
| One screenshot in a bucket | CompositionRecord | same |
| One layer (text/image/background/group) | CompositionLayerRecord | same |
| Pixel-space layer rectangle | PlateAxisAlignedFrame | same |
| Plate gradient (2-stop) | ExportPlateLinearGradientSettings | same |
| Plate gradient (multi-stop) | ExportPlateAdvancedGradientSettings | same |
| Plate fill discriminator | PlateBackgroundFillKind | same |
| Image bytes wrapper | EmbeddedImageAsset | same |
| Bundle read/write | ScreenshotPackageSerialization | ScreenShotComposer/ScreenshotPackageSerialization.swift |
| Mac plate sizes | MacAppStoreExportPreset | ScreenShotComposer/MacAppStoreExportPreset.swift |
| iPhone/iPad plate sizes | AppStoreMobileExportDimensions | ScreenShotComposer/AppStoreMobileExportDimensions.swift |
| Bezel catalog (PNG + inner-rect) | ProductBezelCatalog, ProductBezelDefinition | ScreenShotComposer/ProductBezelCatalog.swift, ScreenShotComposer/ProductBezels/catalog.json |
Always defer to those types if this doc and the code disagree.
Quick checklist for a hand-built file
- Pick
schemaVersion: 4, app: "ScreenShotComposer".
- Choose one
exportGroupPreset* per platform from the allowed sets (see export-sizes.md). Every composition in a bucket inherits that pixel size; mismatched values get normalized away.
- For each composition, position layers via
plateFrame in pixel coordinates (top-left origin, may extend off-plate). Do not use the legacy horizontalOffsetNormalized / textWrapWidthFraction family — those are read-only migrations.
- Always include exactly one
kind: "background" layer at the lowest sortOrder. ensureBackgroundLayerIfNeeded() enforces this on load; new files should ship it directly so they round-trip cleanly.
- For image layers, write
image: { mimeType, assetPath } (no dataBase64 field) and put the actual bytes in assets/<assetPath>. JSON encoder uses [.prettyPrinted, .sortedKeys, .withoutEscapingSlashes].
- For text layers, set at minimum
kind, sortOrder, textContent, textStyle, plateFrame. Defaults match CompositionLayerRecord.init; omit fields you want at default.
- After serializing all platforms, regenerate
QuickLook/Preview.png from the first non-empty image in sidebarPlatformOrder (or omit the directory if there is none).
References
Related skills and tools
- template-author skill — uses this reference to add or edit code-side templates in
ComposerTemplateLibrary.swift.
bin/refresh-product-bezels — rescans bezels/PNG, regenerates ScreenShotComposer/ProductBezels/catalog.json.
bin/refresh-template-previews — re-renders <template-id>-<platform>-<scene>.png thumbnails.
bin/test-mac — runs the round-trip serialization tests under ScreenShotComposerTests/.