format-ui-mockup — the thread is the scene, the frame is the brand
1. Read first
knowledge/ad-formats/_FORMAT-CORE.md(doctrine, gates, launch). Binding.skills/dawn-statics/SKILL.md(the eight locks, copy method, review gate). Every lock applies; the exceptions are in §7 of this file and nowhere else.references/beat-sheet.md(thread beats + line rules),references/render-spec.md(deterministic render, frame geometry),references/d16-proposal.json(proposed templates.json entries),references/sources.md.output/dawn-combo-map-2026-10-05/MAP.md§2B (recipe B; testimonial statics are the 5 weakest pairings) and the stake bankoutput/creative-strategy-cooper-2026-10-05/dawn-stakes.md.~/.claude/projects/-Users-ayden/memory/corrections-hot.mdbefore writing any line.
2. When to use / when not
- Use to test a new static TYPE on the proven static body (Fish 10-04: "the image itself matters the most and what you call out there"). The thread carries one stake that lands on her, in real words, inside a vessel she reads as content instead of an ad.
- Evidence status: untested as a scene-thread; fake-UI is a weak signal at best. Thiswakesthem2 (advertorial UI, template D08) is the best static CPA in the account ($3,776 / 164 / $23.02), but the ledger rules it "execution-specific, not format-carried": the sniper P1-A fresh fake-UI statics (review card / search bar / star rating) spent $48.66 for 0 purchases, and the 7-25 m1c sister text thread got $0.49 and was never read (starved in a shared ad set). davidaistar claims UI mockups "lower ad defense" with lower CTR but higher BOF conversion; unverified.
- Don't use for: a review or result told in a thread ("after" bubbles, a photo of the band sent in the chat) = a testimonial static, the losing device (MAP.md §2B); Notes-app lists, Reddit/Facebook post screenshots, tweets, call screens (§3 bans); the natives lane (natives ban screenshot vessels entirely, Fish 9-30); stakes the mornings didn't cause; college/kid-money stakes.
3. The format
- 1:1, 2048 px (the static grid; 4:5 only as a later one-variable test). Three zones: caption bar (brand-voice headline naming her and ADHD) → thread card (3-6 bubbles, iOS Messages light mode, rendered from HTML) → product zone (real band cutout, root-cause sub, mechanism sub, navy pill).
- Thread types, ranked by fit:
| Rank | Thread | Why it fits | Receipts / risk |
|---|---|---|---|
| 1 | Co-parent → mom (husband / ex) | The accuser close to her (recipe A's strongest stake) in a vessel that needs no narrator; stake on mom is the static money ($178K, 1.86) | VOC: "let him be late" (6 corpus hits), survey S04 "On mornings my husband has wake up… I still end up doing it". Keep him reasonable and wrong: blame/lecture/villain framings died in every batch |
| 2 | Teen → mom, from bed | Blame lands on her from the kid; the line is already a live static callout | "Why didn't you wake me" (3 hits; 10-04 a2 PASS). Vary teen age/gender per variant |
| 3 | Mom ↔ sister/friend (her vent) | Recipe B allows confession; her own words about the burden | m1c (sister thread) starved; it was a before/after story. Burden only, never an "after" |
| 4 | School → mom (attendance text) | Stake bank #6 (truancy letter in her name) is the top legal stake | Attendance-shame statics $121 / 0, m1a attendance portal $20 / 0. Reserve; needs Fish's go |
- Banned vessels (don't build, with the reason): Notes-app list (statics README "Not templated" + Fish 9-30 natives ban); Reddit / Facebook post screenshot ("a facebook or reddit post inside of a facebook post doesnt make sense", Fish 9-25); call screen (README ban, fake-scarcity family); review/star card (testimonial; P1-A $48.66 / 0). Tweet: same feed-inside-a-feed problem and davidaistar uses it as a testimonial template, so it needs Fish's go before any build.
- Reference: davidaistar HEa4AVv-ths BOF set (testimonial / iMessage / tweet / offer). We keep the vessel; we change what it carries: a blame scene, not a review (references/sources.md).
4. Why it sells
- Recognition first: she has had this exact text. A thread is the format where the accuser says it in his own words without a narrator, so the stake reads as overheard, not pitched.
- Recipe B frame, recipe-A stake. The static wins on a brand-voice callout to her, her burden, exhaustion and an independence/calm payoff, with guarantee/science authority (MAP.md §2B). So the caption bar is brand voice ("If your ADHD kid's mornings look like this"), the thread is the burden and the blame as a scene, and the product zone carries root cause, mechanism and the guarantee. No person vouches for the product anywhere. That is why it isn't a testimonial: a testimonial is someone saying the product worked; this thread never mentions the product or a result.
- Problem-aware: the first bubble names her situation by an observable symptom (he's late, he's still asleep, it's on her). The mechanism lines turn it.
5. Beat sheet (full rules in references/beat-sheet.md)
| Beat | Where | Job | Must contain | Line rules |
|---|---|---|---|---|
| 0 Caption | top bar | Name her + ADHD in brand voice | ADHD; "your" reader; ≤8 words | Recipe B POV; no question that only works after reading the thread |
| 1 Opener | bubble 1 (them) | The stake, in action | Verbatim VOC, ≥5-word corpus hit | ≤12 words; readable alone at feed size; no backstory |
| 2 Her burden | bubble 2 (me) | Prove she's the alarm | Her verbatim line (tries, knocks, yelling) | ≤10 words; she never lectures |
| 3 Escalation | bubble 3-4 (them) | The blame lands / costs her | Consequence the mornings caused | One new fact per bubble; reasonable, wrong |
| 4 Last word | bubble 4-6 (me, optional) | Exhaustion, unresolved | Her verbatim | Thread ends unresolved; "Delivered" under it |
| 5 Turn | product zone | Root cause + mechanism | Fish's ruled lines verbatim | Root cause, then mechanism, then pill |
6. Pack spec (static spec.json, gen_statics shape + one thread block)
-
Step 0 — combo plan (feedback loop,
workflow-combo-loop):python3 scripts/combo_loop/plan.py --format format-ui-mockup --brand dawn→ pick one combo (a paying parent + ONE changed dimension) and paste its block into the pack front matter / job or spec JSON ("combo": {...}; no file →tags.py register --prefix):combo_avatarcombo_anglecombo_povcombo_authoritycombo_stakecombo_stake_oncombo_emotioncombo_root_causecombo_mechanismcombo_payoffcombo_devicecombo_formatcombo_parentcombo_variablecombo_ad_prefix(= the launched Meta ad-name prefix).python3 scripts/combo_loop/tags.py check <pack>must PASS before concept approval; the weekly refresh reads results back by that prefix. -
Spec lives in the batch dir (
output/dawn-ui-<slug>-<date>/spec.json). Per static:slug,layout(absolute path to the sourced iOS ref, §9),template: "D16",adset,scene: null,lines,voc,source,why,alts,thread. lines.headline= caption bar.lines.sub= root-cause sub.lines.bullets= the bubbles in thread order (so the gate's qualifier ban, one-sentence and ≤18-word checks run on every bubble).lines.mechanism,lines.pill= product-zone lines (static_review checks them for text_exact; the gate does not QUAL them).voc= every bubble; each must hitvoc_check.py(a hit under 5 words proves nothing: the opener needs a ≥5-word span). Survey verbatims hit since 10-06 (the buyer survey CSVs are in the corpus; the hit printssurvey+ file); a survey line still at 0 (newer export not on disk) goes inwaiverswith file:line.thread={"type": "coparent|teen|sister|school", "contact": "<first name or Mom/School>", "sides": ["them","me",…] (parallel to bullets), "receipt": "Delivered"}.whynames the card row (experience / emotion / behavior / desire / angle);alts2+ caption headlines (they become the ad titles).waivers(read by gen_statics.py itself since 10-06;{"slug","rule","reason"}, rule idrule9or a failure substring): rule 9's default SA2 Apology-Mom chain (fires on every static unless the spec declares its ownchain: it wants "dawn band" + "startle" + "calm") and any hand-verified survey line, each with a reason. Keep the pill inlines.pill, notbullets; its text is "Wake up guaranteed · 60 nights" (product-truth; never "60 days").
7. Visual grammar (and the lock reconciliations)
- Brand lock: a native UI can't be navy/sand, so the FRAME carries the brand and the thread card keeps true iOS light-mode colors. Sand
#f3ece4ground, Halant 700 caption in slate navy#2f4a63, one gold#fdac2bunderline max, Montserrat subs, navy#2d3452pill with white text. The thread card is ≤60% of the canvas so the frame reads as Dawn. - Product lock: the band appears only in the product zone, the real
product-cutout-unlit.pngpasted with PIL (no generated band, LED unlit). Never in a bubble, never sent as a photo in the chat (that is the testimonial move). - Card lock: one card item per static; bubbles are verbatim VOC. Exception (stated): lock 3 says quotes are credited to the forum; Fish 10-03 later ruled "no attribution on static quotes", so no credit line. "Never dressed as buyers" still binds: no bubble mentions Dawn, a purchase or a result.
- Qualifier ban vs UI realism: no status bar (crop above the contact header), no "Today 6:52 AM" header (start mid-thread), receipt reads "Delivered" only (never "Read
- Names and faces: contact = a common first name (or "Mom", or a school office name with no real school), grey initials avatar, never a photo or face, never a real customer or username. No surnames, no kid names in bubbles unless in the verbatim line.
- Legibility: bubble text ≥60 px on the 2048 canvas (readable at 400 px feed width), ≤40 bubble words total, ≤6 bubbles. Blue sent bubbles stay the minority: the accuser's grey bubbles carry the stake.
- Meta/UI safety: no input bar, keyboard, notification banner, unread badge, "iMessage" placeholder, Apple logo or any non-functional button.
- Variant B (photo overlay, Fish 10-04 priority format): a real photo of the band in a home moment (nightstand, counter, a teen's wrist) with the thread card overlaid. Not buildable yet: the only real worn-band asset is
output/dawn-iterate-2026-10-04/statics/assets/arm-real-unlit.png, and no real flat-lay photo exists (10-04 RENDER-LOG). Needs Fish to shoot 3-5 home photos. Shot spec to send him (starpophow-to-create-product-photos-with-ai): phone at full resolution (short side ≥2048 px after crop, no screenshot/compression), soft window light or an overcast day (no direct sun, no flash), phone steadied, band lying flat or worn naturally, display dark, a quiet area for the card. Note the light direction per photo: the card's drop shadow falls the same way (render-spec Variant B).
8. Audio
None (static). The primary text and title are the parent static's, verbatim (one variable = the image).
9. Production (render is $0; review calls are Gemini)
B=output/dawn-ui-<slug>-<date>; cd ~/.openclaw/workspace
python3 scripts/statics/voc_check.py "<bubble 1>" "<bubble 2>" … # every bubble; 0 = rewrite (or survey waiver with file:line)
python3 scripts/statics/gen_statics.py $B/spec.json --check # real gate; waived findings print as WAIVED + reason (10-06)
python3 scripts/statics/gen_statics.py $B/spec.json --list # approval sheet incl. waivers
# + CALLOUTS.md table with every bubble → Fish approves callouts and threads BEFORE any render
# RENDER ($0, built 10-06): HTML → Playwright element screenshot → PIL brand frame → $B/renders/<slug>.png + .render.json
python3 scripts/statics/render_thread.py $B/spec.json [--size 2048x2048,1080x1350,1080x1920] [--only <slugs>]
# exit 1 = card overflows at 60 px/2048 text (cut a bubble), clock time, or HTML text != lines.bullets; 9:16 keeps y 14-65 %
# intermediates (html, *.thread.png) go to $B/thread/, outside renders/; iOS values PROVISIONAL until ui-refs/ has the real ref
python3 scripts/statics/static_review.py $B/renders --spec $B/spec.json # sidecars; FAIL = fix the template, not a regen
python3 ~/ad-batch-hub/stage-session.py $B/renders --brand "Dawn Band" --type static --notes "UI mockup threads" --push
gen_statics.py --listworks (it readswaiverssince 10-06).--outdoes NOT fit this format: it sends text to GPT Image, which garbles UI text. Never render the thread with an image model.- The gate needs
layoutto resolve to a file: the real iOS Messages screenshot ref (§12) atskills/format-ui-mockup/references/ui-refs/. It doesn't exist yet, so the gate fails until it's sourced. That is correct. - Cost per finished static: $0 render + 1-2 Gemini review calls. Time: ~5 min per static once the renderer exists.
10. Gates & QA checklist
- [ ] Parent body/title/link named (current static parent, with CPA); ONE variable = the image type.
- [ ] Thread type from the §3 ranking; school threads only with Fish's go; no banned vessel.
- [ ] Every bubble is a corpus hit (opener ≥5-word span) or a waived survey verbatim with file:line.
- [ ] Stake lands on her and the mornings caused it; no product, purchase or result in any bubble.
- [ ] Accuser reasonable and wrong; she never lectures; thread ends unresolved.
- [ ] Caption names her + ADHD; root cause then mechanism (Fish's ruled lines); pill present.
- [ ]
gen_statics.py --checkPASS with every waiver reasoned; Fish approved the sheet + bubble table. - [ ] Render: no status bar, no clock, "Delivered" only, no input bar, initials avatar, bubble text ≥60 px.
- [ ] Side-by-side eye check vs the real iOS ref (the 9-25 generic-HTML Notes render "doesnt look enough like the notes app").
- [ ] static_review PASS/WARN on the current rubric, WARNs listed for Fish; eyeball at full size and at 400 px.
11. Variants & test plan
- Test 1: one ad set "UI-1 coparent" in Testing CBO, 3 statics = 3 opener bubbles on the same thread type, same frame, same body/title/link as the current static parent. Control = that parent's live D-grid statics (10-04 slop-it1004 sets used the slop ADHD body).
- Floor required. m1c died at $0.49 in a shared ad set; the ledger's P0 rule is a protected budget for new batches. Fish sets the floor; Meta writes need his go.
- Read at 7 days: CPA vs the parent's statics; also link CTR and click→purchase (davidaistar's claim is lower CTR, higher conversion; read both before calling it). Never pause, reduce; 3x CPA kill outside learning.
- Then one variable at a time: thread type (teen → sister → school with Fish's go), variant B photo overlay vs frame, dark mode, 4:5 vs 1:1.
- Record the launch in
project_launch_<date>_ui-mockup.mdwith ad set IDs and the verdict date.
12. Failure modes
- Image model garbles UI text → deterministic render only.
- Generic HTML doesn't look like the app (9-25 Notes correction) → copy a REAL screenshot: source a current iOS Messages light-mode screenshot from Reddit (r/iphone via StealthyFetcher, as the 9-25 Notes ref was sourced), strip usernames, save to
references/ui-refs/. The 9-25 Notes ref path in memory no longer exists on disk. - Reads as a testimonial (result, "after", product photo in chat) → recipe B's losing device; rewrite as the blame scene.
- static_review FAIL —
product<6 with no band (score 5) → band always in the product zone;no_adhd→ caption names ADHD;readable_clock_time→ crop/strip times;brand<6 from the blue bubbles → shrink the card, widen the sand frame. - gen_statics gate rule 9 hard-codes the 9-04 Apology-Mom chain ("dawn band" + "startle" + "calm"); the "wrong guarantee" regex flags "60 days" in any QUAL'd slot, and it is right to: the guarantee is 60 nights → waive
rule9with reasons inwaivers(gen_statics reads them since 10-06), pill = "Wake up guaranteed · 60 nights" inlines.pill, don't bend copy to the regex and don't route a wrong number around it. - Stitched thread reads as a real conversation: the bubbles are real lines from DIFFERENT people, so the exchange itself never happened. No caption or primary text may claim it did ("my husband texted me this"); the caption stays brand voice. Fish rules on the device at gate 1 (open in the 10-06 audit).
- Starved ad set (m1c) → own ad set with a floor.
- Meta rejection for fake system UI → no input bar, banners, badges or buttons.
- Font licence: SF Pro (
/System/Library/Fonts/SFNS.ttf) is licensed by Apple for Apple-platform UI mockups, not ads. render_thread.py defaults to Inter (SIL OFL 1.1,knowledge/brands/dawnbands/fonts/Inter-400.ttf+ 600, 10-06);--ui-font sfprois for internal mockups only.
13. Sources
~/research/davidaistar/analysis/{diff_statics.md, gemini_HEa4AVv-ths.md, guide_copy_images_shorts.md}, REPORT.md §2.11; skills/dawn-statics/SKILL.md; scripts/statics/{gen_statics.py, voc_check.py, static_review.py}; ~/ad-batch-hub/stage-session.py (review_gate); knowledge/brands/dawnbands/static-templates/{README.md, templates.json}; output/dawn-iterate-2026-10-04/statics/{CALLOUTS.md, RENDER-LOG.md, check_gate.py, spec.json}; hub batches sniper-p1p2-2026-07-20, m1-retroproof-fakeui-2026-07-25, learnings.json; skills/native-image-gen/SKILL.md (screenshot bans); memory feedback_native_image_scrape_first, feedback_native_image_selection_credit, feedback_native_image_sourcing_corrections, corrections-archive-2026-10-03 (no attribution); MAP.md; dawn-stakes.md.
Not built yet (needs Fish's go)
- His tweet: not built (feed-inside-a-feed, Fish 9-25 logic; Fish's go needed)