# AI Agent Guide for SoloScreenshot Projects

This is the operational specification for AI assistants that edit a SoloScreenshot / App Screenshot Studio project. Use it to modify project metadata, page copy, localization, screenshot bindings, templates, colors, device appearance, layout, preview state, and export scope without opening the application.

The instructions below describe the current desktop project format and schema version 2.

---

## 1. AI Operating Contract

When a user asks you to edit a SoloScreenshot project:

1. Locate the project folder that contains both `config.json` and `translations.json`.
2. Read both files completely before editing either one.
3. Inspect `screenshots/` when the request involves pages, images, renaming, adding, or deleting.
4. Preserve every unrelated field, page, locale, style override, custom template, and screenshot mapping.
5. Make the smallest change that satisfies the request. Do not “clean up” unknown fields.
6. Keep `schemaVersion` at `2`. If it is missing or older, do not perform a broad migration unless the user asks; add version-2 fields only as needed.
7. Validate all edited JSON and all cross-file references before finishing.
8. Prefer an atomic write: write and validate a temporary file in the same directory, then replace the target.
9. Report which files and page keys changed, plus any assumptions or missing assets.

Never:

- Put comments inside JSON. Use a top-level underscore-prefixed entry in `translations.json` for optional metadata.
- Rename, delete, or replace image files unless the user explicitly requested an image/page operation.
- Remove a page key merely because its translation is incomplete.
- Invent a custom-template structure when an existing preset or custom-template ID can satisfy the request.
- Store image bytes, absolute paths, or `file://` URLs in `config.json`.
- Add a top-level `languages` field to control languages. Active languages are derived from `translations.json`.

---

## 2. Project Folder and Source of Truth

```text
project-folder/
├── config.json
├── translations.json
└── screenshots/
    ├── screenshot-01.png
    └── screenshot-02.png
```

The files have distinct responsibilities:

| Location | Responsibility |
| --- | --- |
| `config.json` | Project settings, screenshot filename bindings, default appearance, per-page styles, preview/export preferences, and custom templates |
| `translations.json` | Page existence, page order, titles, subtitles, and active locales |
| `screenshots/` | Raw app screenshots displayed inside device frames |

### Critical page-key relationship

For every real page key such as `screenshot-01`:

- It must be a top-level key in `translations.json`.
- It may be a key in `config.json.screenshots`.
- It may be a key in `config.json.screenshotStyles`.
- If an image is mapped, its file must exist inside `screenshots/`.
- The image basename should equal the page key: `screenshot-01.png`, not `home.png`.

The application treats non-underscore top-level keys in `translations.json` as the authoritative page list. Their JSON insertion order is the page order shown and exported by the application.

> **Destructive behavior:** When the application loads a project, files in `screenshots/` whose basename is not an active translation page key may be deleted as orphans. Removing or renaming a page key can also discard its screenshot/style binding. Do not remove or rename page keys without explicit user approval and a coordinated rename of all three locations.

---

## 3. Safe Editing Workflow

### 3.1 Read and inventory

Before editing, determine:

- Existing page keys, in order
- Existing locale codes
- Screenshot mappings and whether each file exists
- Project default template and appearance
- Per-page overrides
- Existing custom-template IDs
- Current preview and export selections

### 3.2 Clarify only material ambiguity

Infer obvious intent from existing names and patterns. Ask the user only when a choice would materially change the result, for example:

- The user says “change the second page” but page order is unclear because the JSON is malformed.
- The user asks to add a screenshot but provides no image.
- The user asks for a brand-specific color that cannot be inferred.

### 3.3 Apply a minimal patch

Parse JSON into an object, edit only targeted paths, and serialize with readable indentation. Preserve object order in `translations.json`.

### 3.4 Validate before completion

At minimum verify:

