视觉画布设计
canvas-design
基于设计原则创作静态视觉作品,用于海报与品牌图形。
carousels【文档与办公】Turns a piece of Craig's content (an email, a YouTube script, an essay, or pasted text) into a polished image carousel publishable to both LinkedIn and Instagram from one set of 1080x1350 slides. Distills the source into 5-8 one-idea-per-slide beats, generates hand-drawn infographic illustrations with GPT Image (OpenAI), renders pixel-perfect on-bran…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Turn one strong piece of source content into a swipeable image carousel. One set of 4:5 slides serves both platforms — PNGs for Instagram, an assembled PDF for LinkedIn.
The brand is locked, not configurable: off-white #F5F1E8, ink #0F0F0F, muted
teal #2A6F6A, Inter type, hand-drawn infographic illustrations. Every run comes out
visually identical. Don't ask the user about themes, colors, or fonts.
Skill files (paths relative to repo root /Users/craighewitt/Coding/second-brain):
output/cowork-context/skills/carousels/assets/carousel.css — brand stylesheetoutput/cowork-context/skills/carousels/references/slide-layouts.md — HTML patternsoutput/cowork-context/skills/carousels/scripts/generate-image.mjs — GPT Image (OpenAI)output/cowork-context/skills/carousels/scripts/render.mjs — slides → PNG + PDFRun these checks before anything else. If a check fails, surface the fix and stop until it's resolved — don't proceed with a broken environment.
Node — node -v (need v18+; repo has v22).
Headless browser — render.mjs launches puppeteer. If puppeteer or its
browser is missing, the script prints the install command. Don't pre-empt it;
just run the render step and act on any error.
OPENAI_API_KEY — only needed if the carousel will have image slides. Check
with [ -n "$OPENAI_API_KEY" ] && echo set || echo missing. If missing, tell
the user:
GPT Image (OpenAI) needs an OpenAI API key. Create one at platform.openai.com/api-keys, add billing, then run
export OPENAI_API_KEY="sk-..."in your shell (never commit it).
If the user can't set a key right now, offer to build a type-only carousel (no image slides) — the skill still works fully without the key.
Get the source content. Accept either:
output/, an essay draft.Do not scrape URLs. If the user gives a URL, ask them to paste the content
(per CLAUDE.md).
Then read, once:
context/brand/02-voice.md — for the caption voice.context/brand/03-visual-identity.md — confirm brand-surface palette/type.Ask the user only for things that genuinely change the output (one short batch):
If the user already gave direction in their prompt, skip the questions.
Create the run folder: output/carousels/<source-slug>-<YYYY-MM-DD>/ with
images/ and publish/ subfolders. Copy carousel.css into the run folder
(render needs it next to slides.html).
This is the hard part — carousels live or die on editing, not rendering.
Distill the source into 5-8 beats, one idea per slide. Let the source decide the count: a tight 4-tip article is 7 slides; a dense essay might be 8. Never pad.
Structure:
For each content slide decide: is it type-only or an image slide? Image slides are for ideas that are clearer drawn than written — a process, a relationship, a before/after, a system. Aim for 2-4 image slides, not every slide. Type-only slides use the big-stat, steps, quote, comparison, or statement layouts.
Write 01-slide-plan.md in the run folder: for each slide, its number, role,
layout, one-line idea, and image/type-only flag.
Write the visible copy for every slide. Rules:
For image slides only. Skip entirely if building a type-only carousel.
For each image slide, write a two-paragraph prompt:
Paragraph 1 (locked — brand illustration style, paste verbatim):
Hand-drawn minimalist infographic, black ink linework on a solid flat warm off-white background (hex #F5F1E8), single muted teal accent color (#2A6F6A), clean whiteboard sketch style, confident pen strokes, hand-lettered text, simple geometric icons, lots of white space.
Paragraph 2: describe the specific diagram — the concept, layout, labels, and flow for that slide. Be concrete ("a 3-step horizontal flow: Draft → Review → Publish, each a labeled box connected by arrows"). No stock-photo realism, no gradients, no people. Always end paragraph 2 with: "The entire diagram, including every icon and label, sits well within the frame with generous empty margins on all four sides — nothing is cropped and nothing touches the edges." The model otherwise tends to draw edge-to-edge and clip the outer labels.
Generate each one:
node output/cowork-context/skills/carousels/scripts/generate-image.mjs \
--prompt-file <run>/images/slide-04-prompt.txt \
--out <run>/images/slide-04.png
Write the prompt to a .txt file first to avoid shell-escaping issues. After
generating, the script normalizes the image background to exactly #F5F1E8
(the --bg-hex default) so the illustration sits seamlessly on a light slide —
no visible panel edge. Default size 1024x1024, quality medium. Name each PNG
slide-NN.png matching its slide number. Because the linework is black, image
slides must use the light slide background, not the teal variant. (If you ever
need an image slide on a different background, pass --bg-hex #RRGGBB to match.)
Author <run>/slides.html using the patterns in references/slide-layouts.md.
One .slide div per slide, in order. Link carousel.css (the copy in the run
folder). Reference illustrations as images/slide-NN.png.
Sample-approval checkpoint: before rendering the whole set, render just the cover so the user sees the styling:
node output/cowork-context/skills/carousels/scripts/render.mjs \
--slides <run>/slides.html --out <run>/publish
Show the user publish/slide-01.png. If they want changes (copy, layout), edit
slides.html and re-render. Only continue once the cover is approved.
Run the full render (same command as above — it renders every .slide):
node output/cowork-context/skills/carousels/scripts/render.mjs \
--slides <run>/slides.html --out <run>/publish
Produces publish/slide-01.png … slide-NN.png (Instagram) and
publish/carousel.pdf (LinkedIn). All PNGs are exactly 1080×1350.
Write publish/caption.md with a caption that works for both platforms:
If a LinkedIn vs Instagram split is worth it (different length/tone), write both under clear headings. Otherwise one shared caption is fine.
Open the rendered PNGs and check each against the brand:
#F5F1E8 / #0F0F0F / #2A6F6A (plus rare #C75A2C data callout).03 / 07).Fix any off-spec slide in slides.html and re-render. Then report the run folder
and tell the user: upload the PNGs to Instagram as a carousel, upload
carousel.pdf to LinkedIn as a document post, use caption.md for both.
Final deliverables in output/carousels/<slug>-<date>/publish/:
slide-01.png … slide-NN.pngcarousel.pdfcaption.md