Skip to content
Marketing
Skill

/create-imessage-mockup

Render pixel-accurate iMessage screenshot mockups (DM or group) from a thread JSON. Supports minimal, with-keyboard, and full iPhone 15 Pro frame variants. Outputs HTML + PNG.

From plugin
goose-skills
1.2k200 skills
Install
$ npx -y skills add gooseworks-ai/goose-skills --skill create-imessage-mockup --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/create-imessage-mockup

Context preview

The summary Claude sees to decide when to auto-load this skill.

Render pixel-accurate iMessage screenshot mockups (DM or group) from a thread JSON. Supports minimal, with-keyboard, and full iPhone 15 Pro frame variants. Outputs HTML + PNG.

SKILL.md

create-imessage-mockup.SKILL.md
name: create-imessage-mockup
description: Render pixel-accurate iMessage screenshot mockups (DM or group) from a thread JSON. Supports minimal, with-keyboard, and full iPhone 15 Pro frame variants. Outputs HTML + PNG.

create-imessage-mockup

Generate iMessage screenshots that look like real iOS captures — correct bubbles with tails, typing indicators, timestamps, "Delivered" captions, group avatars + sender names, keyboard chrome, and an optional iPhone 15 Pro bezel with Dynamic Island and status bar.

Purpose

Turn a structured thread JSON into a believable iMessage screenshot — first as standalone HTML (`generate.js` + `templates/chat.css`), then rasterized to PNG with headless Chromium (`screenshot.js`/`render.js` via Playwright). It is the atom you reach for when an ad, social post, or video scene needs a fake-but-convincing iOS message capture.

What it gets right, grounded in the renderer:

  • **Bubble runs and tails** — blue `sent` bubbles (right) and gray `received` bubbles (left), with a curved tear-drop tail drawn only on the *last* bubble of each consecutive sender run (`isLastOfRun` in `generate.js`).
  • **Dark-themed iOS chrome** — `theme: "dark"` flips the page to the iOS dark conversation look; the status bar, Dynamic Island, and keyboard match iPhone 15 Pro.
  • **Group affordances** — group threads (`mode: "group"`) add per-sender colored avatar circles, sender names above the first bubble of a run, and a 4-tile group-header badge.
  • **Beats for storyboards** — `timestamp` pills, a static-but-mid-animation `typing` three-dot bubble, `attachment` cards, and "Delivered"/"Read" captions let you stage individual frames of a conversation.
  • **Three crops** — `--minimal` (bubbles only), `--with-keyboard` (header + iOS keyboard), and `--with-iphone-frame` (full bezel + Dynamic Island + status bar over a gradient backdrop).

The atom embeds **no LLM** — it is deterministic. The orchestrating agent is responsible for composing the thread JSON; the renderer only draws exactly what the JSON says.

When to use

  • Need a fake iMessage screenshot for an ad, social post, video scene, or product mockup.
  • Want a side-by-side hero image showing a conversation in an iPhone frame.
  • Need a typing indicator or "Delivered" beat for a video storyboard.

If you're rendering programmatic graphic frames more broadly (cards, posters, infographics), use `create-goose-graphics` instead.

Inputs

The skill is deterministic — it does not embed an LLM. To translate a free-form prompt into a thread, the orchestrating agent (you) composes a JSON file matching the schema below, then invokes the renderer.

Thread JSON schema

{
  "mode": "dm" | "group",
  "title": "Karaoke Crew",
  "participants": [
    { "id": "me",    "name": "Me",    "self": true },
    { "id": "sarah", "name": "Sarah", "color": "#FF9500", "initials": "S" }
  ],
  "messages": [
    { "type": "timestamp", "label": "iMessage\nToday 9:41 AM" },
    { "type": "timestamp", "bold": "Sat, Jan 2", "light": "11:07" },
    { "type": "text",      "from": "sarah", "text": "Did we crash it?" },
    { "type": "text",      "from": "me",    "text": "Couldn't withstand our friendship", "delivered": true, "read": false },
    { "type": "typing",    "from": "sarah" }
  ],
  "keyboard": { "leftIcon": "plus" }
}
  • `mode` — `dm` or `group`. If omitted, auto-detected from the participant count.
  • `participants[].self: true` marks the user (sent bubbles, no avatar).
  • `participants[].color` is the avatar background; defaults from a 6-color palette.
  • `participants[].initials` defaults to the first letter of `name`.
  • `messages[]`:
  • `timestamp` — centered pill. Use `label` (newline-separated bold/light) or explicit `bold` and `light` fields.
  • `text` — text bubble. `delivered: true` on the last sent bubble in a run renders the "Delivered" caption (or "Read" if `read: true`).
  • `typing` — animated three-dot bubble (rendered as a static mid-animation frame for screenshot determinism).
  • `keyboard.leftIcon` — `"plus"` (default) or `"camera"`.

CLI

node render.js --thread examples/group-with-frame.json --with-iphone-frame
node render.js --thread examples/dm-with-keyboard.json --with-keyboard
node render.js --thread examples/dm-minimal.json       --minimal
node render.js --thread my-thread.json --with-keyboard --output ./my-exports/ --name nightout

Flags

| Flag | Effect | |---|---| | `--thread <path>` | (required) JSON file matching the schema above | | `--prompt "<brief>"` | prints the schema and exits — agent must compose a thread.json and re-invoke | | `--minimal` | bubbles + timestamps only (no header, no keyboard, no frame) | | `--with-keyboard` | bubbles + iOS keyboard chrome (default) | | `--with-iphone-frame` | full iPhone 15 Pro bezel + Dynamic Island + status bar + soft gradient backdrop | | `--dm` / `--group` | force chat mode (otherwise auto-detected from participants) | | `--name <slug>` | override the output folder slug | | `--output <dir>` | parent dir for the dated output folder; default `./imessage-mockup-exports/` |

Frame flags are mutually exclusive.

Output

<output>/<YYYY-MM-DD>-<slug>/
  index.html       # full standalone HTML
  screenshot.png   # rendered PNG (DPR 3, "Retina")
  thread.json      # copy of the input for reproducibility

Default `<output>` is `./imessage-mockup-exports/` in the cwd.

Workflow

1. Receive a prompt or existing thread JSON. 2. If only a prompt was given: compose a thread.json matching the schema, save it. 3. Run `node render.js --thread <path> [flag]`. 4. Open the resulting PNG to verify the layout. If something looks wrong (clipping, wrong tail side, missing avatar), edit the thread JSON or the relevant template under `templates/` and re-render.

Setup (one-time)

cd skills/ads/capabilities/create-imessage-mockup
npm install
npx playwright install chromium

Files

| File | Purpose | |---|---| | `render.js` | CLI entry —

Read more
Ships withgoose-skills

Put your AI agent on the growth team. Research customers and competitors, analyze what is working, create the next campaign, and learn from the result.

Get the whole plugin

Other skills on goose-skills.