- Both files parse as JSON objects.
- All real translation page keys are non-empty and unique.
- Every `screenshots` and `screenshotStyles` key exists in `translations.json`.
- Every mapped screenshot file exists and its basename matches its page key.
- All locale values are strings.
- All colors and numeric ranges are valid.
- Template, preview-size, preview-page, and preview-language references resolve.

---

## 4. `config.json` Schema

### 4.1 Complete top-level field reference

| Field | Type | Accepted/default behavior | AI editing guidance |
| --- | --- | --- | --- |
| `schemaVersion` | integer | Use `2` | Preserve as `2` |
| `appName` | string | Defaults to `SoloScreenshot` when missing | Safe to edit |
| `platforms` | string array | Values with size presets: `ios`, `android`, `other` | Controls batch export targets |
| `activeTemplateId` | string or null | Built-in or existing custom-template ID | Project default template |
| `bgType` | string or null | `solid` or `linearGradient` | Project default background |
| `bgColors` | string array | Hex colors | One color for solid; normally two or more for gradient |
| `phoneFrameColor` | string or null | Hex color | Project default device-frame color |
| `titleColor` | string or null | Hex color | Project default title color |
| `subtitleColor` | string or null | Hex color | Project default subtitle color |
| `showSensorArea` | boolean | Defaults to `true` | Shows notch, Dynamic Island, or punch-hole |
| `useDeviceFrame` | boolean | Defaults to `true` | Shows the physical phone shell |
| `previewLanguage` | string or null | Must be a locale found in translations | UI preview preference only |
| `previewSizeId` | string or null | Built-in size ID | UI preview and “current size” export |
| `previewScreenshotKey` | string or null | Existing page key | UI preview and “current page” export |
| `exportLangMode` | string | `all` or `current`; default `all` | Saved export-dialog preference |
| `exportSizeMode` | string | `all` or `current`; default `all` | Saved export-dialog preference |
| `exportPageMode` | string | `all` or `current`; default `all` | Saved export-dialog preference |
| `screenshots` | object | `{ pageKey: fileName }` | Image bindings, not the page list |
| `screenshotStyles` | object | `{ pageKey: overrides }` | Sparse per-page overrides |
| `customTemplates` | array | Saved custom-template snapshots | Preserve unless specifically editing templates |

Unknown top-level fields should be preserved.

### 4.2 Supported platform and size IDs

| Platform | `previewSizeId` | Output size |
| --- | --- | --- |
| `ios` | `ios_6_7` | 1290 × 2796 |
| `android` | `android_phone_portrait` | 1440 × 2880 |
| `other` | `other_android_1080_1920` | 1080 × 1920 |

Notes:

- A platform produces exports only when it appears in `platforms`.
- `exportSizeMode: "current"` filters every selected platform by the single `previewSizeId`. This normally produces output only for the platform owning that size.
- If `previewSizeId` is invalid, “current size” export may produce no tasks.

### 4.3 Built-in template IDs

Use IDs exactly as written:

| ID | Layout character |
| --- | --- |
| `app_store_hero` | Centered classic hero |
| `modern_saas` | Text above, phone cropped toward bottom |
| `minimal_clean` | Minimal centered layout |
| `ai_assistant` | Phone-left composition |
| `travel_story` | Story-style bottom composition |
| `health_tracker` | Centered health layout |
| `dashboard_analytics` | Phone-right dashboard composition |
| `dark_cyberpunk` | Dark centered composition |
| `neon_glow` | Neon phone-right composition |
| `gaming_neon` | Gaming phone-right composition |
| `luxury_gold` | Premium bottom composition |
| `finance_pro` | Professional phone-left composition |
| `flight_status_tilt` | Small left tilt |
| `calendar_sync_tilt` | Small right tilt |
| `crisp_orange_tilt` | Large left tilt |

An ID may also refer to an entry in `customTemplates`. Do not guess a custom ID: read it from the array.

If a template ID cannot be found, the renderer falls back visually to the first built-in preset (`app_store_hero`), but the invalid ID remains bad configuration. Fix the reference instead of relying on fallback.

