v0.13 baseline · git 初始化 + 仓库瘦身
把所有本地 demo / 测试 / 上传图 / 调试脚本搬入 local-tests/,写 .gitignore 忽略整个测试目录与 node_modules/。本次起 skill 仓库 只跟踪:SKILL.md / HANDOFF.md / PRODUCT.md / assets/(3 模板)/ references/(15 规则文档)/ agents/openai.yaml / validate-social-deck.mjs / package.json + lock。 历次版本(v0.1-v0.12)的全部实质改动已包含在当前文件状态中—— HANDOFF.md 的版本历史段保留作为时间轴文字记录,但代码层面以 此 commit 为唯一基线,后续逐次 commit 对应 HANDOFF.md 新增段落。 HANDOFF/PRODUCT/category-cookbook/components/style-system 中的 demo 路径引用已加 local-tests/ 前缀。SKILL.md Step 5 line 190 的 'social-card-<slug>/' 是下游用户工作区的命名约定,未改动。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
commit
82d221bb90
26 files changed
+6329
No files matched your search
@@ -0,0 +1,108 @@
|
||||
# Background Systems
|
||||
|
||||
The original Guizang PPT electronic-magazine mode uses WebGL fluid, contour, ink, and chromatic atmosphere. Static Rednote/WeChat images should preserve that feeling when the style mode is Editorial Magazine x E-ink.
|
||||
|
||||
Do not reduce this mode to a flat beige page with a faint grid. Do not add visible grid, dot-matrix, or drafting-paper patterns to the background.
|
||||
|
||||
## Layer Model
|
||||
|
||||
Use 3-5 layers:
|
||||
|
||||
1. Paper base from `theme-presets.md`.
|
||||
2. Procedural paper grain.
|
||||
3. Ink wash, contour field, or WebGL fluid canvas.
|
||||
4. Optional hairline structure as content dividers only, not as a page-wide background grid.
|
||||
5. Content layer.
|
||||
|
||||
Recommended CSS order:
|
||||
|
||||
```html
|
||||
<section class="poster magazine hero">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="ink-vignette"></div>
|
||||
<div class="content">...</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
```css
|
||||
.poster { position: relative; overflow: hidden; background: var(--paper); }
|
||||
.mag-bg { position:absolute; inset:0; width:100%; height:100%; z-index:0; opacity:.34; }
|
||||
.poster.hero .mag-bg { opacity:.62; }
|
||||
.grain {
|
||||
position:absolute; inset:0; z-index:1; pointer-events:none;
|
||||
opacity:.12; mix-blend-mode:multiply;
|
||||
background:
|
||||
linear-gradient(112deg, rgba(0,0,0,.035), transparent 26%, rgba(255,255,255,.16) 52%, transparent 82%),
|
||||
radial-gradient(circle at 18% 22%, rgba(var(--ink-rgb),.05), transparent 38%),
|
||||
radial-gradient(circle at 78% 84%, rgba(var(--accent-rgb),.045), transparent 42%);
|
||||
}
|
||||
.ink-vignette {
|
||||
position:absolute; inset:0; z-index:2; pointer-events:none;
|
||||
background:
|
||||
radial-gradient(circle at 18% 12%, rgba(var(--ink-rgb),.10), transparent 34%),
|
||||
radial-gradient(circle at 82% 80%, rgba(var(--accent-rgb),.10), transparent 38%);
|
||||
}
|
||||
.content { position:relative; z-index:3; }
|
||||
```
|
||||
|
||||
## When To Show WebGL
|
||||
|
||||
Use stronger visible atmosphere for:
|
||||
|
||||
- Cover.
|
||||
- Chapter/divider.
|
||||
- Pull quote.
|
||||
- Sparse thesis page.
|
||||
- Closing page.
|
||||
|
||||
Use subtle atmosphere for:
|
||||
|
||||
- Screenshot pages.
|
||||
- Dense ledgers.
|
||||
- Checklists.
|
||||
- Product evidence pages.
|
||||
|
||||
If screenshots are the main evidence, the background should support them rather than compete with them.
|
||||
|
||||
## WebGL Helper
|
||||
|
||||
The skill includes `assets/magazine-bg-webgl.js`, a small helper for a deterministic ink-flow background:
|
||||
|
||||
```html
|
||||
<canvas class="mag-bg" data-seed="workbuddy"></canvas>
|
||||
<script src="assets/magazine-bg-webgl.js"></script>
|
||||
<script>
|
||||
document.querySelectorAll(".mag-bg").forEach((canvas, i) => {
|
||||
MagazineBg.mount(canvas, {
|
||||
ink: [26, 46, 31],
|
||||
paper: [245, 241, 232],
|
||||
accent: [46, 107, 79],
|
||||
strength: canvas.closest(".hero") ? 0.62 : 0.28,
|
||||
frozenTime: 2.4 + i * 0.37
|
||||
});
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
For screenshot exports, prefer `frozenTime` so repeated renders look stable.
|
||||
|
||||
## 2D Fallback
|
||||
|
||||
If WebGL fails, create a 2D canvas with:
|
||||
|
||||
- Large radial ink wash.
|
||||
- Several translucent contour arcs.
|
||||
- Soft paper noise or uneven ink wash.
|
||||
- Theme color at very low opacity.
|
||||
|
||||
The output should still feel like an editorial background, not a plain fill.
|
||||
|
||||
## Do Not
|
||||
|
||||
- Do not use bright gradients.
|
||||
- Do not use page-wide grid, dot-matrix, graph-paper, or drafting-paper backgrounds.
|
||||
- Do not use decorative blobs or circles with no relationship to the layout.
|
||||
- Do not place strong background marks behind body text.
|
||||
- Do not let WebGL obscure screenshots or small captions.
|
||||
- Do not animate the final image sequence unless the task is video.
|
||||
@@ -0,0 +1,232 @@
|
||||
# Category Cookbook
|
||||
|
||||
Per-category cheat sheet for the 11 most common Rednote (小红书) content types. Each entry maps a category to:
|
||||
|
||||
- **What we can do** — concrete poster types this skill produces well.
|
||||
- **Style mode** — which side of the system (Editorial / Swiss) fits.
|
||||
- **Recipes** — which layout IDs (M01-M15 / S01-S12) are first reach.
|
||||
- **Text scheme** — how text relates to image (text-on-image / text-beside-image / text-only).
|
||||
- **Image source** — where the photos come from.
|
||||
- **Common pitfalls** — the way this category breaks.
|
||||
|
||||
This is a routing document. When the user names a category, find the row here and start from the listed recipes instead of building from a blank file.
|
||||
|
||||
For any category, if a poster has a full-bleed image with text on top, also follow `image-overlay.md` (mask + subject avoidance).
|
||||
|
||||
---
|
||||
|
||||
## 旅行 · Travel
|
||||
|
||||
**Strongest fit.**
|
||||
|
||||
- **Recipes**: M01 (text-led cover, no photo dominance) **or M16 (image-led cover, when the user has 1+ great photos)**, M02 (field-note photo), M11 (marginalia essay), M07 (closing note), S11 (itinerary ledger). For image-heavy submissions use the M16 → S11/M05 → M02 sequence in `references/content-planning.md`.
|
||||
- **Style mode**: Editorial × kraft-paper / dune (warm-tone destinations) or × forest-ink (mountain/wilderness). Swiss × IKB works for "trip data report" style.
|
||||
- **Text scheme**: Text beside image is the default. Cover uses text-on-image with a vertical falloff mask. Body pages use photo + caption pairs (field-note style).
|
||||
- **Image source**: User photos > Pexels (for China destinations — supports Chinese keyword search) > Unsplash (`/s/photos/<destination>`, best for overseas / English keywords) > Flickr CC (`license=2,3,4,5,6,9`, when you need documentary "real trip" feel rather than postcard polish). Always log to `assets/SOURCES.md`.
|
||||
- **Content shape**: 5-7 pages. Cover (destination + dates) → atmosphere photo + lead → itinerary ledger → 2-3 field notes (one location each) → closing quote / next-stop teaser.
|
||||
- **Pitfalls**: Generic "best places in X city" listicle voice. Cure: keep one specific date / weather / mileage detail per page to anchor it as observed, not researched.
|
||||
|
||||
See: `local-tests/demo-image-01-yading/` for a reference build.
|
||||
|
||||
---
|
||||
|
||||
## 职场 · Workplace
|
||||
|
||||
**Strongest fit.** This is what Swiss-International was made for.
|
||||
|
||||
- **Recipes**: S01 (cover), S02 (comparison), S05 (warning rows), S06 (pipeline), S07 (takeaway ledger), S09 (KPI tower), S11 (stacked ledger), S12 (matrix + hero stat).
|
||||
- **Style mode**: Swiss × IKB Blue or × Safety Orange. Avoid lemon-yellow / lemon-green for serious workplace content; they read as marketing.
|
||||
- **Text scheme**: Text-only or text-with-diagram. Almost never text-on-photo (workplace photos read as stock).
|
||||
- **Image source**: Avoid stock business photos. If you need an image, prefer a diagram, a screenshot of a real artifact (Notion, Linear, Figma), or omit. Generated images rarely add value here.
|
||||
- **Content shape**: 5-9 pages. Cover question / claim → context KPI → 3-5 numbered insights as ledger → one comparison or pipeline diagram → takeaway.
|
||||
- **Pitfalls**:
|
||||
1. **Listicle voice** ("8 个让你..."). Cure: rewrite as a numbered argument, not numbered tips. Each row makes a falsifiable claim, not a platitude.
|
||||
2. **Cheap "advice" energy** — soft language ("一定要", "千万别"). Cure: replace with observed action verbs and a number.
|
||||
3. **Stock-photo seasoning** — handshake, laptop-with-coffee. Cure: omit, or use a small Lucide icon glyph instead.
|
||||
|
||||
---
|
||||
|
||||
## 游戏 · Game
|
||||
|
||||
**Strong fit** for journals, recap, build/strat lists. **Has image-rights risk** that the user must accept.
|
||||
|
||||
- **Recipes**: M01 (cover with full-bleed art), M08 (boss tier ledger), S07 (takeaway ledger), S11 (chapter timeline), M15 (build before/after).
|
||||
- **Style mode**: Editorial dark (ink-classic with paper inverted to near-black) for atmospheric games (黑神话 / Elden Ring). Swiss for esports / competitive data ("胜率 / KDA / 出装").
|
||||
- **Text scheme**: Text-on-image is standard for game covers because game art is the primary draw. Mask is mandatory (see `image-overlay.md` Rule 1A vertical falloff).
|
||||
- **Image source**: Wallhaven JSON API (see SKILL.md Step 6) for keyword pulls, official screenshots for specific moments. Always disclose copyright risk and log to `SOURCES.md`. If user opts out of attribution, do not crop the credit out of the image itself.
|
||||
- **Content shape**: 4-6 pages. Cover (game name + playtime) → first impression page → chapter-by-chapter ledger → memorable boss / scene page → verdict.
|
||||
- **Pitfalls**:
|
||||
1. **Score-card seriousness** (8.5/10 in a giant block). We're not IGN — keep the verdict as one short clause, not a number.
|
||||
2. **Generic fan-art covers** with the game logo retraced — looks counterfeit. Prefer key art the publisher already released.
|
||||
|
||||
See: `local-tests/demo-image-02-wukong/` for a reference build.
|
||||
|
||||
---
|
||||
|
||||
## 影视 · Film & TV
|
||||
|
||||
**Strong fit** for reviews, scene analysis, quote cards. **Image-rights risk**, same as Game.
|
||||
|
||||
- **Recipes**: M04 (pull quote — for memorable lines), M10 (evidence feature — for scene analysis), M11 (marginalia essay), S02 (two signals — for comparison reviews), S12 (matrix — for film weeklies).
|
||||
- **Style mode**: Editorial × ink-classic or × indigo-porcelain. Letterboxd visual vocabulary fits Editorial naturally — serif title, italic original-language subtitle, monospace metadata.
|
||||
- **Text scheme**: Text-beside-image for review cards (poster on left, take on right). Text-on-image only for atmospheric "what this film made me feel" quote pages.
|
||||
- **Image source**: Official posters / stills. Do not generate fake stills — they look immediately wrong.
|
||||
- **Content shape**: For single film: cover (title + year + 1-line take) → 1-2 scene captures → director-quote / theme pullquote → verdict ledger. For weekly: matrix of 6-9 films + one hero recommendation.
|
||||
- **Pitfalls**:
|
||||
1. **Fake film-festival typography** — adding fake awards badges. Don't.
|
||||
2. **Spoiler in title without warning.** If a cover gives away the ending, mark `剧透` in the kicker.
|
||||
|
||||
---
|
||||
|
||||
## 美食 · Food
|
||||
|
||||
**Split fit.** Recipes work. Food-photo showcase does not.
|
||||
|
||||
### What works: recipes & food essays
|
||||
|
||||
- **Recipes**: M16 (image-led cover when finished-dish photo is hero-worthy) → S11 (ingredient/price ledger) → M14 (cooking steps pipeline) → M02 (extra dish detail). Also M05 (checklist for shopping list).
|
||||
- **Style mode**: Editorial × kraft-paper feels like a cookbook. Swiss × Lemon Yellow / Safety Orange works for "cost-per-serving" data posts.
|
||||
- **Text scheme**: Text-with-image. The finished-dish photo is one frame; everything else is text/data.
|
||||
- **Image source**: User photos of finished dish are best. For 中式菜品 / 国内餐厅 scenes, try Pexels first (Chinese keyword search hits 国内场景 better than Unsplash). Unsplash food photos read as Western stock; use sparingly.
|
||||
- **Content shape**: 5-7 pages. Cover (dish name + one verdict line) → ingredients ledger → numbered steps pipeline → finished-dish photo page → tips / variation marginalia.
|
||||
|
||||
### What does not work: food-photo showcase / restaurant reviews requiring drool-shot art direction
|
||||
|
||||
- We don't shoot food, and stock food photos kill the "I cooked this" trust signal.
|
||||
- For restaurant posts, require user-shot photos at the table. If they don't have them, push back — a stock-photo restaurant post is filler.
|
||||
- For "look at this cake" pure-display posts, refer the user to a photography-focused workflow, not this skill.
|
||||
|
||||
**Pitfalls**:
|
||||
1. **Excited recipe voice** ("超绝!!!"). Editorial doesn't shout — let the dish do the talking.
|
||||
2. **Calorie-shaming asides** in casual recipes. Drop them.
|
||||
|
||||
---
|
||||
|
||||
## 彩妆 · Makeup
|
||||
|
||||
**Split fit.** Tutorials and product reviews work. Selfie-driven "look" posts need user images we can't generate.
|
||||
|
||||
### What works
|
||||
|
||||
- **Recipes**: M14 (tutorial step pipeline), S12 (product matrix), S11 (空瓶 / 复购 ledger), S02 (色号对比).
|
||||
- **Style mode**: Swiss × Lemon Yellow / Lemon Green / Safety Orange for bright product reviews. Editorial × indigo-porcelain for editorial-feel beauty essays.
|
||||
- **Text scheme**: Text-with-image. Each step gets a small hand/face crop + a one-sentence instruction.
|
||||
- **Image source**: User photos. Stock makeup photos have legal grey areas and look generic.
|
||||
- **Content shape**: Tutorial — cover (look name + occasion) → tools/products ledger → 5-7 numbered step pipeline → finish photo → tips marginalia.
|
||||
|
||||
### What does not work
|
||||
|
||||
- "Get-the-look" posts that rely on a recognizable model face. We can't generate those reliably; user must supply.
|
||||
- Trending Y2K / 哥特 / dolly aesthetic decoration — outside the Swiss/Editorial system.
|
||||
|
||||
**Pitfalls**:
|
||||
1. **Color-swatch inaccuracy** if you eyeball CSS hex from a photo. Always ask the user for the official shade name + hex from the brand.
|
||||
2. **Skin-tone homogenization** when scaling photos — preserve user-supplied photos at native ratio.
|
||||
|
||||
---
|
||||
|
||||
## 健身 · Fitness
|
||||
|
||||
**Half fit.** Training plans and nutrition data work. Progress photos need user.
|
||||
|
||||
- **Recipes**: M14 (workout pipeline), S11 (set/rep ledger), S09 (KPI tower for weekly volume), M15 (before/after — needs user photos).
|
||||
- **Style mode**: Swiss × Safety Orange / Lemon Green for energetic training posts. Editorial × forest-ink for "mindful movement / 山系跑步" essays.
|
||||
- **Text scheme**: Mostly text-with-data. Progress posts text-beside-image.
|
||||
- **Image source**: User progress photos (mandatory for before/after). For ambient illustrations, generated gym/outdoor shots are fine.
|
||||
- **Content shape**: Training plan — cover (cycle name + duration) → weekly schedule ledger → per-day pipeline of exercises → recovery / nutrition note → closing data.
|
||||
- **Pitfalls**:
|
||||
1. **Fake aspirational numbers** (50 kg 卧推 8 周从 0 起步). Don't.
|
||||
2. **Body-shaming subtext** in before/after captions. Use neutral language.
|
||||
|
||||
---
|
||||
|
||||
## 家居 · Home & Living
|
||||
|
||||
**Half fit.** Item recommendations, before/after, and floorplan analysis work. Pure interior-design photo posts need user photos.
|
||||
|
||||
- **Recipes**: M16 (image-led cover when user has a strong room photo) → S11 (item ledger with price) → M02 (detail crops). Also M15 (before/after — needs paired user photos), M11 (marginalia for floorplan annotation), M03 (essay-style decor manifesto).
|
||||
- **Style mode**: Editorial × kraft-paper / dune for warm rustic homes. Editorial × indigo-porcelain for cool modern. Swiss × IKB for "rental hack data" posts.
|
||||
- **Text scheme**: Item recommendations are text-beside-image (small product crop + name + price + reason). Before/after is two photos with mid-page divider.
|
||||
- **Image source**: User interior photos. Web-sourced interior images have heavy copyright exposure (Pinterest creators are vigilant) — avoid unless user explicitly authorizes.
|
||||
- **Content shape**: Item rec — cover (room + budget) → 4-6 item rows ledger → 1 hero detail crop → closing tip.
|
||||
- **Pitfalls**:
|
||||
1. **Pinterest-aesthetic stock** that the user can't actually reproduce. Stick to what they live in.
|
||||
2. **Price drift** — products move quickly. Don't quote a price more than 90 days old without re-checking.
|
||||
|
||||
---
|
||||
|
||||
## 穿搭 · Outfit / Fashion
|
||||
|
||||
**Weak fit.** Mood-board essays and product reviews work; OOTD full-body shots are outside our scope.
|
||||
|
||||
### What works
|
||||
|
||||
- **Recipes**: M11 (marginalia essay — "this week I wore"), S12 (item matrix), M04 (style manifesto pull-quote), S11 (capsule wardrobe ledger).
|
||||
- **Style mode**: Editorial × ink-classic / indigo-porcelain for editorial-feel essays. Swiss × Lemon Yellow / Safety Orange for capsule-wardrobe data posts.
|
||||
- **Text scheme**: Text-beside-image — small item crops as evidence, one full-body hero only if user provides.
|
||||
- **Image source**: User OOTD photos (we don't generate body shots). For mood-board context, web-sourced flat-lay or product photos are okay with disclosure.
|
||||
- **Content shape**: Capsule guide — cover (season + count) → wardrobe ledger → 1-2 outfit demonstrations → care/styling marginalia.
|
||||
|
||||
### What does not work
|
||||
|
||||
- Daily OOTD posts. The skill cannot generate or solicit body photography.
|
||||
- High-styling editorial fashion shoots — requires real photography production.
|
||||
|
||||
**Pitfalls**:
|
||||
1. **Brand-and-price-tag overload** turning every poster into an ad. Limit to 6 named items max.
|
||||
2. **Generic "minimalist 25 件夏季基础款" listicle**. Cure: anchor to a specific climate / lifestyle constraint.
|
||||
|
||||
---
|
||||
|
||||
## 情感 · Emotion / Personal Essay
|
||||
|
||||
**Weak fit.** Essay-with-pullquote works. Dreamcore / 氛围感 aesthetic does not fit our system.
|
||||
|
||||
### What works
|
||||
|
||||
- **Recipes**: M04 (pull quote / thesis), M09 (atmospheric thesis), M11 (marginalia essay), M13 (hero question — for rhetorical-question covers), M07 (closing note).
|
||||
- **Style mode**: Editorial × ink-classic or × dune. Magazine pace with restraint.
|
||||
- **Text scheme**: Mostly text-only with one quiet supporting image. The text is the content.
|
||||
- **Image source**: Quiet documentary-style photo (a window, a chair, a hand) — user-supplied is best. If sourcing: **Flickr CC** (`license=2,3,4,5,6,9`) is the strongest match — real interiors, real hands, real moments without stock polish. Pexels for China-context scenes (Chinese keyword search). Unsplash works but skews styled; avoid the "moodcore" gradient-light stock entirely.
|
||||
- **Content shape**: 3-5 pages. Cover question → essay split (M03) or atmospheric thesis → pull quote → closing note. Resist over-stretching to 9 pages.
|
||||
|
||||
### What does not work
|
||||
|
||||
- "梦核 / 氛围感" with soft fluorescent gradients, glowing ovals, hazy lights. Our anti-pattern list explicitly bans those decorations.
|
||||
- Y2K / 早期网络回忆 / 千禧辣妹 aesthetic — outside Swiss and Editorial both.
|
||||
- Heavy emoji / kaomoji captions. We use no emoji.
|
||||
|
||||
**Pitfalls**:
|
||||
1. **Inspirational generic copy** ("愿你...愿我..."). Editorial demands specifics — name the day, the weather, the person.
|
||||
2. **Pretty empty space** — page after page of one pullquote on paper. Risk: reads as filler. Mix with one M02 field photo or M11 marginalia to ground it.
|
||||
|
||||
---
|
||||
|
||||
## 推荐 · Recommended / Mixed
|
||||
|
||||
**Default channel.** This category is the catch-all on the platform; the actual content underneath is always one of the above 10.
|
||||
|
||||
When the user says 推荐 without specifying, ask which underlying type before designing. If they can't say, default to:
|
||||
|
||||
- Swiss × IKB for "I tested 5 products" → S12 matrix + S11 ledger.
|
||||
- Editorial × kraft-paper for "this week's reading / watching" → M02 field notes.
|
||||
|
||||
---
|
||||
|
||||
## Capability Circle Summary
|
||||
|
||||
Categories where this skill produces strong work end-to-end (text + structure + image story all from us):
|
||||
|
||||
- 旅行 · 职场 · 推荐 (with subtype)
|
||||
|
||||
Categories where the skill is strong on text/structure but needs user photos for image story:
|
||||
|
||||
- 游戏 · 影视 · 美食(食谱) · 彩妆(教程) · 健身 · 家居 · 穿搭(精选)
|
||||
|
||||
Categories that are outside scope (skill cannot reliably produce):
|
||||
|
||||
- 美食(菜品大片摆盘) · 穿搭(日常 OOTD 全身) · 情感(梦核 / 氛围感装饰风)
|
||||
- Any post requiring high-saturation Y2K / 千禧辣妹 / dolly / kawaii decoration vocabulary
|
||||
- Pure photography showcase posts where the image is the entire product
|
||||
|
||||
Be explicit with the user when their request lands in the "outside scope" bucket. Do not promise a result the system was not designed to make.
|
||||
@@ -0,0 +1,285 @@
|
||||
# Components
|
||||
|
||||
Shared component spec for both seed templates. Read this when you need to look up a class, a font size, or a hard rule that recurs across recipes. Per-recipe details live in `layout-recipes.md`; per-theme color tokens live in `theme-presets.md`.
|
||||
|
||||
## Font Stacks
|
||||
|
||||
Editorial Magazine x E-ink (`template-editorial-card.html`):
|
||||
|
||||
- `--serif-zh`: Noto Serif SC, Songti SC, STSong — display titles.
|
||||
- `--serif-en`: Playfair Display, italic for subtitles and pull quotes.
|
||||
- `--sans-zh`: Noto Sans SC, PingFang SC — body and lead.
|
||||
- `--sans-en`: Inter — Latin body in mixed content.
|
||||
- `--mono`: IBM Plex Mono — labels, page metadata, issue strip, captions.
|
||||
|
||||
Swiss International (`template-swiss-card.html`):
|
||||
|
||||
- `--sans`: Inter, Helvetica Neue, Helvetica.
|
||||
- `--sans-zh`: Noto Sans SC, PingFang SC — Chinese body.
|
||||
- `--mono`: IBM Plex Mono — labels, captions, t-meta.
|
||||
|
||||
Never load a serif font in the Swiss template. Never let the Editorial template lose its serif display family.
|
||||
|
||||
## Type Scale + Weight Mapping
|
||||
|
||||
Both templates follow the rule **"the larger, the lighter."** Small text always uses heavier weight than large text. On 1080x1440 boards, the minimum readable size is 22-28px after factoring in mobile downsample.
|
||||
|
||||
Editorial scale (default for 3:4):
|
||||
|
||||
| Role | Class | Size | Weight | Tracking | Family |
|
||||
| ----------- | ----------- | ----- | ------ | -------- | --------- |
|
||||
| Display | `.h-display`| 124px | 500 | +.04em | serif-zh |
|
||||
| Section ttl | `.h-xl` | 88px | 500 | +.03em | serif-zh |
|
||||
| Mid title | `.h-md` | 56px | 500 | +.02em | serif-zh |
|
||||
| Subtitle | `.h-sub` | 36px | 400 it | normal | serif-en |
|
||||
| Pull quote | `.pullquote`| 64px | 500 it | normal | serif-zh |
|
||||
| Lead | `.lead` | 28px | 400 | normal | **serif-zh** |
|
||||
| Body | `.body` | 24px | 400 | normal | **serif-zh** |
|
||||
| Kicker | `.kicker` | 21px | 500 | +.22em | mono |
|
||||
| Meta | `.meta` | 18px | 500 | +.20em | mono |
|
||||
| Label | `.label` | 18px | 500 | +.20em | mono |
|
||||
|
||||
> **Restored 2026-05-27.** The previous defaults (900 / 700 / 700 / sans body / `−.01em`) made Editorial cards read as heavy infographic banners. They are NOT the Guizang showcase aesthetic — see `local-tests/demo-showcase/editorial.html` for the source-of-truth. The rule is restrained typography: light weights, **serif body italic-tolerant**, **wide tracking** on display + mono. Heaviness in Editorial = visual demotion to "generic landing-page", same trap as Swiss.
|
||||
|
||||
Swiss scale (default for 3:4):
|
||||
|
||||
| Role | Class | Size | Weight | Family |
|
||||
| ----------- | ------------- | ----- | ------ | --------- |
|
||||
| Hero | `.h-hero` | 240px | 200 | sans |
|
||||
| Statement | `.h-statement`| 180px | 200 | sans |
|
||||
| Section ttl | `.h-xl` | 120px | 300 | sans |
|
||||
| Mid title | `.h-md` | 56px | 400 | sans |
|
||||
| Mega number | `.num-mega` | 200px | 200 | sans |
|
||||
| XL number | `.num-xl` | 144px | 200 | sans |
|
||||
| Lead | `.lead` | 30px | 400 | sans-zh |
|
||||
| Body | `.body` | 26px | 400 | sans-zh |
|
||||
| Category | `.t-cat` | 22px | 600 | sans |
|
||||
| Meta | `.t-meta` | 20px | 500 | mono |
|
||||
| Caption | `.swiss-img-caption` | 18px | 500 | mono |
|
||||
|
||||
Both templates auto-shrink display sizes inside `.poster.square` and `.poster.wide`. You usually do not override them. Override only when a single title cannot be shortened further.
|
||||
|
||||
### Chinese Title Length Bands
|
||||
|
||||
Chinese characters are visually denser than Latin. Pick a band before sizing:
|
||||
|
||||
| Title shape | Editorial display | Swiss h-hero |
|
||||
| ------------------------------------------ | ----------------- | ------------ |
|
||||
| 1 line, <= 6 Chinese chars | 132px (default) | 240px (default) |
|
||||
| 1 line, 7-10 chars | 108px | 200px |
|
||||
| 2 lines, each <= 8 chars | 96px | 180px |
|
||||
| 2 lines, any line 9-12 chars | 84px | 152px |
|
||||
| 3 lines (rare) | 72px | 132px |
|
||||
|
||||
If the title still does not fit, **shorten the copy first**. Never solve overflow by shrinking body text below the minimum readable size.
|
||||
|
||||
### Swiss `.h-xl` — Hard Caps per Board (validated)
|
||||
|
||||
The seed template ships these caps. Anything more violates the vertical budget — verified empirically in `local-tests/smoke-ai-tools/`:
|
||||
|
||||
| Board | Default `.h-xl` | Max lines | Max chars / line | What happens past the cap |
|
||||
| -------------------- | --------------- | --------- | ---------------- | ------------------------------------------------------------------ |
|
||||
| `.poster.xhs` (1080×1440) | 96px | 2 | 8 | 3-line title pushes ledger/matrix past 1440 — push content off-canvas |
|
||||
| `.poster.square` (1080×1080) | 88px | 2 | 7 | Bottom card or metadata strip clips |
|
||||
| `.poster.wide` (2100×900) | 104px | 1 | 14 | Wraps to 2 lines and crowds the right column |
|
||||
|
||||
**If your title needs 3 Chinese lines on `.poster.xhs`:** switch the recipe from S03/S10/S12 (data-heavy) to S01/S05 (cover-style) where the title can dominate. Don't shrink `.h-xl` below 80px — small + heavy reads as Web1.0.
|
||||
|
||||
### Editorial `.h-xl` — Hard Caps per Board (validated)
|
||||
|
||||
The Editorial seed default for `.h-xl` is 92px serif weight 700. Verified in `local-tests/demo-smoke-editorial-travel/` on M11/M14/M07 with 3-paragraph body + ledger + 5-step pipeline:
|
||||
|
||||
| Board | Default `.h-xl` | Max lines | Max chars / line | What happens past the cap |
|
||||
| -------------------- | --------------- | --------- | ---------------- | ------------------------------------------------------------------------- |
|
||||
| `.poster.xhs` (1080×1440) | 92px | 2 | 9 | 3 lines push the marginalia / ledger / pipeline rows past the issue strip |
|
||||
| `.poster.square` (1080×1080) | 78px | 2 | 8 | Sub-paragraph or pull-quote clips |
|
||||
| `.poster.wide` (2100×900) | 96px | 1 | 16 | Wraps and crowds the marginalia column |
|
||||
|
||||
The smoke deck's p2 title `第三次进山,装备比上一次轻 3.4kg` is the 2-line × 9-char limit and worked. The `<br>` was load-bearing — let CJK auto-wrap freely on `.h-xl` and you get awkward breaks. Hard-break manually at semantic seams.
|
||||
|
||||
**Per-recipe nuance:**
|
||||
- M11 (Marginalia Essay): 2-line title leaves room for **3 paragraphs of 3-4 sentences each** in a 700px main column, and 5-7 marginalia rows in a 220px aside.
|
||||
- M14 (Vertical Pipeline): 2-line title + **5 steps** (each step-title 42px serif + step-desc 26px sans, 28px gap) hits the 1440 floor exactly — adding a 6th step requires shrinking title to 1 line.
|
||||
- M07 (Field Ledger): 2-line title + **5 ledger rows** with both `.ledger-title` and `.ledger-note` ≈ 100-120px row height — exactly fills. 6 rows requires 1-line title.
|
||||
|
||||
### Matrix + hero-stat-bottom on `.poster.xhs`
|
||||
|
||||
`.matrix-fill` with `grid-auto-rows: min-content` is the safe default on `xhs`. Hard limits:
|
||||
|
||||
| Cells | Rows | Pair with hero-stat-bottom? | Notes |
|
||||
| ----- | ---- | --------------------------- | ------------------------------------------------- |
|
||||
| 4 | 2 | Yes — comfortable | Cells get 200+ px each |
|
||||
| 6 | 3 | Yes — recommended | The sweet spot |
|
||||
| 8 | 4 | Only with shortened title + `num-mega` 110-128px | Compressed; do not also use 3-line title |
|
||||
| 10+ | 5+ | **No** | Use S10 H-Bar Chart instead — that pattern scales |
|
||||
|
||||
## Minimum Readable Sizes (mobile-safe)
|
||||
|
||||
A 1080x1440 PNG is usually viewed on a phone at 360-420 logical pixels wide. Anything below the listed size becomes unreadable:
|
||||
|
||||
| Role | Minimum | Notes |
|
||||
| ------------------- | ------- | ---------------------------------------- |
|
||||
| Body / paragraph | 28px | Editorial, Swiss alike |
|
||||
| Lead | 30px | The "1.5x body" guard |
|
||||
| Caption / kicker | 20px | Do not drop below 18px |
|
||||
| Label / meta strip | 20px | Mono only |
|
||||
| Cell title in grids | 24px | Matrix / brief cards |
|
||||
| Number annotation | 22px | Stat-card .lbl, ledger .sub |
|
||||
|
||||
If you cannot fit the copy, cut the copy. Do not shrink type.
|
||||
|
||||
## Card Fills — Swiss Only, Mutually Exclusive
|
||||
|
||||
Four card classes exist; **never combine them on the same node:**
|
||||
|
||||
- `.card-ink` — solid black ink, paper text. Use for one statement card.
|
||||
- `.card-accent` — accent fill, accent-on text. Use sparingly; max one accent card per poster.
|
||||
- `.card-fill` — grey-1 fill, ink text. The workhorse for matrix / brief / takeaway grids.
|
||||
- `.card-outlined` — transparent + 1px grey-2 border, ink text. Use when you need a card without weight.
|
||||
|
||||
Multi-card grids must use **the same** card class for every cell, except a single accent highlight is allowed when one item is meant to stand out. Mixing `card-fill` with `card-outlined` in the same grid looks like sloppy templating.
|
||||
|
||||
The Editorial template intentionally does not provide card classes. Editorial layouts express hierarchy through type, rules, ledger rows, and column structure — not card backgrounds. If you find yourself wanting a card on an Editorial poster, you probably picked the wrong style mode.
|
||||
|
||||
## Image Containers
|
||||
|
||||
Both templates share the same `.frame-img` system. Always pick a standard ratio class. Never write `aspect-ratio: 2592/1798` style ad-hoc ratios.
|
||||
|
||||
| Class | Ratio | Use |
|
||||
| ----------- | ------ | -------------------------------------------------- |
|
||||
| `.r-3x4` | 3 : 4 | Default for portrait covers and field-note photos. |
|
||||
| `.r-1x1` | 1 : 1 | Square portraits, product objects, balanced grids. |
|
||||
| `.r-4x3` | 4 : 3 | Classic editorial photo, full-bleed top zone. |
|
||||
| `.r-3x2` | 3 : 2 | Magazine inline figure. |
|
||||
| `.r-16x9` | 16 : 9 | Landscape photo, infographic. |
|
||||
| `.r-16x10` | 16 : 10| Default for left-text + right-image splits. |
|
||||
| `.r-21x9` | 21 : 9 | WeChat 21:9 hero image, S08 Image Hero top zone. |
|
||||
|
||||
Default `object-fit: cover` keeps `object-position: center 50%` (both templates). Use `.fit-contain` for UI screenshots, dense text, code, and infographics. Do not crop faces or product key features.
|
||||
|
||||
**Subject-aware cropping — always set `object-position` inline per photo.** The template default is a fallback, not a recommendation. Before each `<img>`, look at the source and ask: where is the subject? Then set `style="object-position:center N%"` on the `<img>` directly:
|
||||
|
||||
| Subject location in source | Inline value |
|
||||
| ------------------------------------- | ------------------------ |
|
||||
| Subject near top (sky-heavy landscape, face at top) | `center 25-35%` |
|
||||
| Subject centered (default) | `center 50%` (omit, it's the default) |
|
||||
| Subject mid-body (hiker, hands, mid-frame) | `center 55-65%` |
|
||||
| Subject low (foreground gear, ledger, foot of frame) | `center 70-80%` |
|
||||
|
||||
The default `center 50%` will silently crop subjects out of frame on tall ratios (`r-3x4`, `r-21x9`). Every photo in a delivered package needs a deliberate `object-position` — even if the conclusion is "50% is fine here." Catch this in the render-check pass: if the subject is more than 1/3 outside the visible crop, fix it before delivering.
|
||||
|
||||
**Caption class name (don't get this wrong):**
|
||||
- Editorial template: `.img-cap` — 18px mono, applied to `<figcaption>` under `.frame-img`. Writing `.cap` falls back to browser-default 16px and trips R4.
|
||||
- Swiss template: `.swiss-img-caption` — same role, 18px mono.
|
||||
|
||||
There is no shared `.cap` class. If you see `.cap` in a draft, fix it before render.
|
||||
|
||||
## Screenshot Containers (.frame-shot)
|
||||
|
||||
For UI screenshots / web captures / code shots, use `.frame-shot` (both seeds carry it). It defaults to `object-fit: contain` so the source pixels stay pristine — the opposite of `.frame-img`. See `references/screenshot-treatment.md` for the full parameter matrix.
|
||||
|
||||
Quick summary of style-locked defaults (don't second-guess these):
|
||||
|
||||
| Style | Corners | Shadow | Default bg | Default inset |
|
||||
| --------- | ------------ | ------------ | ------------ | ------------- |
|
||||
| Swiss | `corners-sq` | `shadow-none`| `bg-grey-1` | `inset-sub` |
|
||||
| Editorial | `corners-sm` | `shadow-soft`| `bg-paper-2` | `inset-sub` |
|
||||
|
||||
Two device wrappers (`.device-browser`, `.device-phone`) ship in both templates and provide CSS-only browser chrome / phone bezel — no SVG, no image deps. Wrap one `.frame-shot` per chrome.
|
||||
|
||||
## Map Block (.map-block)
|
||||
|
||||
For content with spatial relationships (routes, neighborhoods, store locations). Both seeds ship `.map-block` + `.map-pin` + `.map-legend`. Three modes — see `references/map-component.md` for the full playbook:
|
||||
|
||||
- **Mode S** (default) — schematic SVG drawn in `viewBox="0 0 100 100"`, no token, hand-illustrated feel.
|
||||
- **Mode T** — Mapbox Static Images API URL as `<img>` source; needs `MAPBOX_ACCESS_TOKEN`. Apply `tone-paper` (Editorial) or `tone-paper` saturation-0 (Swiss).
|
||||
- **Mode O** — OSM tile composite, fallback when no token.
|
||||
|
||||
Hard limits: ≤6 pins per board, ≤1 accent pin, no SVG text labels (names go in `.map-pin .card`).
|
||||
|
||||
## Spacing Tokens (Swiss only)
|
||||
|
||||
Swiss template exposes a Carbon-style 2x scale. Stick to these tokens — arbitrary `px` margins drift fast across posters.
|
||||
|
||||
| Token | Value | Typical use |
|
||||
| ------- | ------ | ---------------------------------------------------- |
|
||||
| `--sp-3`| 8px | Tight chip gap, inline meta spacing. |
|
||||
| `--sp-4`| 12px | Card inner gap, dense list rows. |
|
||||
| `--sp-5`| 16px | Body block bottom margin, lead-to-paragraph. |
|
||||
| `--sp-6`| 24px | Card padding (compact), grid gap (tight). |
|
||||
| `--sp-7`| 32px | Default grid gap. |
|
||||
| `--sp-8`| 40px | Card padding (default), section gap (compact). |
|
||||
| `--sp-9`| 48px | Section gap (default), pair-preview outer padding. |
|
||||
| `--sp-10`| 64px | Major break between content blocks on portrait. |
|
||||
| `--sp-11`| 80px | Poster outer padding (square / wide). |
|
||||
| `--sp-12`| 96px | Poster outer padding (portrait). |
|
||||
| `--sp-13`| 160px | Wide poster horizontal padding only. |
|
||||
|
||||
Editorial template uses bare `px` for now because magazine layouts often want bespoke spacing for atmosphere. If you find a pattern that recurs, add an editorial token here.
|
||||
|
||||
## Icons
|
||||
|
||||
Default icon library is **Lucide** (loaded only by the Swiss template). Editorial layouts rarely need icons; when they do, use the same Lucide set, but limit to one or two per poster.
|
||||
|
||||
Rules:
|
||||
|
||||
- No emoji anywhere. Emojis ruin both styles.
|
||||
- Use angular Lucide icons (`arrow-right`, `check`, `triangle-alert`, `dot`, `plus`, `equal`, `slash`). Avoid pillow-rounded icons (`smile`, `heart-filled`) — they fight Swiss geometry.
|
||||
- Icon stroke weight: 1.5 (Lucide default). Do not thicken.
|
||||
- Size: 56px for ledger row indicators, 32px inline with body, 24px in chips. Never below 20px.
|
||||
- Color: `var(--accent)` for highlight, `var(--grey-3)` for neutral, `var(--ink)` for primary. Never gradient.
|
||||
|
||||
To add an icon:
|
||||
|
||||
```html
|
||||
<i data-lucide="arrow-right" width="32" height="32"></i>
|
||||
```
|
||||
|
||||
The Swiss template runs `lucide.createIcons()` on load. If you inject icons after load, call it again manually.
|
||||
|
||||
## Issue Label and Corner Metadata
|
||||
|
||||
Social cards do not have PPT's chrome/foot dual-row metadata. They use a single, quiet element instead.
|
||||
|
||||
Editorial issue elements:
|
||||
|
||||
- `.issue-row` — top: "Vol. 01 · 2026.05" with a small accent dot between segments.
|
||||
- `.issue-strip` — bottom band: 3-5 short labels separated by em-dashes, above a hairline.
|
||||
|
||||
Swiss issue elements:
|
||||
|
||||
- `.chrome-min` — top single row with category on left, date/issue on right, bottom hairline.
|
||||
- `.t-meta` — inline mono uppercase metadata anywhere on the poster.
|
||||
|
||||
One issue element per poster. Never both top issue strip and bottom issue strip on the same poster — it looks like decoration.
|
||||
|
||||
## Layout Primitives
|
||||
|
||||
Both templates share the same primitives (different default gaps).
|
||||
|
||||
| Class | Editorial gap | Swiss gap | Use |
|
||||
| ---------------- | --------------- | --------------- | ------------------------------------ |
|
||||
| `.stack` | flex column | flex column | Default vertical flow. |
|
||||
| `.row` | flex row | flex row | Horizontal flow. |
|
||||
| `.gap-1`...`-5` | 12-64px | 8-16px | Editorial gaps (px) vs Swiss (token).|
|
||||
| `.gap-6`...`-10` | n/a | 24-64px | Swiss only — Carbon scale. |
|
||||
| `.col-2-7-5` | 7:5 split | n/a | Editorial only — quote + image. |
|
||||
| `.col-2-8-4` | 8:4 split | n/a | Editorial only — text-heavy + image. |
|
||||
| `.grid-12` | n/a | 12-col grid | Swiss only. |
|
||||
| `.span-N` | n/a | grid column span| Swiss only. |
|
||||
| `.grid-3` | 3 columns | 3 columns | Both. |
|
||||
|
||||
## Hard Rules (Shared)
|
||||
|
||||
These rules guard the visual identity. Violations are almost always wrong.
|
||||
|
||||
1. Pick exactly one style mode per package. Never mix Editorial and Swiss.
|
||||
2. Pick exactly one theme/accent per package. Never combine two palettes.
|
||||
3. No emojis, ever. Use Lucide or restrained type.
|
||||
4. No fake data, no fake percentages, no `Lorem` text in delivered output.
|
||||
5. No `border-radius`, `box-shadow`, or `linear-gradient` in Swiss.
|
||||
6. No flat one-color background in Editorial — paper grain + optional WebGL atmosphere is required on hero / quote / sparse pages.
|
||||
7. Every `.poster` must have stable export dimensions. Never use `vw` / `vh` in poster content.
|
||||
8. Every image must be wrapped in `.frame-img` with a standard ratio class.
|
||||
9. Multi-card grids use one card class. One accent card maximum.
|
||||
10. Honor the type scale and minimum sizes. Cut copy before shrinking type.
|
||||
@@ -0,0 +1,162 @@
|
||||
# Content Planning
|
||||
|
||||
## Compression Ladder
|
||||
|
||||
Start from the user's original text and compress in layers:
|
||||
|
||||
1. Core claim: one sentence.
|
||||
2. Viewer promise: what the reader gets from swiping.
|
||||
3. Section map: 4-8 ideas.
|
||||
4. Page hooks: short, concrete, not abstract.
|
||||
5. Body fragments: only the words needed to explain the visual.
|
||||
|
||||
Do not put the full article on images. The image set is a visual outline that makes the user want to read the caption/body.
|
||||
|
||||
## Rednote Page Plan Template
|
||||
|
||||
```text
|
||||
Title:
|
||||
Audience:
|
||||
Style:
|
||||
Image assets:
|
||||
|
||||
01 Cover
|
||||
- Hook:
|
||||
- Visual:
|
||||
- Bottom points:
|
||||
|
||||
02 Page
|
||||
- Point:
|
||||
- Copy:
|
||||
- Visual:
|
||||
- Layout:
|
||||
|
||||
...
|
||||
```
|
||||
|
||||
## Good Page Roles
|
||||
|
||||
Use varied roles instead of repeating the same card page:
|
||||
|
||||
- Hook cover.
|
||||
- Problem scene.
|
||||
- Misconception vs reality.
|
||||
- Checklist.
|
||||
- Comparison.
|
||||
- Product screenshot evidence.
|
||||
- One big quote or conclusion.
|
||||
- Step-by-step flow.
|
||||
- Gear list or buying guide.
|
||||
- Summary page with "remember these three".
|
||||
|
||||
## Copy Rules
|
||||
|
||||
- Titles should be plain and sharp.
|
||||
- Avoid abstract labels like "背景介绍" unless the page is actually context.
|
||||
- Use verbs and consequences: "高帮鞋会让脚更闷" is better than "鞋子选择".
|
||||
- For product updates, lead with the user-facing change, then add the feature name.
|
||||
- For outdoor posts, lead with the embodied problem: hot, wet, slippery, heavy, exposed, lost, cold.
|
||||
- For AI/tool posts, lead with workflow change: faster capture, less manual work, cross-app automation, editable output.
|
||||
|
||||
## Cover Hook Patterns
|
||||
|
||||
Use one of these:
|
||||
|
||||
- "终于有 Mac 版了"
|
||||
- "新手别急着买"
|
||||
- "这个功能真的改变用法"
|
||||
- "我替你踩过坑了"
|
||||
- "先看这 5 个点"
|
||||
- "不要被装备带着走"
|
||||
- "从此不用手动..."
|
||||
|
||||
Avoid:
|
||||
|
||||
- Overlong complete article titles.
|
||||
- Vague hype without a concrete object.
|
||||
- Multiple unrelated claims on one cover.
|
||||
|
||||
## WeChat Square Title Compression
|
||||
|
||||
When producing a WeChat `1:1` cover, derive a short title from the long `21:9` title.
|
||||
|
||||
Rules:
|
||||
|
||||
- Preserve the core object and the strongest action.
|
||||
- Use 4-10 Chinese characters when possible.
|
||||
- Use 2 short lines if one line becomes too cramped.
|
||||
- Remove explanations, clauses, and long modifiers.
|
||||
- Do not use the full long title in the square.
|
||||
|
||||
Examples:
|
||||
|
||||
```text
|
||||
开源了一个 Skill,让 AI 接管你屏幕边那张便签纸
|
||||
=> AI 接管便签纸
|
||||
```
|
||||
|
||||
```text
|
||||
Codex 史诗级更新,体验爆炸提升
|
||||
=> Codex 大更新
|
||||
```
|
||||
|
||||
## Image-Led Sequence (lifestyle, image-heavy content)
|
||||
|
||||
When the user has multiple good lifestyle photos (旅行 / 户外 / 自家成菜 / 家居 / 真实情感场景), front-load the strongest photo on page 1 and let pages 2-3 carry the text/data. Do not bury great photos.
|
||||
|
||||
Pattern:
|
||||
|
||||
```
|
||||
P1 M16 Image-Led Cover ← single best photo, full bleed, restrained title
|
||||
P2 S11 / M05 / M10 ← text-heavy: ledger / checklist / mini-data — eye rests
|
||||
P3 M02 Field-Note Photo ← second-best photo, in a frame, with caption
|
||||
P4-N M02 / M11 ← more field notes or marginalia essays
|
||||
P_last M07 / M04 ← closing note or pull quote
|
||||
```
|
||||
|
||||
Hard rule: **never two M16 in a row**. After a full-bleed cover the eye needs to settle on text before another big image. Two image-led covers back-to-back read as "we couldn't decide which photo to use."
|
||||
|
||||
When this pattern does NOT apply:
|
||||
|
||||
- News / tutorial / data / review posts — the cover is a hook line, not a photo. Use M01 or S01.
|
||||
- Posts with one good photo only — use M16 for P1, then M02 once on P3-4 with that same photo or a different angle. Do not pad.
|
||||
- Swiss-mode product/release posts — photos in Swiss are product renders or UI screenshots, not lifestyle. Use S08 Image Hero, not M16.
|
||||
|
||||
For the cover title placement and typography on a great photo, see `references/layout-recipes.md` M16 (4 modes: 顶压底沉 / 侧栏立柱 / 角落徽章 / 下沉条带) and `references/image-overlay.md` (subject map + mask).
|
||||
|
||||
## Page Count Guidance
|
||||
|
||||
- 600-1000 Chinese characters: 5-7 images.
|
||||
- 1000-1800 Chinese characters: 7-9 images.
|
||||
- Very long source: compress to 8-10 images and put the rest in caption/body.
|
||||
- If several pages have large empty lower areas, merge adjacent ideas.
|
||||
|
||||
## Matching Visuals To Content
|
||||
|
||||
Use visuals only when they support the point:
|
||||
|
||||
- Screenshot: proof of a product feature or UI.
|
||||
- Photo: scene, object, person, outdoor atmosphere.
|
||||
- Generated image: missing scene, conceptual hero, stylized product/lifestyle illustration.
|
||||
- Diagram: flow, cross-app chain, checklist, system relation.
|
||||
|
||||
Generated image prompts should be short and role-specific:
|
||||
|
||||
```text
|
||||
Editorial documentary photo for a Rednote hiking gear guide, summer mountain trail, lightweight long-sleeve outfit, natural sunlight, clean composition, no text, no logo, 3:4.
|
||||
```
|
||||
|
||||
```text
|
||||
Swiss style conceptual product image, Android home screen widgets generated by natural language, clean off-white background, one IKB blue accent, no text, no logo, 3:4.
|
||||
```
|
||||
|
||||
## Captions And Metadata
|
||||
|
||||
Small recurring elements help the set feel designed:
|
||||
|
||||
- Category row: `AI TOOL / UPDATE / 2026`
|
||||
- Issue row: `SUMMER HIKING / BEGINNER GUIDE`
|
||||
- Page number: `03 / 08`
|
||||
- Compact labels: `DO`, `DON'T`, `WHY`, `NOTE`
|
||||
|
||||
Keep these consistent. They should support orientation, not become decoration.
|
||||
@@ -0,0 +1,152 @@
|
||||
# Image Overlay & Subject Safety
|
||||
|
||||
Two rules that govern any poster where text sits on top of an image — full-bleed background, large photo well with title bar, or generated/AI image with text overlay.
|
||||
|
||||
A composition can pass HTML linting and still be unreadable. Both rules below must clear before you ship.
|
||||
|
||||
## Rule 1 — Selection first, mask only if selection fails
|
||||
|
||||
The default editorial-magazine answer is **no mask**. Real magazine covers (Kinfolk, Cereal, Apartamento, Monocle) almost never lay a uniform black gradient over a hero photo. They rely on **photo selection + composition** so text lands in a quiet zone naturally. If you cannot find such a photo, the answer is usually to swap the photo, not to caulk over a bad one with a 70%-black scrim.
|
||||
|
||||
Apply the steps in order. Stop at the first one that passes.
|
||||
|
||||
### Step 1 — Photo selection (the main lever)
|
||||
|
||||
Before picking a mask, verify the photo qualifies for full-bleed treatment. Both tests must pass:
|
||||
|
||||
**Quiet-zone test**: at least one band of ≥30% canvas (full width × ≥30% height, or full height × ≥30% width) is **low-detail / low-contrast / uniform**. Examples: out-of-focus background, deep shade, fog, calm water, plain sky, blurred grass. This band is where the title will land.
|
||||
|
||||
**Light test**: the photo carries **atmospheric / restrained light** — overcast, dawn fog, golden hour, forest understory, film softness, dusk silhouette. Reject high-saturation noon shots, on-camera flash, "tourist trap" selfies, generic stock cheerfulness.
|
||||
|
||||
If either test fails, **the photo is wrong for M16**. Fall back to M01 (split-layout cover with photo in a frame), or shoot/source again. Do not "fix it with a mask."
|
||||
|
||||
### Step 2 — Compose without a mask first
|
||||
|
||||
Place the title inside the qualified quiet zone. Run the thumbnail contrast check (Step 4). If it reads clean, ship as-is. Most well-selected editorial photos pass at this step.
|
||||
|
||||
A no-mask cover signals craft. A heavily masked cover signals "we couldn't find the right photo." Try Step 2 every time before reaching for Step 3.
|
||||
|
||||
### Step 3 — Localized, image-toned tint (fallback only)
|
||||
|
||||
Only when Step 2 fails the contrast check. Three rules:
|
||||
|
||||
1. **Localized, not full-canvas.** Tint only the title region. Use `radial-gradient` centered on the title block, or a one-sided linear gradient that fades to fully transparent past the title. Never `inset: 0` over the whole image with a uniform alpha curve.
|
||||
2. **Image-toned, not black.** Sample a dark tone already in the photo and use it as the tint color. Forest → deep moss `#1a2818`. Dusk → tea-rose dusk `#4a2638`. Snow → cool grey-blue `#2a3438`. Pure black `#000` reads as "annotation layer," not "atmospheric depth."
|
||||
3. **Soft, not opaque.** Peak alpha 0.15-0.30 in the title region, falling to 0 outside. If you need >0.40 to read, the photo failed Step 1 — go back.
|
||||
|
||||
```css
|
||||
/* Example: title in lower-left, image-toned soft tint */
|
||||
.hero-bleed::after {
|
||||
content: "";
|
||||
position: absolute; inset: 0;
|
||||
background: radial-gradient(
|
||||
60% 45% at 25% 80%, /* centered on title block */
|
||||
rgba(26, 40, 24, 0.28) 0%, /* forest moss tone, soft peak */
|
||||
rgba(26, 40, 24, 0.0) 100%);
|
||||
pointer-events: none;
|
||||
}
|
||||
```
|
||||
|
||||
### Step 4 — Thumbnail contrast check (always)
|
||||
|
||||
Whether or not you applied a tint:
|
||||
|
||||
- Render the PNG, downscale to 360 px wide in Preview / a browser tab, and look.
|
||||
- Title strokes must be legible without zoom.
|
||||
- If title looks like it's "fighting" the photo → swap photo or shift title to a different quiet zone, **not** strengthen the mask.
|
||||
- If photo looks dead grey under uniform dark → mask is way too heavy or covers wrong area; restart from Step 1.
|
||||
|
||||
### Banned
|
||||
|
||||
- **Uniform full-canvas vertical falloff** (the `rgba(0,0,0,.55) → .10 → .10 → .80` pattern from earlier versions of this skill). That is game-key-art treatment, not editorial.
|
||||
- **Pure black mask color**. Always image-toned (forest, dusk, snow, ink-blue, sepia).
|
||||
- Flat black/white rectangle behind text — reads like screenshot annotation.
|
||||
- `mix-blend-mode: difference` for readability — wrecks skin tones, breaks on print.
|
||||
- `img { opacity: .6 }` — kills the photo's depth, the whole point of full-bleed.
|
||||
- Reaching for Step 3 before honestly attempting Step 1 with a better photo.
|
||||
|
||||
---
|
||||
|
||||
## Rule 2 — Place text away from subject / face zones
|
||||
|
||||
Posters in 旅行 / 游戏 / 影视 / 穿搭 / 美食 frequently use a real photo as the hero. The photo has a subject — a face, a hand, a product, a peak. Text that overlaps the subject reads as graffiti, not editorial.
|
||||
|
||||
### Subject zone discovery — multimodal first
|
||||
|
||||
Before designing the title position on a hero photo, look at the image. Open it with the Read tool and observe in plain language:
|
||||
|
||||
1. Where is the **primary subject's face / focal feature**? (e.g. "the climber's face is in the upper-right third around 70% x 30% y")
|
||||
2. Where is the **edge of the subject's silhouette**? (e.g. "left edge ends at ~40% x; below that is sky")
|
||||
3. Where is the **largest open / low-detail area**? (e.g. "the lower-left quadrant is uniform fog")
|
||||
|
||||
Record the answers as a comment in the HTML next to the hero block:
|
||||
|
||||
```html
|
||||
<!-- subject map (Wukong cover hero):
|
||||
face/skull centerpiece: 50% x 45% y, occupies ~30% of frame
|
||||
left-side staff & weapons: 15-40% x, full height
|
||||
safe text zone: top band (0-15% y) and bottom band (65-100% y)
|
||||
-->
|
||||
```
|
||||
|
||||
This is the input the layout uses. It's deterministic and reviewable.
|
||||
|
||||
### Safe-zone placement rules
|
||||
|
||||
Given the subject map, place text in this order of preference:
|
||||
|
||||
1. **Above + below** the subject (kicker top, title bottom). 90% of full-bleed covers should do this.
|
||||
2. **One side** — if subject occupies one vertical column (e.g. portrait shot on right side), text fills the opposite column. Combine with side tint from Rule 1 Step 3 only if needed.
|
||||
3. **Diagonal corner** — only when the subject is in one corner and the opposite corner is genuinely empty. Rare.
|
||||
|
||||
Never place display titles **across** the face. A 90 px Chinese title cutting through a person's eyes is destructive even with a mask.
|
||||
|
||||
### Composition discipline (editorial look)
|
||||
|
||||
These four rules are what separates an editorial poster from a generic image-with-text:
|
||||
|
||||
- **Asymmetric placement.** Titles offset to one side / one corner read more confident than dead-centered ones. The Kinfolk / Cereal habit.
|
||||
- **Generous negative space.** Title should occupy ≤40% of the canvas. The photo and the empty quiet zone are doing the design work.
|
||||
- **Title in one quiet zone, only one.** Splitting the title into two zones (top + bottom) is fine; splitting it into three or wrapping around the subject is busy.
|
||||
- **Title never overlaps the subject silhouette.** If the only safe placement requires crossing the subject's edge, switch modes (move to a frame, diptych, or off-image title) — do not enlarge the mask.
|
||||
|
||||
### Crop guards
|
||||
|
||||
The face-avoidance rule should also drive `object-position`. If the subject is in the upper third, do not use `object-position: center top` (that pushes the face into the title band).
|
||||
|
||||
| Subject location in raw image | Recommended `object-position` for 3:4 crop |
|
||||
| ----------------------------- | ------------------------------------------ |
|
||||
| Face / focus in upper third | `center 25%` (lifts face higher, gives bottom room for title) |
|
||||
| Face / focus in middle third | `center center` (default; text goes top + bottom) |
|
||||
| Face / focus in lower third | `center 70%` (drops face down, top room for title) |
|
||||
| Wide landscape, no single subject | `center 35%` (slight upward bias to retain horizon line) |
|
||||
| Vertical portrait, full body | `center top` |
|
||||
|
||||
### When the photo cannot accommodate text
|
||||
|
||||
If running the subject map shows there is no safe zone wider than ~30% of the poster (subject fills the frame, e.g. tight portrait), do not retrofit. Options:
|
||||
|
||||
- Move the photo into a **smaller frame** (use `.frame-img.r-3x4` or `.r-1x1` inside the layout — give it a defined slot, surround it with whitespace and text).
|
||||
- **Two-image diptych** with one tight subject + one negative-space image, run titles over the negative-space one.
|
||||
- **Move text off the image entirely** — title above, photo below. The Yading cover already does this.
|
||||
|
||||
A photo that demands the full canvas is not a sign that text should fight it. It is a sign that text should sit elsewhere.
|
||||
|
||||
---
|
||||
|
||||
## Checklist before delivery
|
||||
|
||||
Run this for every poster that has text touching an image:
|
||||
|
||||
- [ ] Photo passes quiet-zone test (≥30% canvas low-detail band) AND light test (atmospheric, not high-saturation noon).
|
||||
- [ ] Tried no-mask composition first. Tint only added if Step 4 contrast check failed.
|
||||
- [ ] If tinted: localized (`radial-gradient` or one-sided), image-toned color (not pure black), peak alpha ≤ 0.30.
|
||||
- [ ] No full-canvas vertical falloff present (`linear-gradient(180deg, rgba(0,0,0,.X) → ...)` over `inset:0`).
|
||||
- [ ] Subject map documented as a comment near the hero block.
|
||||
- [ ] No display title (≥ 72 px) overlaps a face / hand / key product feature / subject silhouette.
|
||||
- [ ] Title occupies ≤40% of canvas. Asymmetric placement preferred over centered.
|
||||
- [ ] `object-position` chosen from the table above, not left at default `center top` for face shots.
|
||||
- [ ] Thumbnail test passed (downscale to 360 px wide; title still legible without strain).
|
||||
- [ ] No flat black/white text plate behind the title.
|
||||
|
||||
If any item fails, fix it before exporting the final PNG. Do not deliver and "we can adjust later" — the QA window for social cards is the moment of upload.
|
||||
@@ -0,0 +1,831 @@
|
||||
# Layout Recipes
|
||||
|
||||
These are static social-image recipes adapted from the Guizang PPT style language. They are not copied PPT templates.
|
||||
|
||||
## Editorial Magazine x E-ink Recipes
|
||||
|
||||
These structures (ledger / marginalia / pull-quote / photo-well / pipeline-vertical) work for **any topic** that wants a magazine-feature pace — outdoor, AI, finance, food, workplace, gaming, all welcome. The mode is a visual stance, not a content filter. See `style-system.md` "Style ↔ content type are decoupled" for the full reasoning.
|
||||
|
||||
Portrait rule:
|
||||
|
||||
- Every 3:4 page should occupy the vertical canvas intentionally. If the content only creates a thin table, switch to M08/M09/M10 below or add a large pull quote, evidence image, marginal column, or full-height ledger.
|
||||
|
||||
**Content density rule (hard)**: on 1080×1440 cards, content must cover ≥75% of canvas height. Any pure-whitespace band >15% canvas height (>216px) needs a stated reason — hero-image breathing, single-sentence statement, or leading/trailing margins (combined ≤15%). Do NOT use `<div style="flex: 1"></div>` to push content to the vertical centre — Editorial magazines absorb whitespace across opposing pages; social cards are scrolled one at a time and under-filled cards read as "PowerPoint with a missing element." Each recipe below carries a `Minimum density:` line indicating the smallest content set that fills a 3:4 canvas. If your copy doesn't reach that floor, **shorten the canvas (switch to 1:1) or pick a different recipe** — never just publish under-filled.
|
||||
|
||||
### M01 Cover: Magazine Issue Cover
|
||||
|
||||
Best for Rednote page 1, portrait social cards, or article-card covers.
|
||||
|
||||
Structure:
|
||||
|
||||
- Top issue row: category, date, ratio, or account label.
|
||||
- Large serif/Songti-like title, usually 2-4 lines.
|
||||
- One large image or photo crop occupying 35%-55% of the page.
|
||||
- Bottom issue strip with 3-5 points.
|
||||
|
||||
Style:
|
||||
|
||||
- Paper background, deep ink title.
|
||||
- Photo can bleed inside a large rectangular well.
|
||||
- Accent appears as one vertical rule, page number, or small label.
|
||||
|
||||
### M02 Field Note Photo
|
||||
|
||||
Best for outdoor, object, hardware, or real-world observation.
|
||||
|
||||
Structure:
|
||||
|
||||
- Large documentary photo.
|
||||
- Narrow caption column or bottom caption band.
|
||||
- One short takeaway in large type.
|
||||
|
||||
Use when the photo is evidence, not decoration.
|
||||
|
||||
### M03 Editorial Essay Split
|
||||
|
||||
Best for explaining one idea with nuance.
|
||||
|
||||
Structure:
|
||||
|
||||
- Left: large title or pull quote.
|
||||
- Right: 2-3 short paragraphs or numbered fragments.
|
||||
- Thin rule between columns.
|
||||
|
||||
Keep paragraphs short. If it becomes dense, split the page.
|
||||
|
||||
**Minimum density (3:4)**: title + 3 short paragraphs OR title + 2 paragraphs + numbered footer list. Title alone is M04, not M03. If you have only a title + 1 paragraph, switch to M04 Pull Quote or fold a marginal column in for M11 Marginalia Essay.
|
||||
|
||||
### M04 Pull Quote / Thesis
|
||||
|
||||
Best for a core sentence or conclusion.
|
||||
|
||||
Structure:
|
||||
|
||||
- Large quote across the page.
|
||||
- Small source/context row.
|
||||
- Optional tiny note or issue marker.
|
||||
|
||||
Use to create rhythm between dense pages.
|
||||
|
||||
**Minimum density (3:4)**: this is the **one recipe** where ≤60% canvas content is allowed (hero statement = intentional whitespace). BUT you must add (a) source/context row 18-20px mono ≤15% from bottom, (b) date-stamp or 章号 kicker at top, (c) hairline rule above the source row. Without these three "anchor points," whitespace reads as missing content. Don't use M04 if you can't supply at least one anchor.
|
||||
|
||||
### M05 Checklist / Buying Guide
|
||||
|
||||
Best for Rednote practical content.
|
||||
|
||||
Structure:
|
||||
|
||||
- Header title.
|
||||
- 4-6 rows, each with a number, item, and consequence.
|
||||
- Optional small photo crop or material swatch.
|
||||
|
||||
Avoid generic rounded cards; use rows, rules, columns, and issue labels.
|
||||
|
||||
### M06 Evidence Wall
|
||||
|
||||
Best for multiple screenshots, references, or small images.
|
||||
|
||||
Structure:
|
||||
|
||||
- 2x2 or 3-column image grid.
|
||||
- Each image has a short caption.
|
||||
- One larger headline anchors the interpretation.
|
||||
|
||||
Use only when supplied images are readable at the final size.
|
||||
|
||||
### M07 Closing Note
|
||||
|
||||
Best for final page.
|
||||
|
||||
Structure:
|
||||
|
||||
- Big takeaway title (≤2 lines).
|
||||
- **4-6 ledger items**, each 26-30px serif title + 16-18px serif sub-line ("consequence" / "reason" / "example"). Each item row should consume 100-140px vertical (border + padding + content).
|
||||
- Closing block: pull-quote OR signature line OR price/CTA OR small marginalia (one of these is required).
|
||||
- Small footer label.
|
||||
|
||||
Mood should feel like the end of a magazine feature, not a sales banner.
|
||||
|
||||
**Minimum density (3:4)**: title + **≥4 ledger items with sub-lines** + closing block. The previous "2-3 rules" version under-fills 3:4 by ~40%. If you genuinely only have 3 reasons, expand each to "title + 2-line consequence + example/quote" OR pair with a pull-quote closing block. **3 short ledger lines on a 3:4 canvas is a failure mode**; either expand or switch to M04 Pull Quote.
|
||||
|
||||
### M08 Tall Ledger
|
||||
|
||||
Best for lists, roles, pros/cons, gear items, product capabilities, and agent responsibilities.
|
||||
|
||||
Structure:
|
||||
|
||||
- Header title.
|
||||
- 4-6 full-width rows.
|
||||
- Each row minimum 118-170px on a 1080x1440 canvas.
|
||||
- Left index/marginalia column, right title + consequence.
|
||||
- Optional vertical accent strip or bottom issue note.
|
||||
|
||||
Use when a normal table would become too short. Do not let the ledger occupy only the middle third of the page.
|
||||
|
||||
### M09 Atmospheric Thesis
|
||||
|
||||
Best for sparse but important points.
|
||||
|
||||
Structure:
|
||||
|
||||
- WebGL/ink-flow background visible across the page.
|
||||
- One very large thesis or quote.
|
||||
- 1-2 supporting notes.
|
||||
- Small issue metadata and a bottom rule.
|
||||
|
||||
Use this instead of forcing a small table onto a page with little content.
|
||||
|
||||
### M10 Evidence Feature
|
||||
|
||||
Best for supplied screenshots/photos.
|
||||
|
||||
Structure:
|
||||
|
||||
- Large screenshot/photo occupying 45%-65% of the vertical canvas.
|
||||
- Headline and lead above or beside it.
|
||||
- Bottom caption band with 2-3 takeaways.
|
||||
|
||||
The image is not an afterthought. If the screenshot is important, it must be big enough to inspect.
|
||||
|
||||
### M11 Marginalia Essay
|
||||
|
||||
Best for nuanced explanation with moderate text.
|
||||
|
||||
Structure:
|
||||
|
||||
- Wide editorial title.
|
||||
- Main column with 2-3 paragraphs.
|
||||
- Narrow marginal column containing keywords, quote fragments, or small evidence crops.
|
||||
- Hairline vertical rule between columns.
|
||||
|
||||
Use this when M03 feels too empty but a ledger feels too mechanical.
|
||||
|
||||
### M12 Section Divider
|
||||
|
||||
Best for a mid-carousel breath between dense pages. Drop one between act 1 and act 2 of a 7-9 page Rednote set so the reader gets a beat of silence.
|
||||
|
||||
Structure:
|
||||
|
||||
- WebGL ink-flow background visible across most of the canvas (Editorial template mounts this by default).
|
||||
- One mono `kicker` like `Act II` or `Part 2 of 3`.
|
||||
- One large serif `h-display` naming the section (3-6 Chinese characters).
|
||||
- One short subtitle in serif italic.
|
||||
- Optional bottom `issue-strip` with the section's promise.
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-04">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="content stack gap-4" style="justify-content:center; align-items:flex-start">
|
||||
<p class="kicker">Act II · Part 2</p>
|
||||
<h1 class="h-display">实测结果</h1>
|
||||
<p class="h-sub">What actually happened.</p>
|
||||
</div>
|
||||
<div class="issue-strip">
|
||||
<span>Section · Findings</span>
|
||||
<span>—</span>
|
||||
<span>3 pages</span>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Adapt for 1:1: drop the subtitle, center the `h-display`, keep the ink-flow background strong. Adapt for 21:9: shift title to the left half, let the WebGL atmosphere occupy the right half.
|
||||
|
||||
### M13 Hero Question
|
||||
|
||||
Best for the last page of a Rednote carousel or for a sharp pivot mid-set. The question is the entire page.
|
||||
|
||||
Structure:
|
||||
|
||||
- WebGL ink-flow background.
|
||||
- Quiet kicker like `The Question` or `留给你的`.
|
||||
- Big serif question, broken into 2-3 lines on `<br>` at semantic breakpoints (not random wraps).
|
||||
- One short single-sentence prompt in `lead`, often a hint or invitation to comment.
|
||||
- Minimal metadata at bottom.
|
||||
|
||||
**Minimum density (3:4)**: like M04, this is intentionally airy. Required anchors: top kicker (0-12% y) + bottom prompt + bottom metadata strip. The ink-flow WebGL background **must be visible** (don't let `.content` cover it). If the WebGL background is missing or the kicker is empty, the page reads as under-filled rather than meditative.
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-09">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="content stack gap-4" style="justify-content:center">
|
||||
<p class="kicker">The Question · 留给你的</p>
|
||||
<h1 class="h-display">
|
||||
下一次<br>
|
||||
你会先<br>
|
||||
问 AI 还是问朋友?
|
||||
</h1>
|
||||
<p class="lead">在评论区告诉我你的答案。</p>
|
||||
</div>
|
||||
<div class="issue-strip">
|
||||
<span>End · Page 9</span>
|
||||
<span>—</span>
|
||||
<span>欢迎留言</span>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Title length cap: 3 lines, each <= 6 Chinese characters at default size. If the question is longer, shorten it; do not shrink the `h-display`.
|
||||
|
||||
### M14 Vertical Pipeline
|
||||
|
||||
Best for explaining a 3-5 step workflow, decision tree, or recipe. PPT's pipeline is horizontal; for portrait social cards rotate it vertical.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- 3-5 `.pipeline-v .step` rows. Each row has step number (mono), step title (serif), one-line description (sans).
|
||||
- Hairline between steps, gap 28-36px.
|
||||
- Optional small evidence image to the right of the title, or a single bottom caption.
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-06">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="content stack gap-3">
|
||||
<p class="kicker">Workflow · 4 步</p>
|
||||
<h2 class="h-xl">我的写作流水线</h2>
|
||||
<div class="pipeline-v">
|
||||
<div class="step">
|
||||
<div class="step-nb">01</div>
|
||||
<div>
|
||||
<h3 class="step-title">Draft</h3>
|
||||
<p class="step-desc">用语音备忘录把想法说出来</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">02</div>
|
||||
<div>
|
||||
<h3 class="step-title">Reorder</h3>
|
||||
<p class="step-desc">用 AI 把段落顺序重新排</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">03</div>
|
||||
<div>
|
||||
<h3 class="step-title">Polish</h3>
|
||||
<p class="step-desc">人工逐句去 AI 味</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="step-nb">04</div>
|
||||
<div>
|
||||
<h3 class="step-title">Ship</h3>
|
||||
<p class="step-desc">同时发小红书、推特、公众号</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Hard limit: 3-5 steps. If you have 6+, split into two pages or switch to M05 Checklist.
|
||||
|
||||
### M15 Before / After
|
||||
|
||||
Best for "old way vs new way", "before AI vs after AI", "rookie vs pro" comparisons. PPT's Before/After is left-right; on 3:4 portrait, stack top/bottom to avoid pinched columns.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- `.beforeafter` container with two `.ba-block` rows: one with class `before` (dimmed at .68 opacity), one without.
|
||||
- Each block has its own kicker, mid title, and 3-4 short bullets.
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-07">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="content stack gap-3">
|
||||
<p class="kicker">Before · After</p>
|
||||
<h2 class="h-xl">写作流的演变</h2>
|
||||
<div class="beforeafter">
|
||||
<div class="ba-block before">
|
||||
<p class="kicker">Before · 旧</p>
|
||||
<h3 class="h-md">在 Notion 里反复修</h3>
|
||||
<ul class="body" style="margin:0; padding-left:1.2em">
|
||||
<li>开头改了 20 遍</li>
|
||||
<li>每个段落都想精雕</li>
|
||||
<li>一周才发一条</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="ba-block">
|
||||
<p class="kicker">After · 新</p>
|
||||
<h3 class="h-md">先发版,再迭代</h3>
|
||||
<ul class="body" style="margin:0; padding-left:1.2em">
|
||||
<li>20 分钟出初稿</li>
|
||||
<li>评论区做精修</li>
|
||||
<li>一天发三条</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Adapt for 21:9: switch to left/right split (use `.col-2` grid). Adapt for 1:1: usually too cramped; consider M04 Pull Quote instead.
|
||||
|
||||
### M16 Image-Led Cover (Full-Bleed Hero)
|
||||
|
||||
Best for **lifestyle, image-heavy** content where the user has 1+ excellent photos: 旅行目的地 / 户外场景 / 自家成菜 / 家居一角 / 情感场景照. Photo fills the canvas; title rides on top with restraint. This is what M01 is **not** — M01 splits the canvas into photo + text blocks. M16 lets the photo own the canvas.
|
||||
|
||||
**Reference look**: Kinfolk / Cereal / Apartamento / Monocle covers. Quiet photo, serif title, paper-cream text, generous negative space, asymmetric placement. **NOT** game key-art with heavy black gradient. **NOT** travel poster with chunky bold caption.
|
||||
|
||||
**Required**: `references/image-overlay.md` Rule 1 Steps 1-4 must all pass. The first gate (photo selection) is the hardest — most photos fail it.
|
||||
|
||||
### Photo qualification (gate before choosing M16)
|
||||
|
||||
Run both tests on the user's photo. Both must pass, or **switch to M01** (split-layout) instead of forcing M16.
|
||||
|
||||
1. **Quiet-zone test**: photo has a band of ≥30% canvas (full width × ≥30% height, or full height × ≥30% width) that is low-detail / out-of-focus / uniform. This is where the title will land.
|
||||
2. **Light test**: photo carries atmospheric/restrained light — overcast, dawn fog, golden hour, forest understory, dusk silhouette, film softness. Reject high-saturation noon shots, on-camera flash, generic tourist snaps.
|
||||
|
||||
If only one passes: try M01. If neither: ask user for a different photo, or use M01 with a smaller `.frame-img` slot. **Do not "fix it with a mask."**
|
||||
|
||||
**Page sequence convention** (this is the "image-led" pattern):
|
||||
|
||||
```
|
||||
P1 (M16) ← full-bleed photo + short title — the hook
|
||||
P2 (S11 / M05 / M10) ← ledger / checklist / mini-data — text-heavy rest stop
|
||||
P3 (M02 or M16-small) ← second photo as field-note evidence, not full-bleed
|
||||
P4-N (M02 / M11) ← more field notes or marginalia essays
|
||||
P_last (M07 / M04) ← closing note or pull quote
|
||||
```
|
||||
|
||||
Never run two M16 in a row. After a full-bleed photo the eye needs text. P2 must be data/text.
|
||||
|
||||
**Four title-placement modes** — pick by subject map (from image-overlay.md Rule 2):
|
||||
|
||||
| Mode | Subject location | Title position | Tint (only if Step 4 contrast fails) |
|
||||
| ---- | ---------------- | -------------- | ------------------------------------ |
|
||||
| **A · 顶压底沉** (top kicker + bottom title) | Subject in middle third (face, peak, hero object), top + bottom open | Top: kicker 0-12% y. Bottom: 1-2 line title 72-92% y. | Try no tint. If needed: bottom-only radial, image-toned, peak α ≤ 0.30 over title block. |
|
||||
| **B · 侧栏立柱** (vertical column) | Subject occupies a **clean** vertical column with ≥40% width safe opposite side. Skip B if subject edge is irregular (e.g. tree canopy spilling sideways) — use A or D instead. | Opposite column (~36-40% of width), stacked: kicker → title → subtitle | Try no tint. If needed: one-sided horizontal falloff `radial-gradient(45% 60% at 18% 50%, …)`, image-toned. |
|
||||
| **C · 角落徽章** (corner badge) | Subject fills most of the frame; one corner is genuinely empty | Small block in the empty corner (≤35% w × ≤25% h): kicker / short title / meta | Light vignette only in that corner — never darken the whole image |
|
||||
| **D · 下沉条带** (bottom ribbon) | Wide landscape / atmospheric scene / no single subject; abundant negative space at bottom | Bottom band 78-92% y: title + meta strip; align flush-left or flush-right (not centered) | Try no tint. If needed: bottom-only radial, image-toned, peak α 0.20-0.30 |
|
||||
|
||||
**Typography spec on 1080×1440 (Editorial × E-ink) — restrained, NOT chunky**:
|
||||
|
||||
| Element | Mode A | Mode B | Mode C | Mode D |
|
||||
| ------- | ------ | ------ | ------ | ------ |
|
||||
| Kicker | mono 20-22px, uppercase, tracking 0.18-0.22em | mono 20-22px | mono 18-20px | mono 22-24px |
|
||||
| Title font | Noto Serif SC **400-500** (NOT 700-900) | same | same | same |
|
||||
| Title size | **88-108px**. Default 96px for 2-line zh title. Drop to 88px if 2 lines × ≥7 chars. | **84-100px**, wrap on phrase boundary | 56-64px (NOT display) | **96-112px**, single line preferred |
|
||||
| Title tracking (zh) | 0.10-0.15em | 0.10-0.15em | 0.05-0.10em | 0.12-0.18em |
|
||||
| Title line-height | 1.10-1.18 | 1.10-1.18 | 1.20 | 1.05-1.10 |
|
||||
| Subtitle | optional `h-sub` 28-32px italic Playfair, tracking 0 | same | omit | same |
|
||||
| Issue strip | mono 18-20px bottom, uppercase, tracking 0.20-0.25em, hairline above | omit | omit | mono 20-22px, tracking 0.20-0.25em |
|
||||
| Text color | `#f5f1e8` (paper-cream, NOT pure white #fff) | same | same | same |
|
||||
| Hairline color | `rgba(245, 241, 232, 0.35)` (paper at 35% alpha) | same | same | same |
|
||||
|
||||
**Forbidden in M16 type**:
|
||||
|
||||
- Title weight 700+ inline (e.g. `font-weight: 800` to "make it pop"). M16 wants **regular-medium serif**, not bold.
|
||||
- Pure white `#fff` text — too clinical, fights the photo's warmth. Always paper-cream.
|
||||
- Title size > 120px on 1080-wide canvas. We are not making travel posters.
|
||||
- Latin sans-serif as primary title (Helvetica / Inter for the headline) — M16 belongs to serif. Sans only as kicker / meta / mono caption.
|
||||
- Centered title on D mode. Always flush-left or flush-right for asymmetric Kinfolk feel.
|
||||
|
||||
**Title-length budget** (cut copy if you bust this — never shrink type below 84px):
|
||||
|
||||
| Mode | Max Chinese chars | Max lines |
|
||||
| ---- | ----------------- | --------- |
|
||||
| A | 12 (2 × 6) or 14 (2 × 7 at 88px) | 2 |
|
||||
| B | 14 (2 × 7) | 2 |
|
||||
| C | 8 | 1 |
|
||||
| D | 10 | 1 |
|
||||
|
||||
**Square (1:1, 1080×1080) and Wide (21:9, 2100×900) adaptations**:
|
||||
|
||||
- **1:1**: Use Mode A or Mode D only. Mode B's column squeeze, Mode C's corner are too tight on square. Shorten title to 6-10 chars.
|
||||
- **21:9**: Use Mode B (left text column + right photo bleed) or Mode D (full-width bottom band). Mode A works but the bottom title competes with the WeChat caption strip — prefer D.
|
||||
|
||||
**HTML skeleton (Mode A — 顶压底沉 on 3:4, no mask)**:
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="cover-image-led">
|
||||
<!-- subject map (cover hero — example: Yading lake at dawn):
|
||||
primary focus: snow peak at 50% x 32% y (middle band)
|
||||
safe text zone: top band (0-12% y) low-detail sky,
|
||||
bottom band (72-95% y) calm water reflection
|
||||
quiet-zone test: PASS — bottom 30% is uniform water
|
||||
light test: PASS — dawn overcast, soft saturation
|
||||
-->
|
||||
<div class="hero-bleed" style="background-image: url('assets/hero-yading.jpg');
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
position: absolute; inset: 0;"></div>
|
||||
<!-- NO MASK — quiet zone already provides contrast.
|
||||
Add only if Step 4 contrast check fails. -->
|
||||
<div class="content" style="position: relative; height: 100%;
|
||||
color: #f5f1e8; padding: 72px 80px;
|
||||
display: flex; flex-direction: column;">
|
||||
<p class="kicker" style="color: #f5f1e8; opacity: .85;
|
||||
font-family: var(--mono); font-size: 22px;
|
||||
letter-spacing: 0.22em; text-transform: uppercase; margin: 0">
|
||||
Vol. 04 — 2026 — 户外
|
||||
</p>
|
||||
<div style="flex: 1"></div>
|
||||
<h1 style="font-family: 'Noto Serif SC', serif;
|
||||
font-weight: 500; font-size: 96px; line-height: 1.12;
|
||||
letter-spacing: 0.12em; color: #f5f1e8;
|
||||
margin: 0 0 18px 0">
|
||||
在稻城<br/>看见冬天
|
||||
</h1>
|
||||
<div style="border-top: 1px solid rgba(245,241,232,.35);
|
||||
padding-top: 14px; font-family: var(--mono); font-size: 19px;
|
||||
letter-spacing: 0.22em; text-transform: uppercase;
|
||||
color: #f5f1e8; opacity: .85">
|
||||
DAY 1-4 · 4,200 M · −18°C
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
**HTML skeleton (Mode D — 下沉条带 on 21:9, for WeChat main cover)**:
|
||||
|
||||
```html
|
||||
<section class="poster wide" id="wechat-21x9-led">
|
||||
<!-- subject map: wide atmospheric landscape, mist over lake at dawn
|
||||
quiet-zone test: PASS — entire bottom 35% is calm water + mist -->
|
||||
<div class="hero-bleed" style="background-image: url('assets/hero-yading-wide.jpg');
|
||||
background-size: cover; background-position: center 40%;
|
||||
position: absolute; inset: 0;"></div>
|
||||
<div class="content" style="position: relative; height: 100%;
|
||||
color: #f5f1e8; padding: 0 96px 88px;
|
||||
display: flex; flex-direction: column; justify-content: flex-end;
|
||||
align-items: flex-start;">
|
||||
<h1 style="font-family: 'Noto Serif SC', serif; font-weight: 500;
|
||||
font-size: 108px; line-height: 1.05; letter-spacing: 0.14em;
|
||||
margin: 0; color: #f5f1e8">
|
||||
在稻城看见冬天
|
||||
</h1>
|
||||
<div style="margin-top: 18px; border-top: 1px solid rgba(245,241,232,.35);
|
||||
padding-top: 14px; font-family: var(--mono); font-size: 20px;
|
||||
letter-spacing: 0.24em; text-transform: uppercase">
|
||||
VOL. 04 — DAY 1-4 — 4,200 M — 35MM
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
**Pitfalls**:
|
||||
|
||||
- Choosing M16 when the photo fails quiet-zone or light test. The cover will look bad no matter what mask you layer on. Fall back to M01.
|
||||
- Putting Mode A's bottom title across someone's torso when the subject is in the lower third — re-run subject map and switch to Mode C, or change `object-position: center 70%`.
|
||||
- Mode C with a heavy backdrop plate behind the corner title — defeats the point of having a great photo. Use vignette only.
|
||||
- Using Mode B on a photo where the subject's silhouette is **irregular** (trees with sideways branches, scattered objects) — the "side column" won't be wide enough to be a true safe zone. Switch to Mode A or D.
|
||||
- Adding a full-canvas vertical falloff "just in case." Mask-by-default kills the editorial look. The fix is photo selection, not opacity.
|
||||
- Setting title weight 700+ or pure-white text — both are anti-pattern in Editorial M16.
|
||||
- Running M16 on every cover. M16 is for **image-heavy lifestyle**. Product/tech/AI release covers still belong to S01 / S03 / M01.
|
||||
|
||||
## Swiss International Recipes
|
||||
|
||||
These structures (accent cover / matrix / KPI tower / h-bar / numbered statement) work for **any topic** that wants an engineered, quantified pace — software releases yes, but also travel budgets, fitness logs, recipe portions, reading stats, anything where you'd rather count it than narrate it. The mode is a visual stance, not a content filter.
|
||||
|
||||
### S01 Accent Cover
|
||||
|
||||
Best for Rednote cover.
|
||||
|
||||
Structure:
|
||||
|
||||
- Full accent or off-white background.
|
||||
- Big light-weight title.
|
||||
- Simple abstract system block, comparison, or two-node diagram.
|
||||
- Bottom metadata strip.
|
||||
|
||||
Use one clear concept. No decorative blobs.
|
||||
|
||||
### S02 Two Signals / Comparison
|
||||
|
||||
Best for explaining two sources, two options, or two product directions.
|
||||
|
||||
Structure:
|
||||
|
||||
- Page title.
|
||||
- Two large rectangular modules.
|
||||
- One module may be ink-filled; the other paper/outlined.
|
||||
- Short notes below each.
|
||||
|
||||
### S03 Data Layer / File Card
|
||||
|
||||
Best for Markdown, memory, source-of-truth, database, or state.
|
||||
|
||||
Structure:
|
||||
|
||||
- Large file-type or object block.
|
||||
- List of 3-4 properties.
|
||||
- Strong mono labels.
|
||||
|
||||
### S04 Interface / Browser Mock
|
||||
|
||||
Best for HTML, UI, presentation, interaction, or output layer.
|
||||
|
||||
Structure:
|
||||
|
||||
- Browser-window style frame with straight edges.
|
||||
- Inside: one hero content block plus 2-3 functional modules.
|
||||
- Bottom action or interaction strip.
|
||||
|
||||
### S05 Trap / Warning Rows
|
||||
|
||||
Best for problems, anti-patterns, and "do not do this" pages.
|
||||
|
||||
Structure:
|
||||
|
||||
- Big warning title.
|
||||
- Three horizontal rows.
|
||||
- Left mono label, right consequence.
|
||||
|
||||
Safety Orange works well here if the whole package uses it.
|
||||
|
||||
### S06 Pipeline / Architecture
|
||||
|
||||
Best for workflows and layered systems.
|
||||
|
||||
Structure:
|
||||
|
||||
- Three rows or columns: source, render, share.
|
||||
- Each has number, label, action, and consequence.
|
||||
- Use hairline boxes and neutral grey fills.
|
||||
|
||||
### S07 Takeaway Ledger
|
||||
|
||||
Best for final page.
|
||||
|
||||
Structure:
|
||||
|
||||
- Big thesis title.
|
||||
- Three ledger rows with number, phrase, and compressed explanation.
|
||||
- Dark or ink background can create closure.
|
||||
|
||||
### S08 Image Hero
|
||||
|
||||
Best for the WeChat 21:9 main cover and the Rednote cover when you have one strong photo or product render. The image fills the page; the title sits inside an overlay block; 3 quantified stats anchor the bottom.
|
||||
|
||||
Structure:
|
||||
|
||||
- `.chrome-min` top single row (category + date).
|
||||
- `.image-hero` grid: `.hero-img-wrap` with one `.frame-img.r-21x9` photo (or `.r-3x2` on 3:4).
|
||||
- `.hero-overlay-block` sitting over the upper-left of the image with `t-cat` kicker + `h-statement` title.
|
||||
- `.hero-stats` row of 3 `.stat-block`s, each with a big `num` (e.g. `132K`) and a mono `lbl`.
|
||||
|
||||
HTML skeleton (21:9, the natural format for this recipe):
|
||||
|
||||
```html
|
||||
<section class="poster wide" id="wechat-21x9-hero" data-accent="ikb">
|
||||
<div class="content stack gap-7">
|
||||
<div class="chrome-min">
|
||||
<span class="t-cat">Release · 产品</span>
|
||||
<span class="t-meta">2026.05 · v3.0</span>
|
||||
</div>
|
||||
<div class="image-hero">
|
||||
<div class="hero-img-wrap">
|
||||
<img src="assets/hero.jpg" alt="hero">
|
||||
<div class="hero-overlay-block">
|
||||
<p class="t-cat">Cover · 主封面</p>
|
||||
<h1 class="h-statement">下一代<br>写作工作流</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hero-stats">
|
||||
<div class="stat-block">
|
||||
<p class="num">132K</p>
|
||||
<p class="lbl">Weekly Writers</p>
|
||||
</div>
|
||||
<div class="stat-block">
|
||||
<p class="num">3.4×</p>
|
||||
<p class="lbl">Output Speed</p>
|
||||
</div>
|
||||
<div class="stat-block">
|
||||
<p class="num">98%</p>
|
||||
<p class="lbl">Ship Rate</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Adapt for 3:4: keep the same `.image-hero` structure but swap `.r-21x9` to `.r-3x2`, drop overlay block down to 35% height. Adapt for 1:1: drop the overlay block entirely, push title above the image, keep at most 2 stats in `hero-stats`.
|
||||
|
||||
### S09 KPI Tower
|
||||
|
||||
Best for product-update pages, release notes, traffic dashboards, growth posts — anywhere 3-4 numbers need to be compared at a glance.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- `.kpi-tower-row` with 4 `.tower-col`s, each containing a `num`, `lbl`, and a `.bar-tower` whose height encodes the value via `style="--h:Npx"`.
|
||||
- One column may carry the `.muted` modifier to drop the bar to neutral grey (use for a comparison baseline).
|
||||
|
||||
HTML skeleton (3:4 — template auto-collapses to 2 columns):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-data" data-accent="lemon-yellow">
|
||||
<div class="content stack gap-7">
|
||||
<p class="t-cat">Data · 半年增长</p>
|
||||
<h2 class="h-xl">六个月,四组数字</h2>
|
||||
<div class="kpi-tower-row">
|
||||
<div class="tower-col">
|
||||
<p class="num">132K</p>
|
||||
<p class="lbl">Subscribers</p>
|
||||
<div class="bar-tower" style="--h:320px"></div>
|
||||
</div>
|
||||
<div class="tower-col">
|
||||
<p class="num">3.4M</p>
|
||||
<p class="lbl">Reads</p>
|
||||
<div class="bar-tower" style="--h:220px"></div>
|
||||
</div>
|
||||
<div class="tower-col">
|
||||
<p class="num">68%</p>
|
||||
<p class="lbl">Repeat Visits</p>
|
||||
<div class="bar-tower" style="--h:160px"></div>
|
||||
</div>
|
||||
<div class="tower-col muted">
|
||||
<p class="num">8.2%</p>
|
||||
<p class="lbl">Conversion</p>
|
||||
<div class="bar-tower" style="--h:120px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
`--h` is a real height in px — pick values that proportionally encode the data. Do not invent numbers; if you only have 2 numbers, drop to 2 columns and use S03 File Card instead. Adapt for 21:9: keep 4 columns at the original width (it's where the layout shines). Adapt for 1:1: 2 columns max, taller bars.
|
||||
|
||||
### S10 H-Bar Chart
|
||||
|
||||
Best for rankings, comparisons of 5-10 items, "top N" lists, before/after pairs at scale. The bar fill encodes magnitude via `style="--w:NN%"`.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- `.h-bar-chart` grid with 5-10 `.bar-row`s.
|
||||
- Each row: `.row-lbl` (Chinese item name), `.row-track` containing `.row-fill`, `.row-val` (mono number).
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-rank" data-accent="ikb">
|
||||
<div class="content stack gap-7">
|
||||
<p class="t-cat">Ranking · TOP 6</p>
|
||||
<h2 class="h-xl">本月最受欢迎的工具</h2>
|
||||
<div class="h-bar-chart">
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Claude Code</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:94%"></div></div>
|
||||
<div class="row-val">94%</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Cursor</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:78%"></div></div>
|
||||
<div class="row-val">78%</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Linear</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:62%"></div></div>
|
||||
<div class="row-val">62%</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Raycast</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:48%"></div></div>
|
||||
<div class="row-val">48%</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Notion</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:36%"></div></div>
|
||||
<div class="row-val">36%</div>
|
||||
</div>
|
||||
<div class="bar-row">
|
||||
<div class="row-lbl">Obsidian</div>
|
||||
<div class="row-track"><div class="row-fill" style="--w:28%"></div></div>
|
||||
<div class="row-val">28%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Hard limits: max 6 rows on 1:1, max 10 rows on 3:4, max 8 rows on 21:9. On 3:4 the template stacks `row-lbl` above the track automatically — leave it alone. Always use real percentages or normalize the largest value to 100%; never fabricate.
|
||||
|
||||
### S11 Stacked Ledger
|
||||
|
||||
Best for shopping lists, expense rollups, agent capability inventories, or any "big number + label + icon" row stack where each item is quantified.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- `.stacked-ledger` containing 4-6 `.ledger-row`s.
|
||||
- Each row: `.ledger-num` (large mono-feel sans number), `.ledger-lbl` (Chinese label + optional `.sub` secondary line), `.ledger-icn` (Lucide icon).
|
||||
|
||||
HTML skeleton (3:4):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-spend" data-accent="safety-orange">
|
||||
<div class="content stack gap-7">
|
||||
<p class="t-cat">Spend · 五月账单</p>
|
||||
<h2 class="h-xl">这个月我把钱花在哪</h2>
|
||||
<div class="stacked-ledger">
|
||||
<div class="ledger-row">
|
||||
<p class="ledger-num">¥1,280</p>
|
||||
<div class="ledger-lbl">订阅 · Subscriptions
|
||||
<span class="sub">Claude · Cursor · Linear</span>
|
||||
</div>
|
||||
<i class="ledger-icn" data-lucide="square-stack"></i>
|
||||
</div>
|
||||
<div class="ledger-row">
|
||||
<p class="ledger-num">¥860</p>
|
||||
<div class="ledger-lbl">书 · Books
|
||||
<span class="sub">6 本中文 · 2 本英文</span>
|
||||
</div>
|
||||
<i class="ledger-icn" data-lucide="book-open"></i>
|
||||
</div>
|
||||
<div class="ledger-row">
|
||||
<p class="ledger-num">¥540</p>
|
||||
<div class="ledger-lbl">咖啡 · Coffee
|
||||
<span class="sub">主要在 Manner 和 Seesaw</span>
|
||||
</div>
|
||||
<i class="ledger-icn" data-lucide="coffee"></i>
|
||||
</div>
|
||||
<div class="ledger-row">
|
||||
<p class="ledger-num">¥320</p>
|
||||
<div class="ledger-lbl">硬件 · Hardware
|
||||
<span class="sub">键盘配件 · 一根 USB-C</span>
|
||||
</div>
|
||||
<i class="ledger-icn" data-lucide="keyboard"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Hard limits: max 6 rows on 3:4, max 4 rows on 1:1, max 8 rows on 21:9. Pick angular Lucide icons (`book-open`, `coffee`, `bolt`, `square-stack`, `keyboard`) — never `heart-filled` or `smile`. If you cannot find numerical evidence, this is the wrong recipe; use S05 Trap Rows or M08 Tall Ledger.
|
||||
|
||||
### S12 Matrix + Hero Stat
|
||||
|
||||
Best for capability matrices, agent inventories, "this set covers X domains" pages where 8-12 small cells back a single bottom-line number.
|
||||
|
||||
Structure:
|
||||
|
||||
- `kicker` + `h-xl` page title.
|
||||
- `.matrix-fill` grid of 8-12 `.matrix-cell`s. Each cell: `.cell-nb` (numbered mono label like `01`) and `.cell-title` (one short Chinese phrase).
|
||||
- Exactly one cell may carry the `.is-accent` modifier to single out the most important capability.
|
||||
- `.hero-stat-bottom` below the grid: left column with a kicker + short sentence, right column with one `num-mega` summary stat.
|
||||
|
||||
HTML skeleton (3:4 — matrix collapses to 2 columns):
|
||||
|
||||
```html
|
||||
<section class="poster xhs" id="xhs-matrix" data-accent="lemon-green">
|
||||
<div class="content stack gap-7">
|
||||
<p class="t-cat">Capabilities · 能力清单</p>
|
||||
<h2 class="h-xl">一个 Agent,十二件事</h2>
|
||||
<div class="matrix-fill">
|
||||
<div class="matrix-cell"><p class="cell-nb">01</p><p class="cell-title">读取项目结构</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">02</p><p class="cell-title">运行测试</p></div>
|
||||
<div class="matrix-cell is-accent"><p class="cell-nb">03</p><p class="cell-title">起草 PR 描述</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">04</p><p class="cell-title">回滚错误改动</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">05</p><p class="cell-title">迁移 lockfile</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">06</p><p class="cell-title">检查类型</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">07</p><p class="cell-title">追踪 issue</p></div>
|
||||
<div class="matrix-cell"><p class="cell-nb">08</p><p class="cell-title">阅读日志</p></div>
|
||||
</div>
|
||||
<div class="hero-stat-bottom">
|
||||
<div>
|
||||
<p class="t-cat">In total · 累计</p>
|
||||
<p class="lead">在 6 个仓库上,持续 4 周。</p>
|
||||
</div>
|
||||
<p class="num-mega">12</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
Hard limits: 8 cells on 3:4 (2×4), 9 cells on 1:1 (3×3), 12 cells on 21:9 (4×3). Max one `is-accent` cell — two breaks the rhythm. The `num-mega` at bottom must agree with the cell count (`12` if 12 cells, `8` if 8); never display a number unsupported by the grid.
|
||||
|
||||
## WeChat Adaptation
|
||||
|
||||
For 21:9:
|
||||
|
||||
- Use M01/S01 as a wide composition, not a crop.
|
||||
- Put title in the left or center-left safe area.
|
||||
- Use the right half for photo/object/system visual.
|
||||
- Enlarge title and subtitle spacing if the center feels empty.
|
||||
|
||||
For 1:1:
|
||||
|
||||
- Distill the long title into a simple centered title.
|
||||
- If the user asks for no image, use type only.
|
||||
- Avoid small subtitles and avoid photos by default.
|
||||
- Keep the square readable as a thumbnail: one idea, big type, generous margins.
|
||||
|
||||
For pair preview:
|
||||
|
||||
- Put the `21:9` and `1:1` compositions in one HTML preview frame.
|
||||
- The preview frame is for review only; do not treat it as a third required WeChat deliverable unless requested.
|
||||
@@ -0,0 +1,142 @@
|
||||
# Map Component (.map-block)
|
||||
|
||||
Use when the content has **spatial relationships**: a travel route, store locations, walking tour, neighborhood overview, store-vs-store comparison by district, before/after relocation. Single coordinates ("我在北京") don't need a map.
|
||||
|
||||
Both seeds ship `.map-block` + `.map-pin` + `.map-legend` classes. The same markup works in either; only the style-locked tones differ.
|
||||
|
||||
## Three rendering modes
|
||||
|
||||
Pick mode **before** writing the markup. They are not stackable.
|
||||
|
||||
### Mode S · Schematic SVG (default, no token)
|
||||
|
||||
Hand-drawn-style vector map drawn into a `viewBox="0 0 100 100"` SVG. Best for editorial decks where the map should feel like an illustrated guide, not a satellite capture. No external service.
|
||||
|
||||
```html
|
||||
<div class="map-block r-16x10">
|
||||
<svg viewBox="0 0 100 100" preserveAspectRatio="none">
|
||||
<!-- coastline / district boundary -->
|
||||
<path class="map-coast" d="M 6 18 Q 32 22 58 16 T 96 28"/>
|
||||
<!-- main road -->
|
||||
<path class="map-road" d="M 8 78 Q 42 62 78 70 T 96 56"/>
|
||||
<!-- secondary road -->
|
||||
<path class="map-road" d="M 24 14 L 38 62 L 52 86"/>
|
||||
<!-- water / park polygon -->
|
||||
<path class="map-water" d="M 62 8 L 92 12 L 96 36 L 70 30 Z"/>
|
||||
</svg>
|
||||
|
||||
<!-- pins overlay: % coords relative to .map-block -->
|
||||
<div class="map-pin" style="left:32%; top:48%;">
|
||||
<div class="dot"></div><div class="line"></div>
|
||||
<div class="card"><div class="name">大昭寺</div><span class="meta">DAY 1</span></div>
|
||||
</div>
|
||||
<div class="map-pin accent" style="left:62%; top:38%;">
|
||||
<div class="dot"></div><div class="line"></div>
|
||||
<div class="card"><div class="name">布达拉宫</div><span class="meta">DAY 2 · 18:40 SUNSET</span></div>
|
||||
</div>
|
||||
|
||||
<div class="map-legend">LHASA · 拉萨城关 · 1:8K</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
The SVG paths are stylized, not GPS-accurate. **Don't** try to trace OpenStreetMap by hand — this map is a graphic device, not a wayfinding tool. Sketch the major axes that frame the pins.
|
||||
|
||||
Layer order in the SVG (back to front):
|
||||
1. `.map-water` polygons (rivers, lakes, parks)
|
||||
2. `.map-coast` (boundary)
|
||||
3. `.map-grid` (optional reference grid lines)
|
||||
4. `.map-road` (transport lines)
|
||||
|
||||
Pins sit *outside* the SVG, as HTML siblings — they get the `.frame-shot` treatment for free.
|
||||
|
||||
### Mode T · Mapbox Static Image (signed token)
|
||||
|
||||
Real raster tiles, desaturated and tinted to match the deck. Use when the content is travel / hiking and you need to show actual terrain. Requires `MAPBOX_ACCESS_TOKEN` in the build env.
|
||||
|
||||
```
|
||||
https://api.mapbox.com/styles/v1/mapbox/light-v11/static/
|
||||
pin-s-1+555555(116.404,39.915),
|
||||
pin-l-2+1936b3(116.421,39.918)
|
||||
/116.412,39.916,14,0/1200x675@2x
|
||||
?access_token=YOUR_TOKEN
|
||||
```
|
||||
|
||||
```html
|
||||
<div class="map-block r-16x10 tone-paper">
|
||||
<img src="https://api.mapbox.com/styles/v1/mapbox/light-v11/static/.../1200x675@2x?access_token=..." alt="Lhasa walking route">
|
||||
|
||||
<!-- pins overlay (calculate % from mapbox bounds) -->
|
||||
<div class="map-pin" style="left:34%; top:52%;">...</div>
|
||||
<div class="map-pin accent" style="left:64%; top:42%;">...</div>
|
||||
|
||||
<div class="map-legend">LHASA · MAPBOX LIGHT</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Editorial uses `tone-paper` (multiply-blend, saturation 36%). Swiss uses `tone-paper` with saturation 0 (pure greyscale). Don't show the raw Mapbox colour-saturated style — it fights the deck.
|
||||
|
||||
**Style allowlist** for the URL — keep it monochrome:
|
||||
- `mapbox/light-v11`
|
||||
- `mapbox/dark-v11`
|
||||
- `mapbox/streets-v12` (only with `tone-paper`, never raw)
|
||||
|
||||
Never use `outdoors-v12` or `satellite-v9` — too colourful, will clash with both styles.
|
||||
|
||||
### Mode O · OpenStreetMap tile composite (fallback)
|
||||
|
||||
Free, no token. Reach for this only if you don't have a Mapbox token and the schematic doesn't carry the message. Render server-side via `staticmaps` npm package or similar — not covered here. Quality is lower than Mapbox.
|
||||
|
||||
## Hard rules
|
||||
|
||||
- **No pin labels on the SVG**. Names live in `.map-pin .card`, never as SVG `<text>`. Keeps font rendering consistent and avoids vector-text scaling issues.
|
||||
- **Max 6 pins per board**. More than that, the cards collide. Use a relations / index card to list secondary points.
|
||||
- **One accent pin maximum**. Multiple accents kill the visual hierarchy.
|
||||
- **Pins must not overlap cards**. Test in browser first — if two cards are within 80 px on the long axis, alternate `.left` placement.
|
||||
- **No live JavaScript map**. Social cards are static PNGs, MapLibre is wasted weight. The PPT skill has an interactive variant — don't port it here.
|
||||
|
||||
## Pin placement playbook
|
||||
|
||||
The `.map-pin` element uses `left:X%; top:Y%;` to anchor on its centre. The card grows to the right by default; add `.left` to flip:
|
||||
|
||||
```html
|
||||
<div class="map-pin left" style="left:78%; top:30%;">
|
||||
<div class="dot"></div><div class="line"></div>
|
||||
<div class="card"><div class="name">车公庄</div><span class="meta">START</span></div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Rule of thumb:
|
||||
- Pin sits in left 60% of canvas → card opens right (default).
|
||||
- Pin sits in right 60% of canvas → card opens left (`.left`).
|
||||
- Two pins close to each other → alternate sides so cards don't stack.
|
||||
|
||||
## Recipe routing
|
||||
|
||||
Map block fits into existing recipes; it doesn't get its own.
|
||||
|
||||
| Recipe | How the map fits |
|
||||
| --------------- | --------------------------------------------------------------- |
|
||||
| M01 split | Top half = `.map-block r-16x9`; bottom half = explanatory text. |
|
||||
| M11 marginalia | Main column = `.map-block r-3x4`; aside lists relation cards. |
|
||||
| M14 pipeline | One step contains a small map (r-16x10) showing that step's location. |
|
||||
| S02 two signals | One signal cell holds a map; the other holds the data table. |
|
||||
| S08 image hero | Replace the hero photo with `.map-block r-16x10`. |
|
||||
|
||||
Don't invent a "map-only" page — the map always pairs with text that says **why** the spatial relationship matters.
|
||||
|
||||
## Tone tokens
|
||||
|
||||
| Token | Editorial behaviour | Swiss behaviour |
|
||||
| ------------- | ------------------------------------------------ | --------------------------------------------- |
|
||||
| (none) | Raw — only use for SVG schematic. | Raw — only use for SVG schematic. |
|
||||
| `tone-paper` | Multiply blend on warm paper. Default for travel.| Hard greyscale. Default for everything. |
|
||||
| `tone-ink` | Brightness 62%, saturation 18%. Dark deck pages. | Brightness 58%, saturation 0%. Dark posters. |
|
||||
|
||||
Tone only affects `> img` children, not the SVG schematic.
|
||||
|
||||
## Common mistakes
|
||||
|
||||
- **Pasting Google Maps screenshots** — wrong tone, has UI chrome, will look out of place. Use Mapbox Static or schematic.
|
||||
- **Tracing a real map into SVG** — schematic should *abstract*, not replicate. If a viewer can guess the city from your SVG alone, you over-traced.
|
||||
- **Tiny pin cards** — `.card .name` is 15-16 px minimum. Cut the name if it overflows; never shrink.
|
||||
- **Accent on every pin** — defeats the highlight system. Pick one most-important point.
|
||||
@@ -0,0 +1,122 @@
|
||||
# Platform Specs
|
||||
|
||||
Use high-resolution exports. The user can downsample later.
|
||||
|
||||
## Xiaohongshu / Rednote
|
||||
|
||||
Default size:
|
||||
|
||||
- `1080 x 1440`
|
||||
- Ratio: `3:4`
|
||||
- Export: PNG for text-heavy images, JPEG only when photo-only and file size matters.
|
||||
|
||||
Safe area:
|
||||
|
||||
- Side margin: 72-96px.
|
||||
- Top margin: 72-112px.
|
||||
- Bottom margin: 80-120px.
|
||||
- Keep all text and key objects inside the safe area.
|
||||
|
||||
Recommended set:
|
||||
|
||||
- 1 cover.
|
||||
- 4-8 content pages.
|
||||
- 1 summary or checklist page if the article benefits from it.
|
||||
|
||||
Naming:
|
||||
|
||||
```text
|
||||
output/xhs-01-cover.png
|
||||
output/xhs-02-<topic>.png
|
||||
output/xhs-03-<topic>.png
|
||||
...
|
||||
```
|
||||
|
||||
Cover structure:
|
||||
|
||||
- Big title with a sharp hook.
|
||||
- One strong visual: supplied image, screenshot, generated photo, or product object.
|
||||
- Bottom line with 3-5 key points or a compact issue strip.
|
||||
- Avoid long subtitles. Put nuance in later pages.
|
||||
|
||||
Content page structure:
|
||||
|
||||
- One idea per page.
|
||||
- 12-30 Chinese characters for the title when possible.
|
||||
- 2-4 short bullet fragments or one concise paragraph.
|
||||
- If a page has a screenshot, reduce the text and give the screenshot enough area.
|
||||
- If lower space is empty across pages, combine pages or add a functional element such as checklist, comparison row, quote, or image evidence.
|
||||
|
||||
## WeChat Official Account Cover Pair
|
||||
|
||||
Generate a pair: one `21:9` main cover and one `1:1` square cover. Build both in the same HTML file, and include a combined preview section that places them together for visual checking.
|
||||
|
||||
### 21:9 Main Cover
|
||||
|
||||
Default size:
|
||||
|
||||
- `2100 x 900`
|
||||
- Ratio: `21:9`
|
||||
|
||||
Use:
|
||||
|
||||
- Main article cover.
|
||||
- Full or near-full headline, subtitle, and visual evidence.
|
||||
- Keep title readable near center-left or within a clear safe band.
|
||||
- Avoid an empty middle. Increase title scale, image scale, or spacing if the center feels hollow.
|
||||
|
||||
### 1:1 Cover
|
||||
|
||||
Default size:
|
||||
|
||||
- `1080 x 1080`
|
||||
- Ratio: `1:1`
|
||||
|
||||
Default style:
|
||||
|
||||
- Short title only, simplified from the long title.
|
||||
- Big type, center aligned.
|
||||
- No image unless the user explicitly asks for one.
|
||||
- No subtitle by default.
|
||||
- Strong contrast and enough breathing room.
|
||||
|
||||
Short-title rule:
|
||||
|
||||
- Extract the core object and action from the long title.
|
||||
- Keep it to roughly 4-10 Chinese characters, or 2 short lines when needed.
|
||||
- Do not squeeze the full `21:9` title into the square.
|
||||
|
||||
Example:
|
||||
|
||||
```text
|
||||
Long: 开源了一个 Skill,让 AI 接管你屏幕边那张便签纸
|
||||
Square: AI 接管便签纸
|
||||
```
|
||||
|
||||
Naming:
|
||||
|
||||
```text
|
||||
output/wechat-21x9-cover.png
|
||||
output/wechat-1x1-cover.png
|
||||
output/wechat-cover-pair-preview.png
|
||||
```
|
||||
|
||||
## Screenshot And Photo Placement
|
||||
|
||||
For supplied screenshots/photos:
|
||||
|
||||
- Put originals in `assets/`.
|
||||
- Use CSS `object-fit:cover` only when cropping is safe.
|
||||
- Use CSS `object-fit:contain` for UI screenshots, dense text, code, tables, or app windows.
|
||||
- Set `object-position` deliberately: top for long UI when top matters, center for objects, 35%-45% vertical for portraits.
|
||||
- Do not pin images to the canvas edge unless the design intentionally uses bleed.
|
||||
|
||||
## Final Response Media
|
||||
|
||||
In Codex desktop, local media can be shown with absolute paths:
|
||||
|
||||
```markdown
|
||||

|
||||
```
|
||||
|
||||
Do this for the most important images, especially the cover and any pages the user asked to inspect.
|
||||
@@ -0,0 +1,85 @@
|
||||
# Portrait Fill Rules
|
||||
|
||||
3:4 social images have much more vertical space than a horizontal PPT slide. A layout that works in 16:9 often becomes a thin strip in 3:4. Solve that at the planning stage.
|
||||
|
||||
## Vertical Zones
|
||||
|
||||
Think of a 1080x1440 Rednote image as five zones:
|
||||
|
||||
| Zone | Typical Height | Role |
|
||||
| --- | --- | --- |
|
||||
| Header/meta | 56-90px | issue label, category, page |
|
||||
| Title/lead | 240-420px | hook and claim |
|
||||
| Evidence/body | 520-760px | image, ledger, diagram, comparison |
|
||||
| Bottom strip | 90-180px | captions, checklist, summary |
|
||||
| Footer | 52-86px | issue/page metadata |
|
||||
|
||||
Not every page needs all five, but every page needs an intentional vertical composition.
|
||||
|
||||
## Underfilled Page Smells
|
||||
|
||||
Revise if:
|
||||
|
||||
- A table or ledger occupies less than 45% of the canvas height.
|
||||
- The lower 25% of the page is empty without being an atmospheric hero page.
|
||||
- Four list items are rendered as short rows with large blank space below.
|
||||
- A screenshot is small even though it is the evidence.
|
||||
- Body copy is centered in the middle with no top/bottom rhythm.
|
||||
|
||||
## Fixes For Thin Tables
|
||||
|
||||
When a table is too short:
|
||||
|
||||
1. Increase row height to 118-170px.
|
||||
2. Add a left marginal column with large numbers, keywords, or category labels.
|
||||
3. Add a pull quote column beside the table.
|
||||
4. Add a top or bottom issue strip with 2-3 consequences.
|
||||
5. Convert the table to M08 Tall Ledger.
|
||||
6. If there are only 2-3 points, use M04 Pull Quote or M09 Atmospheric Thesis instead of a table.
|
||||
|
||||
## Fixes For Sparse Text
|
||||
|
||||
If a page has only one core sentence:
|
||||
|
||||
- Use M09 Atmospheric Thesis with visible WebGL/ink background.
|
||||
- Make the sentence the hero, not a small paragraph.
|
||||
- Add one small source/context row.
|
||||
- Use dark/ink page if the package needs rhythm.
|
||||
|
||||
## Fixes For Screenshot Pages
|
||||
|
||||
If screenshot content matters:
|
||||
|
||||
- Give it 45%-65% of the page height.
|
||||
- Put only one key sentence above it.
|
||||
- Use a bottom caption band instead of a side paragraph.
|
||||
- Crop carefully; preserve readable UI labels.
|
||||
|
||||
## Page Rhythm
|
||||
|
||||
For a 7-page Rednote set, use at least 5 distinct shapes:
|
||||
|
||||
- Cover / feature image.
|
||||
- Essay split.
|
||||
- Tall ledger.
|
||||
- Evidence screenshot.
|
||||
- Pull quote or atmospheric thesis.
|
||||
- Checklist/comparison.
|
||||
- Closing note.
|
||||
|
||||
Avoid repeating `title + lead + 3 rows` more than twice in one set.
|
||||
|
||||
## Minimum Occupancy
|
||||
|
||||
As a rough rule, the active composition should occupy at least 78% of the page height.
|
||||
|
||||
This can include:
|
||||
|
||||
- Large type.
|
||||
- Images/screenshots.
|
||||
- Ledger rows.
|
||||
- Background atmosphere on hero pages.
|
||||
- Caption bands.
|
||||
- Marginalia columns.
|
||||
|
||||
Whitespace is good only when it is designed. Empty leftover space is not.
|
||||
@@ -0,0 +1,172 @@
|
||||
# Production Workflow
|
||||
|
||||
## Recommended Folder Shape
|
||||
|
||||
Create a task folder under the current workspace:
|
||||
|
||||
```text
|
||||
social-card-<slug>/
|
||||
index.html
|
||||
render.cjs
|
||||
assets/
|
||||
output/
|
||||
```
|
||||
|
||||
Use descriptive slugs:
|
||||
|
||||
- `social-card-doubao-input`
|
||||
- `social-card-hiking-outfit`
|
||||
- `wechat-ai-card-skill-cover`
|
||||
|
||||
## HTML/CSS Rendering Pattern
|
||||
|
||||
Build one HTML file containing all frames:
|
||||
|
||||
```html
|
||||
<main class="sheet">
|
||||
<section class="poster xhs" id="xhs-01">...</section>
|
||||
<section class="poster xhs" id="xhs-02">...</section>
|
||||
<section class="cover wechat wide" id="wechat-21x9">...</section>
|
||||
<section class="cover wechat square" id="wechat-1x1">...</section>
|
||||
<section class="wechat-pair-preview" id="wechat-pair-preview">
|
||||
<div class="preview-wide">...</div>
|
||||
<div class="preview-square">...</div>
|
||||
</section>
|
||||
</main>
|
||||
```
|
||||
|
||||
Each frame must have stable dimensions:
|
||||
|
||||
```css
|
||||
.xhs {
|
||||
width: 1080px;
|
||||
height: 1440px;
|
||||
}
|
||||
|
||||
.wechat.wide {
|
||||
width: 2100px;
|
||||
height: 900px;
|
||||
}
|
||||
|
||||
.wechat.square {
|
||||
width: 1080px;
|
||||
height: 1080px;
|
||||
}
|
||||
|
||||
.wechat-pair-preview {
|
||||
width: 2400px;
|
||||
min-height: 1180px;
|
||||
}
|
||||
```
|
||||
|
||||
Use `box-sizing:border-box`, fixed safe margins, and `overflow:hidden`.
|
||||
|
||||
For WeChat covers:
|
||||
|
||||
- Compose `wechat-21x9` and `wechat-1x1` as separate source frames.
|
||||
- Also include `wechat-pair-preview` in the same HTML so the pair can be inspected together.
|
||||
- Export the two real deliverables separately.
|
||||
- Export the pair preview only when helpful for review.
|
||||
- The `1:1` cover should use a simplified title derived from the long title, not a crop or text squeeze from the `21:9` frame.
|
||||
|
||||
For electronic-magazine pages, place background canvases inside each `.poster` instead of relying only on CSS color:
|
||||
|
||||
```html
|
||||
<section class="poster magazine hero" id="xhs-01">
|
||||
<canvas class="mag-bg" data-bg="ink-flow"></canvas>
|
||||
<div class="grain"></div>
|
||||
<div class="content">...</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
The skill includes a reusable helper at `assets/magazine-bg-webgl.js`. Copy or inline it into the generated project when a WebGL background is useful.
|
||||
|
||||
## Rendering
|
||||
|
||||
Use Playwright or an equivalent browser screenshot workflow:
|
||||
|
||||
1. Open `index.html`.
|
||||
2. Wait for fonts and images.
|
||||
3. Screenshot each frame node by id.
|
||||
4. Save to `output/`.
|
||||
5. Verify dimensions.
|
||||
|
||||
If using WebGL or procedural canvas backgrounds:
|
||||
|
||||
- Wait at least 500-900ms before screenshots so the canvas has rendered.
|
||||
- Use deterministic seeds or a fixed time when repeatability matters.
|
||||
- On normal content pages, keep background opacity subtle.
|
||||
- On cover, divider, pull-quote, and sparse pages, let the atmosphere show more strongly.
|
||||
|
||||
Example render logic:
|
||||
|
||||
```js
|
||||
const targets = [
|
||||
["#xhs-01", "xhs-01-cover.png"],
|
||||
["#xhs-02", "xhs-02-point.png"],
|
||||
["#wechat-21x9", "wechat-21x9-cover.png"],
|
||||
["#wechat-1x1", "wechat-1x1-cover.png"],
|
||||
["#wechat-pair-preview", "wechat-cover-pair-preview.png"],
|
||||
];
|
||||
```
|
||||
|
||||
If a local dev server is needed for assets or font loading, start it and tell the user the URL. If `file://` rendering works, no server is required.
|
||||
|
||||
## Verification Commands
|
||||
|
||||
Useful checks on macOS:
|
||||
|
||||
```bash
|
||||
sips -g pixelWidth -g pixelHeight output/*.png
|
||||
```
|
||||
|
||||
For visual inspection in Codex:
|
||||
|
||||
- Use image viewing tools for local PNGs.
|
||||
- Show final PNGs inline with absolute paths.
|
||||
|
||||
## Screenshot Treatment
|
||||
|
||||
Programmatic framing is preferred for user-provided screenshots:
|
||||
|
||||
- Create a clean target-ratio frame.
|
||||
- Add plain white, refined grey, or paper background. Do not add page-wide grid/dot backgrounds unless the user explicitly asks for a technical blueprint look.
|
||||
- Place screenshot inside with safe padding.
|
||||
- Preserve readable text.
|
||||
- Do not redraw the screenshot unless the user asked for redesign.
|
||||
|
||||
For Swiss:
|
||||
|
||||
- Straight corners.
|
||||
- No shadow by default.
|
||||
- Hairline only if the screenshot edge disappears.
|
||||
|
||||
For editorial magazine:
|
||||
|
||||
- Small radius or subtle shadow is allowed, but avoid SaaS marketing-card styling.
|
||||
|
||||
## Generated Images
|
||||
|
||||
When generating missing visuals:
|
||||
|
||||
- Generate only the raw visual asset.
|
||||
- Keep text out of generated images.
|
||||
- Match the page role and style mode.
|
||||
- Save generated assets into `assets/` and place them in the HTML.
|
||||
- Generate only the pages that need it, usually 1-2 images for a set.
|
||||
|
||||
## Accessibility And Readability
|
||||
|
||||
- Use strong contrast for all text.
|
||||
- Do not place long text over busy photos.
|
||||
- If text must sit over photo, use a solid ink/paper block or a high-contrast strip, not a blur blob.
|
||||
- Avoid negative letter spacing in Chinese body text.
|
||||
- Use line-height that lets Chinese breathe: roughly 1.08-1.22 for big titles, 1.35-1.55 for body.
|
||||
|
||||
## Common Fixes
|
||||
|
||||
- Cover feels empty: enlarge title, enlarge image, or add a functional bottom strip.
|
||||
- Screenshot too small: reduce side text, give screenshot 55%-70% of the canvas.
|
||||
- Lower area empty: read `portrait-fill.md`; merge pages, add a full-height ledger, use a larger evidence image, add a marginal quote column, or switch to an atmospheric thesis page.
|
||||
- Style feels generic: add issue metadata, better type hierarchy, a stronger evidence image, richer WebGL/ink atmosphere, or more intentional content dividers.
|
||||
- Text overflows: shorten copy before shrinking type.
|
||||
@@ -0,0 +1,83 @@
|
||||
# QA Checklist
|
||||
|
||||
Run this before final delivery.
|
||||
|
||||
## Dimensions
|
||||
|
||||
- Rednote images are `1080 x 1440`.
|
||||
- WeChat 21:9 cover is `2100 x 900`.
|
||||
- WeChat 1:1 cover is `1080 x 1080`.
|
||||
- WeChat pair preview exists in the same HTML when WeChat covers are requested.
|
||||
- File names are stable and ordered.
|
||||
|
||||
## Text
|
||||
|
||||
- No text overflows or touches the edge.
|
||||
- No content collides with `.foot` / `.issue-strip`. If body copy or a closing line is overlapping the page footer, the footer is probably `position: absolute` while content above grew. Switch to flex `margin-top: auto` (see Anti-pattern C in `style-system.md`).
|
||||
- Cover title is readable on a phone at thumbnail size.
|
||||
- Body text is not smaller than it needs to be.
|
||||
- Chinese line breaks are intentional.
|
||||
- Important product names, English terms, and code snippets are spelled correctly.
|
||||
- Captions match the source text; no invented facts.
|
||||
|
||||
## Layout
|
||||
|
||||
- Each page has one clear focal point.
|
||||
- Pages do not all use the same structure.
|
||||
- Lower empty space is either intentional or fixed.
|
||||
- Images and screenshots align to the grid.
|
||||
- Screenshot pages give the screenshot enough area.
|
||||
- 1:1 WeChat cover uses a simplified short title and is composed separately, not blindly cropped.
|
||||
|
||||
### 4-band Density Check (3:4 only — run after render)
|
||||
|
||||
Open the rendered PNG. Mentally divide it into 4 horizontal bands of 360px each (0-25%, 25-50%, 50-75%, 75-100%). For each band, classify as:
|
||||
|
||||
- **Filled** — contains text, image, data, or rule.
|
||||
- **Justified empty** — empty for a stated reason: hero-image breathing (M01/M16), single-sentence statement (M04/M13), leading/trailing margin (top 8% / bottom 8%).
|
||||
- **Under-filled** — empty with no reason. **Any single under-filled band > 15% canvas height (>216px) is a fail.**
|
||||
|
||||
A poster passes when:
|
||||
|
||||
1. Total Filled + Justified empty ≥ 100%.
|
||||
2. Filled bands cover ≥ 75% canvas height (≥ 1080px of 1440px).
|
||||
3. No two adjacent bands are both "justified empty" — that creates a >25% void mid-poster.
|
||||
|
||||
If failing: don't shrink the canvas, don't add decorative blobs. Either expand copy (more ledger items, longer paragraphs, supporting evidence row, marginalia column) or switch recipe (M07 → M04 for genuinely-short content; M03 → M11 to add a marginal column; thin ledger → M08 Tall Ledger with bigger rows).
|
||||
|
||||
## Style
|
||||
|
||||
- Package uses one visual system.
|
||||
- Swiss identity test passes for every Swiss poster (see `style-system.md` "Style Identity Test"). In particular: every display title >=72px uses a typed class with weight <=300; no serif font is loaded; only one accent color is used. A bold 90px headline is not Swiss.
|
||||
- Editorial identity test passes for every Editorial poster: at least one atmosphere layer beyond a flat fill (paper grain / ink wash / WebGL); serif display family on the title; at least one of large photo well, serif pull quote, marginalia column, or true ledger structure. A flat paper with serif title + mono pills everywhere is Swiss-in-disguise.
|
||||
- Swiss uses one accent color only.
|
||||
- Magazine style uses restrained paper/ink tones.
|
||||
- No random SVG blobs, ovals, drops, circles, stickers, or decorative gradients.
|
||||
- No nested cards.
|
||||
- No excessive rounded corners.
|
||||
|
||||
## Images
|
||||
|
||||
- Supplied images are not distorted.
|
||||
- Faces, hardware, product UI, and key text are not accidentally cropped.
|
||||
- Screenshots remain readable.
|
||||
- Generated images do not contain unwanted text, logos, page numbers, or poster borders.
|
||||
- Photo crops feel intentional.
|
||||
- For any image fetched from the web (Pexels / Unsplash / Flickr CC / Wallhaven / direct search): the source URL is recorded in `assets/SOURCES.md`, and the user has been asked whether to add an in-image attribution caption. The user's answer is honored. Flickr CC attribution preserves the author name when the user opts in.
|
||||
|
||||
## Text-On-Image (when applicable)
|
||||
|
||||
Run these only for posters where text touches a photo (full-bleed cover, large image well, generated overlay). See `references/image-overlay.md`.
|
||||
|
||||
- Image area ≥60% of canvas → A, B, or C contrast mask is present (not a flat black rectangle behind text).
|
||||
- Subject map is documented as an HTML comment next to the hero block (face / focal feature location + safe zones).
|
||||
- No display title (≥72 px) overlaps a face, hand, or key product feature.
|
||||
- `object-position` was chosen from the subject-location table, not left at default for face shots.
|
||||
- Thumbnail test: downscale the rendered PNG to 360 px wide and confirm the title is still legible without strain.
|
||||
|
||||
## Final Response
|
||||
|
||||
- Include the output path.
|
||||
- Show the main cover inline when useful.
|
||||
- Mention verification performed.
|
||||
- Mention any limitations, such as low-resolution source assets.
|
||||
@@ -0,0 +1,148 @@
|
||||
# Screenshot Treatment
|
||||
|
||||
When the user supplies an app / web / code / dashboard screenshot, **do not** drop it raw into a `.frame-img`. The aspect ratio mismatch crops UI and the harsh edge looks SaaS-y. Use `.frame-shot` instead — a sibling class added to both seed templates.
|
||||
|
||||
## When to reach for it
|
||||
|
||||
- App / Web UI capture — anything with a status bar, tab bar, toolbar, or window chrome.
|
||||
- Code / terminal screenshots.
|
||||
- Dashboard / chart screenshots that need to keep every label readable.
|
||||
- IDE captures where text density matters more than composition.
|
||||
|
||||
For **photographic** content (people, scenery, products) — keep using `.frame-img`. The treatments below assume a pixel-perfect UI source where contain-fit is non-negotiable.
|
||||
|
||||
## Anatomy
|
||||
|
||||
```
|
||||
.frame-shot.r-{ratio}.corners-{sq|sm|md}.shadow-{none|soft|ed}.bg-{paper|grid|dot|grey-1|ink}.inset-{none|sub|bal}
|
||||
└─ <img src="…"> (object-fit: contain by default)
|
||||
```
|
||||
|
||||
Optional wrapping:
|
||||
|
||||
```
|
||||
.device-browser
|
||||
└─ .frame-shot.r-16x10.bg-paper
|
||||
└─ <img>
|
||||
|
||||
.device-phone
|
||||
└─ .frame-shot.r-3x4.bg-paper
|
||||
└─ <img>
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
Pick six values before writing the markup. Treat this like the M16 cover decision tree — pick once, don't fiddle mid-build.
|
||||
|
||||
### 1. `r-*` ratio (required, matches slot)
|
||||
|
||||
| Class | Use |
|
||||
| ---------- | --------------------------------------------------------- |
|
||||
| `r-16x10` | Default for app / web shots, looks like a real window |
|
||||
| `r-16x9` | Landscape video / dashboard / wide chart |
|
||||
| `r-4x3` | Classic desktop window, legacy app |
|
||||
| `r-3x2` | DSLR-style — only if the source is photographic UI mockup |
|
||||
| `r-1x1` | App icon / square widget |
|
||||
| `r-3x4` | Mobile portrait shot (pair with `.device-phone`) |
|
||||
| `r-21x9` | Multi-monitor / ultra-wide / WeChat hero |
|
||||
|
||||
### 2. `corners-*` (style-locked default)
|
||||
|
||||
- **Swiss** default: `corners-sq`. Use `corners-sm` only if the slot has surrounding shadow or chrome.
|
||||
- **Editorial** default: `corners-sm` (6 px). Bump to `corners-md` (14 px) for "cutout" feel on paper.
|
||||
|
||||
Never go above 14 px — anything bigger reads as iOS marketing.
|
||||
|
||||
### 3. `shadow-*` (style-locked default)
|
||||
|
||||
- Swiss → `shadow-none` 90% of the time. `shadow-soft` only on screenshots that float on `bg-grid` / `bg-dot`. `shadow-ed` adds a `1px` outline as part of the shadow — reserve for hero shots.
|
||||
- Editorial → `shadow-soft` on `bg-paper-2` is the warm default. `shadow-ed` for hero shots.
|
||||
|
||||
### 4. `bg-*` (the screenshot "stage")
|
||||
|
||||
| Token | Swiss role | Editorial role |
|
||||
| ------------ | ------------------- | ---------------------- |
|
||||
| `bg-paper` | Default plain stage | Same |
|
||||
| `bg-paper-2` | n/a | Default warm stage |
|
||||
| `bg-grey-1` | Default plain stage | n/a |
|
||||
| `bg-grid` | Engineering / data | Field-notes engineering |
|
||||
| `bg-dot` | Subtle structure | Subtle structure |
|
||||
| `bg-ink` | Dark-mode UI shot | Dark-mode UI shot |
|
||||
|
||||
Backgrounds are **never** accent-coloured. If the screenshot needs an accent emphasis, add a `.t-cat` chip or `.kicker` next to it — don't tint the stage.
|
||||
|
||||
### 5. `inset-*` (padding between shot and stage)
|
||||
|
||||
- `inset-none` — image fills the frame. Use when the screenshot itself already has window chrome.
|
||||
- `inset-sub` (Swiss 20 px / Editorial 24 px) — default. Lets the stage breathe.
|
||||
- `inset-bal` (Swiss 48 px / Editorial 56 px) — when the shot is busy and needs to feel calm.
|
||||
|
||||
### 6. `fit-cover` (override)
|
||||
|
||||
Default is `object-fit: contain` — this is the whole point of `.frame-shot`. **Only** add `.fit-cover` when:
|
||||
- The slot is a hero where exact pixels of the source don't matter (e.g. a code shot used as a background pattern).
|
||||
- The user explicitly says they want the shot cropped.
|
||||
|
||||
## Device chrome
|
||||
|
||||
Two wrapper classes ship with the seeds. They wrap a `.frame-shot`:
|
||||
|
||||
### `.device-browser`
|
||||
|
||||
Adds a 32–36 px chrome bar with traffic-light dots. Use for web / desktop app captures.
|
||||
|
||||
```html
|
||||
<div class="device-browser">
|
||||
<div class="frame-shot r-16x10 bg-paper inset-none">
|
||||
<img src="assets/website.png" alt="Linear inbox">
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Pair with `shadow-soft` on the screenshot itself for a desk-photo feel.
|
||||
|
||||
### `.device-phone`
|
||||
|
||||
Wraps a 3:4 or 16:10 shot in an ink-coloured bezel with 18-24 px rounded inner corners. Use for mobile captures.
|
||||
|
||||
```html
|
||||
<div class="device-phone">
|
||||
<div class="frame-shot r-3x4 bg-paper inset-none">
|
||||
<img src="assets/app.png" alt="WeChat detail">
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
|
||||
Don't stack `corners-md` on top of `.device-phone` — the bezel already rounds the inner shot.
|
||||
|
||||
## Safe-area cropping
|
||||
|
||||
When the user delivers a full-screen capture (1290×2796 iOS / 1080×2400 Android / 1920×1080 desktop), do **not** show the status bar, dock, or browser tab strip unless that chrome is the subject. Crop before importing:
|
||||
|
||||
1. Trim the iOS / Android status bar (top 47-59 px on retina).
|
||||
2. Trim the home indicator / nav gesture bar (bottom 34 px on iOS).
|
||||
3. For desktop: trim everything above the page content unless wrapped in `.device-browser`.
|
||||
|
||||
If you can't crop ahead of time, use `object-position: center 6%` to bias the visible region downward — but this is a workaround, not the preferred path.
|
||||
|
||||
## Style cheat-sheet
|
||||
|
||||
Two recipes that cover 80% of cases.
|
||||
|
||||
**Swiss product demo** — pure stage, no shadow:
|
||||
```
|
||||
.frame-shot.r-16x10.corners-sq.shadow-none.bg-grey-1.inset-bal
|
||||
```
|
||||
|
||||
**Editorial deep-dive** — desk-photo warmth:
|
||||
```
|
||||
.frame-shot.r-16x10.corners-sm.shadow-soft.bg-paper-2.inset-sub
|
||||
```
|
||||
|
||||
For comparison shots (before / after), use **the same parameters** on both — different treatment between cells reads as inconsistency, not contrast.
|
||||
|
||||
## Validator
|
||||
|
||||
`validate-social-deck.mjs` doesn't have a screenshot-specific rule (yet). The existing R1 / R2 / R5 still apply: a `.frame-shot` that overflows or pushes the footer is still a fail.
|
||||
|
||||
If a deck mixes `.frame-img` and `.frame-shot` on the same poster, that's usually a smell — pick one approach per poster.
|
||||
@@ -0,0 +1,188 @@
|
||||
# Style System
|
||||
|
||||
This skill extracts Guizang PPT visual principles for static social images. It does not depend on the original PPT templates.
|
||||
|
||||
## Shared Rules
|
||||
|
||||
- Content shape decides layout. Do not pick a pretty layout first and invent content to fit it.
|
||||
- Use strong hierarchy: title, hook, evidence, caption, metadata.
|
||||
- Use real images as evidence or atmosphere, not decoration.
|
||||
- Avoid visible clutter: no random SVG circles, oval drops, blobs, bokeh, ornamental stickers, fake diagram decorations, or decorative gradients.
|
||||
- Keep all pages in a package visually related through grid, typography, palette, and recurring metadata.
|
||||
- Every page should have a clear focal point.
|
||||
|
||||
## Style ↔ content type are decoupled
|
||||
|
||||
The two modes below are **visual stances, not content categories**. Any topic can be rendered in either mode — what changes is the page's feel and which structural devices are available (ledger / marginalia / pull quote vs matrix / KPI tower / h-bar). Pick by editorial intent ("feature story" vs "release note" / "system explainer"), not by topic lookup. The lists below are *good fits*, not exhaustive.
|
||||
|
||||
## Mode A: Editorial Magazine x E-ink
|
||||
|
||||
Good fits: outdoor, lifestyle, reflective, humanistic, cultural, narrative — but also workplace essays, AI think-pieces, product retrospectives, anything that wants a slow magazine-feature pace.
|
||||
|
||||
Visual anchors:
|
||||
|
||||
- Serif or Songti-like display title plus quiet sans-serif body text.
|
||||
- Warm paper, deep ink, refined greys, restrained color.
|
||||
- WebGL or procedural ink/contour atmosphere, especially on covers, dividers, pull quotes, and sparse pages.
|
||||
- Documentary photography, field-note captions, issue labels, page numbers.
|
||||
- Large but purposeful whitespace.
|
||||
- Fine rules, magazine columns, image captions, pull quotes, and editorial contrast.
|
||||
- Subtle paper texture is allowed; it must not lower text readability.
|
||||
|
||||
Use one of the 6 magazine palettes in `theme-presets.md`. Do not improvise arbitrary warm paper colors. Five palettes are light (paper-and-ink); one — **Midnight Ink** — is the only sanctioned dark variant, reserved for content where the source imagery is already dark (game art, night photography, cinematic covers). Do not invent a second dark palette.
|
||||
|
||||
**Typography stance — "the larger, the lighter."** This rule is non-negotiable for Editorial. Display titles run at **weight 500** with **wide tracking** (`+.03em` to `+.04em`). Small text (kicker, meta, label) is the *only* place where weight 500 is paired with mono uppercase and wide letter-spacing (`+.20em` to `+.22em`). Body uses **serif-zh**, not sans. The anti-pattern — 700 to 900 weight display, sans body, negative tracking — collapses Editorial into a generic "infographic banner" look. If a page feels heavy or shouty, the title is too bold or the body switched to sans. See `local-tests/demo-showcase/editorial.html` for source-of-truth.
|
||||
|
||||
Layout patterns:
|
||||
|
||||
- Cover: big title top or left, large photo/image evidence, bottom checklist or issue-strip.
|
||||
- Feature page: one large image plus a narrow column of compressed explanation.
|
||||
- Checklist page: editorial header, numbered items, one supporting image crop or icon-free diagram.
|
||||
- Quote/takeaway page: large pull quote with small source/context row.
|
||||
- Comparison page: two-column tension, simple labels, one visual anchor.
|
||||
|
||||
Background rule:
|
||||
|
||||
- A flat paper color is not enough for this mode. Use a layered background from `background-systems.md`: paper base, subtle grain, ink wash or contour field, and optional WebGL canvas. The background should create atmosphere while keeping text readable.
|
||||
|
||||
## Mode B: Swiss International
|
||||
|
||||
Good fits: AI tools, product updates, engineering workflows, software explainers, release notes, comparison posts — but also travel ledgers, expense logs, fitness data, recipe step counts, anything that wants a engineered/quantified pace. Topic is not the gate; visual stance is.
|
||||
|
||||
Visual anchors:
|
||||
|
||||
- Inter, Helvetica Neue, Noto Sans SC feeling.
|
||||
- Very light display weights for huge type; stronger weights for small labels.
|
||||
- Strict 12/16-column grid, left alignment, asymmetric whitespace.
|
||||
- White/off-white, black, refined greys, exactly one high-saturation accent.
|
||||
- Straight modules, hairline rules, no rounded cards, no shadows, no glassmorphism.
|
||||
|
||||
Use one of the 4 Swiss accent palettes in `theme-presets.md`. One package gets exactly one accent.
|
||||
|
||||
Rules:
|
||||
|
||||
- Use one accent only. Do not mix blue, yellow, green, and orange.
|
||||
- Avoid gradients. Use pure color blocks, hairline rules, and grid modules.
|
||||
- Headings usually sit on the top-left content axis, not center, except special square covers or explicit poster compositions.
|
||||
- Huge text should be lighter; small text should be heavier.
|
||||
- Images are proof blocks. Use straight edges and stable aspect-ratio containers.
|
||||
|
||||
Typography guidance:
|
||||
|
||||
| Role | Size Guidance | Weight |
|
||||
| --- | --- | --- |
|
||||
| Main cover title | 84-128px on 1080x1440 | 200-400 |
|
||||
| Page title | 52-82px | 300-500 |
|
||||
| Body copy | 28-42px | 400-500 |
|
||||
| Captions/meta | 20-28px | 500-650 |
|
||||
|
||||
Chinese titles are visually dense. Shorten first, then reduce size. Do not solve overflow by shrinking body text below readability.
|
||||
|
||||
## Image Rules
|
||||
|
||||
- Photos: crop with intent. Keep faces, hands, products, and main objects in safe areas.
|
||||
- Product screenshots: preserve text; use `object-fit:contain` when detail matters.
|
||||
- Hardware photos: make the object a first-viewport signal. The photo should be large enough to inspect.
|
||||
- Generated images: generate only the image content, not the final poster with text.
|
||||
- Do not make generated images include page chrome, titles, borders, captions, or fake UI unless required by the concept.
|
||||
|
||||
## Bad Smells
|
||||
|
||||
Revise if you see:
|
||||
|
||||
- A page that looks like a generic template with the article pasted in.
|
||||
- Large empty lower area across multiple pages.
|
||||
- Decorative shapes that do not explain anything.
|
||||
- Screenshots too small to read.
|
||||
- Inconsistent margins between pages.
|
||||
- Blue text on black or dark photo with poor contrast.
|
||||
- A 1:1 cover that is a cramped crop of a 21:9 cover.
|
||||
|
||||
## Style Identity Test
|
||||
|
||||
A poster compiles cleanly long before its style identity is right. Run this test on every page before delivering.
|
||||
|
||||
### Swiss identity test
|
||||
|
||||
A poster is Swiss only if **all four** hold:
|
||||
|
||||
1. Every large display title (>=72px on 1080x1440) uses a typed class from `components.md` (`.h-hero` / `.h-statement` / `.h-xl` / `.num-mega`). Its computed `font-weight` is `<=300`.
|
||||
2. No serif family is loaded in the document head. No element uses `font-family: serif` or `Noto Serif SC` / `Playfair Display`.
|
||||
3. Section separators are hairline rules (1-2px) or grid gutters, not card borders + drop shadows.
|
||||
4. Exactly one accent palette is in use. No mixed accents across pages.
|
||||
|
||||
If any one of these fails, the poster is not Swiss — it is generic editorial or "Swiss-flavored card". Fix it or relabel the package.
|
||||
|
||||
### Editorial identity test
|
||||
|
||||
A poster is Editorial only if **all three** hold:
|
||||
|
||||
1. The background has at least one atmosphere layer beyond a flat fill: paper grain, ink wash, frozen WebGL canvas, or contour field (see `background-systems.md`). A page-wide solid `#f3f0e8` with nothing on top is not Editorial.
|
||||
2. The display title uses a serif-zh / serif-en family (`Noto Serif SC` / `Songti SC` / `Playfair Display`).
|
||||
3. The poster contains at least one of: a large photo well, a serif pull-quote with em-italic English, a left/right marginalia column, or a ledger with real magazine row hierarchy.
|
||||
|
||||
If a poster has a serif title, mono labels everywhere, structured pill grids, and a flat paper background — it is **Swiss-with-a-serif**, not Editorial. Either add atmosphere + magazine structure, or switch the package to Swiss honestly.
|
||||
|
||||
## Anti-Patterns From Real Demos
|
||||
|
||||
These all rendered without errors and looked plausible in isolation, but failed once compared against a clean reference.
|
||||
|
||||
### Anti-pattern A: thick big title in Swiss
|
||||
|
||||
```html
|
||||
<!-- WRONG: inline 700-800 weight on a huge title -->
|
||||
<h1 style="font-size: 92px; font-weight: 800">如果只能留 5 个,我留这些。</h1>
|
||||
|
||||
<!-- RIGHT: typed class, automatic 200-300 weight -->
|
||||
<h1 class="h-statement">如果只能<br>留 <em>5 个</em>,<br>我留这些。</h1>
|
||||
```
|
||||
|
||||
"The larger, the lighter" is a hard rule. A 90px h1 at weight 700+ instantly downgrades the design from Swiss International to generic landing-page editorial. Always reach for `.h-hero` / `.h-statement` / `.h-xl` / `.num-mega`. Do not bypass them with inline `font-size` + `font-weight`.
|
||||
|
||||
### Anti-pattern B: Editorial without atmosphere
|
||||
|
||||
A page with all of the following looks Swiss-in-disguise even if you intended Editorial:
|
||||
|
||||
- Single flat paper color, no grain, no ink wash, no WebGL,
|
||||
- Mono labels (`IBM Plex Mono uppercase`) on every kicker, foot, pill, and row label,
|
||||
- A serif headline floating alone with no large image, pull quote, or marginalia column.
|
||||
|
||||
Fix by **one** of:
|
||||
|
||||
- Add the paper grain + ink-wash background per `background-systems.md`.
|
||||
- Replace mono labels with serif / italic micro copy.
|
||||
- Introduce a large photo or serif pull quote with column structure.
|
||||
- Switch the package to Swiss honestly — the content might want Swiss.
|
||||
|
||||
### Anti-pattern C: footer overlap (closing essay collides with `.foot`)
|
||||
|
||||
When `.foot` or `.issue-strip` is positioned with `position: absolute; bottom: ...`, any content above that grows past its expected height crashes through the footer. Use one of these safe patterns instead:
|
||||
|
||||
```css
|
||||
/* Pattern A — flex column. Foot is the last child, pushed by margin-top: auto. */
|
||||
.poster .pad { display: flex; flex-direction: column; height: 100%; }
|
||||
.poster .foot { margin-top: auto; }
|
||||
|
||||
/* Pattern B — grid with fixed footer row. */
|
||||
.poster .pad { display: grid; grid-template-rows: auto 1fr auto; height: 100%; }
|
||||
```
|
||||
|
||||
Both seed templates already use Pattern A. Preserve it. If a recipe truly needs an absolutely-positioned foot, reserve `padding-bottom: <foot-height + 24px>` on the content container.
|
||||
|
||||
### Anti-pattern D: full-bleed photo with title crossing the subject
|
||||
|
||||
The poster looks dramatic at 100% zoom and unreadable at thumbnail size. Two common subfailures:
|
||||
|
||||
- A hero photo covers the entire poster, the title sits directly on whatever pixel happens to be behind it. The image's own brightness varies across the canvas, so the title is legible in some bands and invisible in others.
|
||||
- A mask layer is present but only on one band (bottom), while the subject's face was pushed to the top by `object-position: center top`. The display title lands across the face.
|
||||
|
||||
Both pass HTML linting; both fail the thumbnail readability test.
|
||||
|
||||
Fix by following `image-overlay.md`:
|
||||
|
||||
1. **Add a mask layer** appropriate to where text lands — vertical falloff (top+bottom), side scrim (one column), or radial vignette (text fills the canvas).
|
||||
2. **Map the subject before placing the title.** Read the image, describe in plain language where the face/focal feature sits, record the subject map as an HTML comment next to the hero block. Place text only in documented safe zones.
|
||||
3. **Match `object-position` to subject location** — see the table in `image-overlay.md`. Never leave it at default for face / hero shots.
|
||||
4. **Thumbnail test** — render the PNG, downscale to 360 px wide, and look at the title. If it fights the photo, the mask is too thin; if the photo looks dead, the mask is too heavy.
|
||||
|
||||
This anti-pattern survives almost every other check because the HTML is valid, the image loads, and the title renders. The only way to catch it is to look at the rendered output at the size readers will actually see it.
|
||||
@@ -0,0 +1,208 @@
|
||||
# Theme Presets
|
||||
|
||||
Use one theme for one image package. Do not mix palettes across pages unless the user explicitly asks for a deliberate multi-chapter system.
|
||||
|
||||
## Editorial Magazine x E-ink Palettes
|
||||
|
||||
These are adapted from the Guizang PPT electronic-magazine mode for static Rednote and WeChat images.
|
||||
|
||||
### Ink Classic
|
||||
|
||||
Use for business commentary, AI essays, product thinking, and neutral editorial posts.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #f3f0e8;
|
||||
--paper-2: #ebe6da;
|
||||
--ink: #0a0a0b;
|
||||
--muted: #68625a;
|
||||
--line: rgba(10,10,11,.22);
|
||||
--accent: #111111;
|
||||
--accent-soft: #d8d2c6;
|
||||
}
|
||||
```
|
||||
|
||||
### Indigo Porcelain
|
||||
|
||||
Use for technology, research, data, AI infrastructure, and calm analytical writing.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #f2f4f5;
|
||||
--paper-2: #e5ebef;
|
||||
--ink: #0a1f3d;
|
||||
--muted: #5f6d78;
|
||||
--line: rgba(10,31,61,.20);
|
||||
--accent: #315d93;
|
||||
--accent-soft: #d7e1ec;
|
||||
}
|
||||
```
|
||||
|
||||
### Forest Ink
|
||||
|
||||
Use for hiking, outdoor, nature, sustainability, personal field notes, and grounded lifestyle posts.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #f5f1e8;
|
||||
--paper-2: #e8dfcf;
|
||||
--ink: #16251b;
|
||||
--muted: #5d665d;
|
||||
--line: rgba(22,37,27,.22);
|
||||
--accent: #2e6b4f;
|
||||
--accent-soft: #d4dfd2;
|
||||
}
|
||||
```
|
||||
|
||||
### Kraft Paper
|
||||
|
||||
Use for memory, craft, personal essays, old objects, creator notes, and warm low-tech topics.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #eedfc7;
|
||||
--paper-2: #dfc9a8;
|
||||
--ink: #2a1e13;
|
||||
--muted: #755f49;
|
||||
--line: rgba(42,30,19,.24);
|
||||
--accent: #9b5a2e;
|
||||
--accent-soft: #d5b58f;
|
||||
}
|
||||
```
|
||||
|
||||
### Dune
|
||||
|
||||
Use for design, object studies, portfolio-like covers, gallery tone, and restrained aesthetic posts.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #f0e6d2;
|
||||
--paper-2: #ded0b7;
|
||||
--ink: #1f1a14;
|
||||
--muted: #6f6557;
|
||||
--line: rgba(31,26,20,.22);
|
||||
--accent: #8f7650;
|
||||
--accent-soft: #d4c2a4;
|
||||
}
|
||||
```
|
||||
|
||||
### Midnight Ink
|
||||
|
||||
The **only** official dark Editorial palette. Use for game key art, night photography, cinematic covers, dark-themed cultural pieces — content whose source imagery is already dark and would be diminished by paper backgrounds. Do not improvise other dark palettes; if Midnight Ink does not fit, pick a different mode (Editorial dark is not a universal switch).
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #0e0d0c;
|
||||
--paper-2: #1a1714;
|
||||
--ink: #ece2cf;
|
||||
--muted: #9a8c75;
|
||||
--line: rgba(236,226,207,.22);
|
||||
--accent: #d4a04a;
|
||||
--accent-soft: #3a2a14;
|
||||
}
|
||||
```
|
||||
|
||||
Midnight Ink **must** also override two background layers — light-paper math does not carry over:
|
||||
|
||||
```css
|
||||
[data-theme="midnight-ink"] .grain {
|
||||
opacity: .26;
|
||||
mix-blend-mode: screen;
|
||||
background-image: radial-gradient(rgba(255,244,214,.10) 1px, transparent 1px);
|
||||
}
|
||||
[data-theme="midnight-ink"] .paper-wash {
|
||||
background:
|
||||
radial-gradient(80% 50% at 28% 16%, rgba(212,160,74,.12), transparent 64%),
|
||||
radial-gradient(70% 60% at 80% 86%, rgba(60,40,20,.20), transparent 72%),
|
||||
linear-gradient(180deg, rgba(236,226,207,.02), rgba(0,0,0,.32));
|
||||
}
|
||||
[data-theme="midnight-ink"] .frame-img {
|
||||
background: #18120f;
|
||||
box-shadow: 0 0 0 1px rgba(236,226,207,.10);
|
||||
}
|
||||
```
|
||||
|
||||
The seed `template-editorial-card.html` ships these overrides — just switch `data-theme` and they apply automatically.
|
||||
|
||||
Magazine palette rules:
|
||||
|
||||
- Use `--paper` as the main background and `--ink` as primary type.
|
||||
- Use `--accent` sparingly: section marker, page number, pull quote rule, or one highlighted phrase.
|
||||
- `--paper-2` can support photo wells, issue strips, or checklist bands.
|
||||
- Light palettes (the first five): do not turn into beige-on-beige. Maintain real contrast.
|
||||
- Midnight Ink: do not stack opaque cards or fills on the page. Dark Editorial relies on photo bleeds + warm gilt accent for hierarchy, not background blocks.
|
||||
|
||||
## Swiss International Palettes
|
||||
|
||||
These are adapted from the Guizang PPT Swiss mode.
|
||||
|
||||
### IKB Blue
|
||||
|
||||
Default for AI, technology, product updates, design, and engineering topics.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #fafaf8;
|
||||
--ink: #0a0a0a;
|
||||
--grey-1: #f0f0ee;
|
||||
--grey-2: #d4d4d2;
|
||||
--grey-3: #737373;
|
||||
--accent: #002FA7;
|
||||
--accent-on: #ffffff;
|
||||
}
|
||||
```
|
||||
|
||||
### Lemon Yellow
|
||||
|
||||
Use for young, consumer, active, retail, sporty, or playful information.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #fafaf8;
|
||||
--ink: #0a0a0a;
|
||||
--grey-1: #f0f0ee;
|
||||
--grey-2: #d4d4d2;
|
||||
--grey-3: #737373;
|
||||
--accent: #FFD500;
|
||||
--accent-on: #0a0a0a;
|
||||
}
|
||||
```
|
||||
|
||||
### Lemon Green
|
||||
|
||||
Use for ecology, future, emerging tech, health, and highlighter-like contemporary topics.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #fafaf8;
|
||||
--ink: #0a0a0a;
|
||||
--grey-1: #f0f0ee;
|
||||
--grey-2: #d4d4d2;
|
||||
--grey-3: #737373;
|
||||
--accent: #C5E803;
|
||||
--accent-on: #0a0a0a;
|
||||
}
|
||||
```
|
||||
|
||||
### Safety Orange
|
||||
|
||||
Use for industrial, warning, urgency, risk, decision points, and sharp corrections.
|
||||
|
||||
```css
|
||||
:root {
|
||||
--paper: #fafaf8;
|
||||
--ink: #0a0a0a;
|
||||
--grey-1: #f0f0ee;
|
||||
--grey-2: #d4d4d2;
|
||||
--grey-3: #737373;
|
||||
--accent: #FF6B35;
|
||||
--accent-on: #ffffff;
|
||||
}
|
||||
```
|
||||
|
||||
Swiss palette rules:
|
||||
|
||||
- Use exactly one `--accent`.
|
||||
- Do not use gradients, shadows, glass, or mixed accent colors.
|
||||
- If the accent is yellow or green, text on accent must use `--accent-on: #0a0a0a`.
|
||||
- Prefer pure blocks, hairline rules, and grid rhythm.
|
||||
@@ -0,0 +1,128 @@
|
||||
# Title Shortener (1:1 covers + cross-platform reuse)
|
||||
|
||||
A long title that works in a 3:4 XHS card or a 21:9 WeChat cover **does not** work in a 1:1 square. Square covers need a different sentence — shorter, blunter, with one idea hitting the viewer in the first glance. This file is the playbook for generating that second title.
|
||||
|
||||
It also applies whenever you reuse one piece of content across multiple platforms: XHS carousel + WeChat cover pair + Lvshu single — each surface has a different attention budget.
|
||||
|
||||
## Why a separate title is needed
|
||||
|
||||
Tested empirically across the smoke decks:
|
||||
|
||||
| Source title (3:4 / 21:9) | Squeezed into 1:1 verbatim | Authored short title |
|
||||
| -------------------------------------------------------- | ---------------------------------- | ----------------------- |
|
||||
| 第三次进山,装备比上一次轻 3.4kg | overflows at 88px, fights bleed | 装备减重 3.4kg |
|
||||
| 开源了一个 Skill,让 AI 接管你屏幕边那张便签纸 | 3-line wrap, looks like a paragraph | AI 接管便签纸 |
|
||||
| 当代年轻人,不为了变美,只为了不丑 | 4-line wrap on `.poster.square` | 不为变美,只为不丑 |
|
||||
| 我把家从北京搬到大理后,第一次安静地写完了一本书 | overflows even at 80px | 北京到大理,写完一本书 |
|
||||
|
||||
The squeezed version reads as a wall of text. The authored short title reads as a poster headline.
|
||||
|
||||
## The 5-step extraction
|
||||
|
||||
When the user gives you a long title (or you wrote one for the 3:4 cover), derive the 1:1 like this:
|
||||
|
||||
**1. Identify the core verb.** Every good poster headline has one. `接管` / `减重` / `搬到` / `写完`. Drop modifiers, drop preambles, drop adjectival noise.
|
||||
|
||||
**2. Identify the core object.** What is the verb acting on? `便签纸` / `装备` / `家` / `书`. Skip qualifiers (`你屏幕边那张` → `便签纸`).
|
||||
|
||||
**3. Compress to 4-10 Chinese characters.** That is the readable band for 88-120px type on a 1080×1080 canvas. Outside that band, you either need 2 lines (still OK), 3+ lines (almost certainly wrong), or a typographic stunt (one giant character + meta — see Big Word recipe below).
|
||||
|
||||
**4. Drop English unless it carries the verb.** Mixed CJK + Latin at large size is a Swiss/Editorial trick that takes a lot of practice. For 1:1 short titles, prefer pure Chinese. Exceptions: brand names (`AI`, `Mac`, `iOS`), domain terms with no Chinese equivalent (`PPT`, `MCP`).
|
||||
|
||||
**5. Add a small subtitle only if needed for disambiguation.** Most 1:1 covers don't need one. If you must add it, use `.kicker` or `.t-meta` size (20-22px mono), never a second `.h-xl`.
|
||||
|
||||
## Patterns that work for 1:1 covers
|
||||
|
||||
### A · Verb + Object (single line, 4-8 chars)
|
||||
|
||||
```
|
||||
装备减重 3.4kg
|
||||
AI 接管便签纸
|
||||
家搬到大理
|
||||
眼线一笔到位
|
||||
```
|
||||
|
||||
Use when the verb is concrete and the object is short. The headline does the work alone — no subtitle.
|
||||
|
||||
### B · Two-clause cut (comma between, 2 lines)
|
||||
|
||||
```
|
||||
不为变美,
|
||||
只为不丑
|
||||
```
|
||||
|
||||
```
|
||||
六个停靠点,
|
||||
两天走完
|
||||
```
|
||||
|
||||
Use when the title needs a contrast or a setup-payoff. Hard-break at the comma; don't let CJK auto-wrap pick the line. Each line should be ≤ 6 characters.
|
||||
|
||||
### C · Big Word (one giant character + meta)
|
||||
|
||||
```html
|
||||
<h1 class="h-hero" style="font-size:520px; line-height:0.86;">家</h1>
|
||||
<p class="t-meta">从北京搬到大理</p>
|
||||
```
|
||||
|
||||
A single character can carry a cover if it's the conceptual anchor of the piece. Pair it with a 1-line meta in mono. Don't try this with 2 characters — it always looks worse than either 1 or 4+.
|
||||
|
||||
### D · Number-led headline
|
||||
|
||||
```
|
||||
↓ 3.4kg
|
||||
装备减重
|
||||
```
|
||||
|
||||
```
|
||||
1+1=3
|
||||
共创笔记
|
||||
```
|
||||
|
||||
When the numerical fact is the news, lead with it. Editorial uses `.num-mega` (200px) over an 56px serif subtitle; Swiss uses `.num-mega` (200px) over a 22px mono cat.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- **Squeezing the 21:9 title.** Cover the urge to use the same exact sentence. The square needs a separate sentence.
|
||||
- **Adding "如何"/"怎样"/"为什么" preambles.** Question-form titles are too long for 1:1. Use a declarative form: `怎样减重装备` → `装备减重 3.4kg`.
|
||||
- **Three-line titles.** If your draft wraps to 3 lines on `.poster.square`, shorten the copy — never shrink `.h-hero` below 152px. Three lines collapses into a paragraph.
|
||||
- **Adding a long subtitle.** A 1:1 cover with a 2-line subtitle reads as a flyer. If the subtitle is essential, you probably picked the wrong recipe — switch to a `.poster.xhs` 3:4 instead.
|
||||
- **English-only titles when the content is Chinese.** Looks like stock template. Mix only when the English carries the actual headline (e.g. brand launch).
|
||||
|
||||
## Sizing on `.poster.square` (1080×1080)
|
||||
|
||||
Type scale defaults on square boards:
|
||||
|
||||
| Style | Class | Default size | Use |
|
||||
| --------- | ----------- | ------------ | ---------------------------------- |
|
||||
| Editorial | `.h-display`| 110px | Pattern A or B, 1-2 lines |
|
||||
| Editorial | `.h-xl` | 78px | Subtitle or secondary headline |
|
||||
| Swiss | `.h-hero` | 200px | Pattern A or B, 1-2 lines |
|
||||
| Swiss | `.h-statement` | 160px | Same role as `.h-hero`, slightly tamer |
|
||||
| Both | `.num-mega` | 200px | Pattern D leading number |
|
||||
|
||||
If a single-line short title is ≤ 4 Chinese chars on Swiss square, you can push `.h-hero` to 240px without overflow.
|
||||
|
||||
## Cross-platform pairing
|
||||
|
||||
When the same content runs as XHS carousel + WeChat cover pair + Lvshu single:
|
||||
|
||||
| Surface | Title source | Length band |
|
||||
| -------------------- | ------------------------------------------- | ------------------------ |
|
||||
| XHS p1 cover (3:4) | Authored long title (12-30 chars) | 1-2 lines, ≤ 9 chars/line|
|
||||
| WeChat 21:9 main | Authored long title or 80% of it | 1 line, ≤ 14 chars |
|
||||
| WeChat 1:1 square | Shortened per this file (4-10 chars) | 1-2 lines, ≤ 6 chars/line|
|
||||
| Lvshu single (3:4) | Same as XHS p1 or shortened to 8-12 chars | 1-2 lines |
|
||||
|
||||
The 1:1 short title is the **shortest** of the family. If you cannot shorten further without losing meaning, the content probably needs a different framing — talk to the user.
|
||||
|
||||
## Workflow integration
|
||||
|
||||
When a user task includes "公众号封面" or "WeChat cover", you should:
|
||||
|
||||
1. Write the long title for 21:9 first.
|
||||
2. Apply this file's 5-step extraction to derive the 1:1 short title.
|
||||
3. Print both in the planning notes before rendering.
|
||||
4. Render both in the same HTML file, plus a `.pair-preview` section showing them side-by-side.
|
||||
|
||||
If the user supplies only one title and asks for the pair, derive the short one yourself and call it out in the response (don't silently swap text — the user needs to confirm the shortening reads right).
|
||||
Reference in new issue
Block a user