Skip to main content
ClaudeWave
Skill1.2k repo starsupdated 5d ago

create-chatgpt-mockup

Render pixel-accurate ChatGPT mobile (iOS) screen mockups in light mode from a thread JSON. Supports user text bubbles, user image attachments, assistant markdown prose, citation chips, the OpenAI spiral logo, the Apps-SDK GPT chip in the composer, and three header styles (model-tag, plain title, "Get Plus"). Fixed 9:16 viewport. Outputs HTML + PNG.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/gooseworks-ai/goose-skills /tmp/create-chatgpt-mockup && cp -r /tmp/create-chatgpt-mockup/skills/ads/packs/video-ad-formats/create-chatgpt-mockup ~/.claude/skills/create-chatgpt-mockup
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# create-chatgpt-mockup

## Purpose

Generate single-frame ChatGPT mobile screens that read as real iOS captures — accurate header chrome, user/assistant message styling, composer pill, status bar, and the OpenAI spiral mark. Designed for use inside ad creatives, social posts, video storyboards, and product mockups.

If you need an **animated, video-recorded chat reveal** (bubbles popping over time, SFX, music bed, end card), use the molecule `skills/molecules/create-chatgpt-video-ad`. This atom only produces a single still frame.

## Inputs

Compose a `thread.json` matching the schema below, then pass it to `render.js`.

### Thread JSON schema

```json
{
  "statusBar": {
    "time": "9:41",
    "dnd": false
  },
  "header": {
    "style": "model-tag",
    "title": "ChatGPT",
    "model": "5.1",
    "rightIcons": ["personPlus", "dottedCircle"]
  },
  "messages": [
    { "type": "user-image", "src": "assets/photo.jpg", "aspect": "square" },
    { "type": "user-text",  "text": "Make this face sunscreen better" },
    {
      "type": "assistant",
      "title": "Optional H1 with spiral logo",
      "feedback": true,
      "text": "Markdown-ish prose. **bold**, *italic*, ## H2, * bullet, 1. ordered, [[cite:Source +1]], [[icon:💡]] inline-icon."
    }
  ],
  "composer": {
    "placeholder": "Ask anything",
    "text": "Typed text to show with caret",
    "cursor": true,
    "streaming": false,
    "chip": { "name": "SeatGeek" }
  }
}
```

### Field reference

**`statusBar`**
- `time` — string shown top-left (e.g. `"9:41"`, `"08:18"`).
- `dnd` — when `true`, renders a small moon glyph next to the time (matches iOS Focus-on indicator).

**`header.style`** — one of:
- `"model-tag"` — `≡   ChatGPT 5.1 ▾   ●●` — used when a specific model is active.
- `"title-only"` — `≡   ChatGPT ›   ●●` — the plain in-chat header.
- `"plain-title"` — `≡   Get Plus ✦   ●●` — for the upsell/empty-state title.

**`header.rightIcons`** — array of icon keys, rendered left-to-right on the right side. Available: `"personPlus"`, `"dottedCircle"`, `"edit"`, `"more"`. Default is `["personPlus", "dottedCircle"]` for `model-tag`, `["edit"]` for `title-only`.

**`messages[]`** — one of:
- `{ "type": "user-image", "src": <path>, "aspect": "square"? }` — relative `src` paths resolve against the thread.json directory.
- `{ "type": "user-text", "text": <string> }` — right-aligned soft-gray bubble.
- `{ "type": "assistant", "text": <markdown>, "title"?: <string>, "feedback"?: <bool> }` — left-aligned plain prose. If `title` is set, an OpenAI spiral logo + bold title is rendered above the body. `feedback: false` hides the thumbs-up/down chips.

**Assistant `text` markdown** — supported syntax:
- `**bold**`, `*italic*`
- `# H1`, `## H2`, `### H3`
- `* item` / `- item` bullet lists
- `1. item` ordered lists
- `---` horizontal rule
- `[[cite:Some Source +1]]` — pill citation chip
- `[[icon:💡]]` — inline emoji prefix (kept un-escaped)
- Single `\n` → soft line break (`<br>`); double `\n\n` → new paragraph

**`composer`**
- `placeholder` — shown when `text` is empty (default `"Ask anything"`).
- `text` — typed-in text. When present, the send button activates (black bg).
- `cursor` — whether to render the blinking caret after `text` (default `true`).
- `streaming` — when `true`, replaces the send arrow with a stop square (matches "response generating" state).
- `chip` — optional GPT chip in the composer. `chip.name` is the GPT name. Sets `placeholder` to `"Ask ChatGPT"` if you don't override it.

## CLI

```bash
node render.js --thread examples/01-sunscreen-image.json
node render.js --thread my-thread.json --output ./exports --name nightly
```

### Flags

| Flag | Effect |
|---|---|
| `--thread <path>` | (required) JSON file matching the schema above |
| `--output <dir>`  | parent dir for the dated output folder; default `./chatgpt-mockup-exports/` |
| `--name <slug>`   | override the output folder slug |

## Output

```
<output>/<YYYY-MM-DD>-<slug>/
  index.html       # standalone HTML (CSS inlined)
  screenshot.png   # 2250 × 4002 PNG (DPR 3, 9:16)
  thread.json      # copy of the input for reproducibility
```

## Workflow

1. Receive a brief or existing thread JSON.
2. If only a brief is given, compose `thread.json` matching the schema above.
3. Run `node render.js --thread <path>`.
4. Open the PNG. If anything looks off (header alignment, bubble width, missing icon), edit the JSON or `templates/chat.css` and re-render.

## Setup (one-time)

```bash
cd create-chatgpt-mockup
npm install
npx playwright install chromium
```

## Quality checks

- [ ] Renders in **light mode only** (white background, dark text). Dark-mode rendering is out of scope for v1.
- [ ] Status bar time and right cluster (signal / wifi / battery) sit at the very top, no clipping under the iOS status-bar safe area.
- [ ] Header chrome icons (hamburger / personPlus / dottedCircle / edit / more) all visually weigh the same as a real ChatGPT iOS screenshot at the same display size — **eyeball, don't pixel-match**. Sub-reading-weight icons read as broken even when their pixel dimensions "match the spec."
- [ ] Header model tag (`5.1`, `5.2`) sits inline with `ChatGPT` and its chevron — no wrapping.
- [ ] User bubble is **right-aligned**, soft-gray (`#F4F4F4`), `border-radius: 28px`, max-width 78% of stage.
- [ ] User image attachments use the same `28px` corner radius and sit right-aligned above the text bubble.
- [ ] Assistant body is plain prose (no bubble), left-aligned, full-width within the gutter.
- [ ] **Composer corner radius is 999px** (full pill), `1px` border `#E5E5E5`, send button is `44 × 44` round.
- [ ] When `composer.text` is set: send button is **solid black** with a white up-arrow. Caret sits right after the last character of typed text.
- [ ] When `composer.streaming: true`: send button shows a **black square stop icon**.
- [ ] When a citation marker `[[cite:Foo +1]]` is in the assistant text, it renders as a pill chip inline at the end of the sente