---

## 5. Per-Page Styles: `screenshotStyles`

`screenshotStyles` is a map of page keys to sparse override objects. Omitted fields inherit; `null` is not normally written by the application and should be omitted rather than used to mean “reset.”

```json
{
  "screenshotStyles": {
    "screenshot-02": {
      "templateId": "calendar_sync_tilt",
      "bgType": "linearGradient",
      "bgColors": ["#1D4ED8", "#7C3AED"],
      "titleColor": "#FFFFFF",
      "subtitleColor": "#E0E7FF",
      "phoneFrameColor": "#111827",
      "showSensorArea": true,
      "useDeviceFrame": true,
      "phoneXOffset": 24,
      "phoneYOffset": 40,
      "phoneScale": 1.08,
      "phoneRotationOffsetDegrees": -2,
      "textYOffset": 0,
      "titleScale": 1.05,
      "subtitleScale": 1,
      "titleLineHeight": 1.15,
      "titleSubtitleSpacing": 22
    }
  }
}
```

### 5.1 Override field reference

| Field | Type | Default when not inherited | Valid/safe range or values | Meaning |
| --- | --- | --- | --- | --- |
| `templateId` | string | Project `activeTemplateId` | Built-in or existing custom ID | Base layout for this page |
| `bgType` | string | Template/project value | `solid`, `linearGradient` | Background type |
| `bgColors` | string array | Template/project value | Valid hex colors | Background colors |
| `phoneFrameColor` | string | Template/project value | Hex color | Device shell |
| `titleColor` | string | Template/project value | Hex color | Main title |
| `subtitleColor` | string | Template/project value | Hex color | Subtitle |
| `showSensorArea` | boolean | Usually `true` | `true`, `false` | Notch/island/camera visibility |
| `useDeviceFrame` | boolean | Usually `true` | `true`, `false` | Physical device shell visibility |
| `phoneXOffset` | number | `0` | `-300` to `300` | Horizontal offset in design pixels |
| `phoneYOffset` | number | `0` | `-500` to `500` | Vertical offset in design pixels |
| `phoneScale` | number | `1` | `0.5` to `2` | Device scale multiplier |
| `phoneRotationOffsetDegrees` | number | `0` | `-45` to `45` | Rotation added to template baseline |
| `textYOffset` | number | `0` | `-200` to `200` | Vertical text-group offset |
| `titleScale` | number | `1` | `0.5` to `2` | Title size multiplier |
| `subtitleScale` | number | `1` | `0.5` to `2` | Subtitle size multiplier |
| `titleLineHeight` | number | `1.2` | `0.8` to `1.8` | Title line-height multiplier |
| `titleSubtitleSpacing` | number | `24` | `8` to `80` | Gap between title and subtitle |

Values must be finite JSON numbers, not numeric strings. The renderer clamps geometry and typography, but AI edits should remain inside the documented ranges.

### 5.2 Rotation semantics

`phoneRotationOffsetDegrees` is an offset, not always the final angle. Approximate built-in baselines are:

- Standard layouts: `0°`
- `flight_status_tilt`: `-5.73°`
- `calendar_sync_tilt`: `+5.73°`
- `crisp_orange_tilt`: `-14.90°`

The final rendered angle is the template baseline plus the offset, clamped to `-45°...45°`.

### 5.3 Exact style resolution

For a page, the renderer:

1. Chooses `screenshotStyles[pageKey].templateId` when present; otherwise `activeTemplateId`.
2. Resolves that ID to a custom template first, then a built-in preset.
3. Builds the base style:
   - Existing custom ID: use its `templateSnapshot` and `styleSnapshot`.
   - Built-in ID with no page-level `templateId`: use the preset plus project-level colors/background/device switches.
   - Built-in ID explicitly set at page level: use the preset defaults; project-level appearance is not inherited.
4. Applies all non-null page-level override fields.
5. Clamps numeric layout values.

This nuance matters: adding only `"templateId": "minimal_clean"` to a page intentionally resets its missing appearance fields to that preset, rather than keeping the project background.

### 5.4 Reset and apply-to-all recipes

- **Reset one page to project defaults:** remove that page’s entire entry from `screenshotStyles`.
- **Reset one page to its selected template defaults:** keep only `{"templateId": "..."}` for that page.
- **Apply appearance and layout to all pages:** copy the source page’s complete override object to every existing real page key.
- **Apply only selected fields to all pages:** merge only those fields into every page; preserve the other target-page fields.
- **Set a global default:** edit top-level appearance fields and remove conflicting fields from pages that should inherit them.

Do not create `screenshotStyles` entries for underscore metadata keys.

---

## 6. Colors and Backgrounds

Preferred color syntax is uppercase `#RRGGBB`, for example `#0F172A`. The parser also accepts 8 hex digits as `#AARRGGBB` (alpha first), but six-digit opaque colors are safest.

Rules:

- Include the leading `#`.
- Use only hexadecimal digits.
- For `solid`, provide at least one color; only the first is rendered.
- For `linearGradient`, provide two or more colors for an intentional gradient.
- Never use an empty `bgColors` array together with an active page-level background override.
- Keep adequate contrast between background, `titleColor`, and `subtitleColor`.

Example:

```json
{
  "bgType": "linearGradient",
  "bgColors": ["#0F172A", "#1D4ED8"],
  "titleColor": "#FFFFFF",
  "subtitleColor": "#DBEAFE"
}
```

Gradient direction comes from the selected template. There is no top-level or per-page field for changing gradient direction in schema version 2.

---

## 7. `translations.json` Schema

### 7.1 Canonical structure

```json
{
  "_meta": {
    "note": "Optional metadata; ignored as a page because the key starts with _"
  },
  "screenshot-01": {
    "title": {
      "en": "Create beautiful store screenshots",
      "zh-Hans": "制作精美的商店截图",
      "ja": "美しいストア画像を作成"
    },
    "subtitle": {
      "en": "Export every language and device size in one workflow.",
      "zh-Hans": "一次完成多语言与多尺寸导出。",
      "ja": "多言語・多サイズをまとめて書き出せます。"
    }
  },
  "screenshot-02": {
    "title": {
      "en": "Keep every screen private",
      "zh-Hans": "让每张截图保持私密",
      "ja": "画面データを安全に保護"
    },
    "subtitle": {
      "en": "Local rendering keeps unreleased UI on your machine.",
      "zh-Hans": "本地渲染让未发布界面始终留在设备上。",
      "ja": "ローカル処理で未公開UIを端末内に保ちます。"
    }
  }
}
```

### 7.2 Parsing behavior

- Every top-level key not starting with `_` is a real screenshot page.
- Top-level order determines page order.
- Canonical copy keys are `title` and `subtitle`.
- Legacy aliases `titles` and `subtitles` are accepted, but do not mix singular and plural forms in new edits.
- Each title/subtitle value must be an object of `{ localeCode: string }`.
- Active languages are the union of locale keys found in every title and subtitle map.
- If the requested locale is missing on a page, rendering falls back to that page’s English (`en`) text, then to an empty string.
- An empty subtitle is allowed and will not be rendered.
- There is no automatic translation. Adding a locale to one page makes it globally selectable even if other pages lack it.

Use locale codes consistently. Common supported UI/localization codes include:

`en`, `zh-Hans`, `zh-Hant`, `ja`, `ko`, `de`, `fr`, `es`, `it`, `pt-BR`

Other locale codes can exist in a project, but use standard BCP 47-style codes and preserve the user’s existing convention.

### 7.3 Copy-editing guidance

- Preserve the product claim, tone, and intent; do not translate word-for-word when store marketing phrasing would sound unnatural.
- Prefer concise benefit-led titles.
- As a conservative starting point, aim for roughly 40 characters or fewer for titles and 80 or fewer for subtitles, then account for language and template width.
- Keep terminology consistent across pages and locales.
- Ensure every page has an English fallback when practical.
- When adding a locale, add it to both title and subtitle for every real page unless the user requests a partial translation.
- Do not change page keys while merely rewriting or translating copy.

---

## 8. Screenshot Image Bindings

`config.json.screenshots` is an object, not an array:

```json
{
  "screenshots": {
    "screenshot-01": "screenshot-01.png",
    "screenshot-02": "screenshot-02.jpg"
  }
}
```

For each mapping:

- The key must exist as a real page in `translations.json`.
- The value is a filename only, not a path.
- The file must be located at `screenshots/<filename>`.
- The filename basename must match the page key.
- Common image extensions such as `.png`, `.jpg`, and `.jpeg` should be preserved.

### Coordinated page rename

Only do this when explicitly requested. To rename `old-key` to `new-key`:

1. Rename the top-level translation key without changing its relative order.
2. Move `config.json.screenshots["old-key"]` to `["new-key"]`.
3. Rename the image file so its basename is `new-key`.
4. Move `config.json.screenshotStyles["old-key"]` to `["new-key"]`.
5. Update `previewScreenshotKey` if it equals `old-key`.
6. Validate that no old references remain.

### Add a page

1. Add a new non-underscore top-level key to `translations.json` at the desired position.
2. Add complete title/subtitle locale maps.
3. If an image was provided, place it under `screenshots/` with a matching basename and add the mapping.
4. Add `screenshotStyles[newKey]` only if page-specific styling is needed.

### Delete a page

Deletion is destructive and must be explicit:

1. Remove the translation key.
2. Remove its `screenshots` mapping.
3. Remove its `screenshotStyles` entry.
4. Update `previewScreenshotKey` if necessary.
5. Remove or archive the image only as authorized by the user.

---

## 9. Preview and Export Configuration

Preview fields do not change the design itself:

```json
{
  "previewLanguage": "en",
  "previewSizeId": "ios_6_7",
  "previewScreenshotKey": "screenshot-01"
}
```

Export preferences:

```json
{
  "exportLangMode": "all",
  "exportSizeMode": "all",
  "exportPageMode": "all"
}
```

Semantics:

- `all`: export all values available in that dimension.
- `current`: export only the corresponding preview selection.
- Export platforms always come from `platforms`.
- “All languages” means the union of locale keys derived from `translations.json`.
- “All pages” follows the top-level order of `translations.json`.

If the user asks to prepare a project for a specific single export, update the relevant preview value and its export mode together.

---

## 10. Custom Templates

Each custom template is a self-contained snapshot. The following is a structural outline only; it is intentionally not a usable template because the required background and element details are abbreviated:

```json
{
  "id": "custom_123456789",
  "name": "Brand Blue",
  "version": 1,
  "templateSnapshot": {
    "id": "custom_123456789",
    "name": "Brand Blue",
    "engine": "centerClassic",
    "category": "premium",
    "background": {},
    "elements": []
  },
  "styleSnapshot": {}
}
```

Valid engine names:

`centerClassic`, `bottomCrop`, `leftSlide`, `rightSlide`, `tiltLeft`, `tiltRight`, `tiltLeftLarge`, `tiltRightLarge`

Valid category names:

`recommended`, `ai`, `dashboard`, `premium`

`templateSnapshot.background` and every template element contain required structural fields. Therefore:

- Treat existing custom-template objects as opaque unless the user specifically asks to create or modify one.
- Prefer changing `styleSnapshot` fields, which use the same appearance/layout fields as `screenshotStyles` except `templateId`.
- Keep the custom template’s outer `id` and `templateSnapshot.id` aligned.
- Keep IDs unique.
- Increment `version` when overwriting an existing custom template.
- Before deleting a custom template, replace all references in `activeTemplateId` and page-level `templateId`.
- Creating a custom template by hand is advanced; copying a complete existing template structure is safer than building a partial one.

---

## 11. Common AI Modification Recipes

### Change copy only

Edit only the target strings in `translations.json`. Do not modify `config.json`, page keys, or images.

### Add a language

For every real page, add the locale to both `title` and `subtitle`. Then set `previewLanguage` only if the user wants that locale selected by default.

### Change the entire project’s brand colors

Edit top-level `bgType`, `bgColors`, `titleColor`, `subtitleColor`, and optionally `phoneFrameColor`. Remove the same per-page fields only from pages the user wants to inherit the global palette.

### Give one page a special style

Merge fields into `screenshotStyles[pageKey]`. Preserve other fields already present in that page override.

### Use one template everywhere

Set `activeTemplateId` to the chosen ID. Remove page-level `templateId` only on pages that should inherit it. Preserve other page-specific overrides.

### Center the first page and control its rotation

For the first real page key, center the device with:

```json
{
  "phoneXOffset": 0
}
```

For a non-tilted template, set `phoneRotationOffsetDegrees` to `0`. An offset of `0` preserves a tilted template’s baseline; to produce an approximately straight device on a tilted template, apply the inverse baseline (for example about `-5.73` on `calendar_sync_tilt`) or choose a non-tilted template.

### Alternate visual rhythm across pages

Prefer alternating tilt template IDs or modest rotation offsets on pages 2–5. Keep page 1 clear, high-contrast, and easy to scan. Do not sacrifice text/image separation for decorative motion.

---

## 12. Canonical Version-2 Example

```json
{
  "schemaVersion": 2,
  "appName": "MyApp",
  "platforms": ["ios", "android"],
  "activeTemplateId": "modern_saas",
  "bgType": "linearGradient",
  "bgColors": ["#0F172A", "#1E3A8A"],
  "phoneFrameColor": "#111827",
  "previewLanguage": "en",
  "previewSizeId": "ios_6_7",
  "previewScreenshotKey": "screenshot-01",
  "titleColor": "#FFFFFF",
  "subtitleColor": "#DBEAFE",
  "showSensorArea": true,
  "useDeviceFrame": true,
  "exportLangMode": "all",
  "exportSizeMode": "all",
  "exportPageMode": "all",
  "screenshots": {
    "screenshot-01": "screenshot-01.png",
    "screenshot-02": "screenshot-02.png"
  },
  "screenshotStyles": {
    "screenshot-01": {
      "phoneScale": 1.08,
      "titleScale": 1.1
    },
    "screenshot-02": {
      "templateId": "calendar_sync_tilt",
      "bgType": "solid",
      "bgColors": ["#4F46E5"],
      "titleColor": "#FFFFFF",
      "subtitleColor": "#E0E7FF",
      "phoneRotationOffsetDegrees": -2
    }
  },
  "customTemplates": []
}
```

---

## 13. Final Validation Checklist

Before telling the user the edit is complete, confirm:

- [ ] `config.json` and `translations.json` are valid UTF-8 JSON objects.
- [ ] `schemaVersion` is `2`.
- [ ] No unrelated field or custom template was lost.
- [ ] Translation key order matches the intended page order.
- [ ] Every screenshot/style key points to a real translation page.
- [ ] Every mapped file exists under `screenshots/` and has a matching basename.
- [ ] No page/image was deleted without explicit authorization.
- [ ] All locale values are strings and locale coverage matches the request.
- [ ] `previewLanguage`, `previewScreenshotKey`, and `previewSizeId` resolve.
- [ ] Template IDs are built-in IDs or existing custom IDs.
- [ ] Background arrays are non-empty and colors are valid.
- [ ] All numeric overrides are finite and inside safe ranges.
- [ ] Export modes are only `all` or `current`.

If application execution is available, reopen/refresh the project and visually inspect every changed page in at least the primary locale and target size. Configuration validity does not guarantee that long localized copy will fit every template.
