social-poster
Skill0 starsChanged 36 days agoMITView on GitHub
Build a LinkedIn/social poster image whose job is to stop the scroll and drive clicks. Use when the user asks for a post image, launch graphic, announcement card, feature-release visual, or "a picture to post alongside". Produces a 4:5 2400x3000 PNG rendered from HTML via puppeteer, verified at feed size before delivery.
2 other projects use a version of this.
Adopted by
Most recently taken up by
- ActuallyNodejam/openpaperworktheir own version, first seen Nov 8, 2026
- ciberjohn/Hermes-Skillstheir own version, first seen Sep 4, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- ciberjohn/Hermes-Skills★ 17same name
- ActuallyNodejam/openpaperwork★ 0same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
We split this skill into the rules it gives an agent
9 rules. About 0 are common, 6 are distinctive, and 3 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
3
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 39
No em dashes anywhere. Periods over dashes.
- Distinctive: line 86
Every one of these came from a real rejection.
- Distinctive: line 89
Live play, in an arena, on the ice: Not fan zones, arena exteriors, queues, ceremonies, honour guards, anthems, locker rooms, celebrations, …
- Distinctive: line 135
Do not use broadcast frames as the hero of a promo.
- Distinctive: line 145
Picking works by scrolling and pointing, not searching: Do not hand over a search link or a filter UI.
- Very specific: line 160
If you do mirror files: fetch the bytes fully before opening the output file.
- Very specific: line 164
Always re-check the license on each file's own page before shipping (extmetadata.LicenseShortName), and record photographer + file page in …
- Distinctive: line 171
Read the release notes / source of truth.
- Very specific: line 172
Write the HTML (copy reference/poster_template.html).
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Social poster
The deliverable is one image that (1) stops the thumb, (2) makes the caption worth reading, (3) sends people to a URL. It is not a spec sheet. Features live in the caption, never in the image.
The one non-negotiable rule
Verify at feed size before delivering. Downscale the finished poster to 440px wide and Read it. Anything you cannot read at 440px does not exist. This single check kills most bad posters — it is how the three-column feature layout that looked fine at full res was caught as unreadable mush.
Image.open('poster.png').resize((440,550), Image.LANCZOS).save('feed.png')Then actually Read feed.png. Do not skip because it "looks obviously fine".
Copy budget (hard ceilings)
| Element | Ceiling |
| Eyebrow | product + version, e.g. PELAA 1.0.4 |
| Headline | 5 words, verb-first, one accent word in brand red |
| Sub | one sentence, ≤14 words, may be 3 short clauses |
| Footer | pelaa.tv + a 4-word status like Out now for Mac |
| Feature bullets | zero |
Headline pattern that works: <Product> now <verb>s <the thing>. Concrete verb,
not a category noun. "Pelaa now records the game" beats "The biggest update since 1.0"
because a verb tells a coach what changed.
No em dashes anywhere. Periods over dashes.
Layout (the shape that won)
4:5 portrait, 1200x1500 CSS px rendered at deviceScaleFactor 2 → 2400x3000. 4:5 claims more vertical feed space on mobile than 1.91:1 landscape.
┌──────────────────────┐
│ photo, top ~50% │ ← real sport/product imagery, gradient-faded into black
│ small REC/status │ at the bottom edge so type sits on solid ground
│ pill, top right │
├──────────────────────┤
│ EYEBROW │ 25px, .40em tracking, #8A8A93
│ Headline │ 124px / 900 / -0.035em / line-height .98
│ Sub │ 42px / 400 / #B0B0B8
│ │
│ ─────────────── │ 1px rgba(255,255,255,.12)
│ ⬛ pelaa.tv status│ 42px bold + 30px muted, icon 54px
└──────────────────────┘Type sizes are for the 1200px-wide CSS canvas. Headline caps-height must survive the 440px check — 118 to 132px is the working band; below ~110px it starts to go.
Brand tokens (Pelaa)
- Background
#0B0B0B, accent red#E11D2C, muted#8A8A93, body#B0B0B8 - Font:
-apple-system, BlinkMacSystemFont, "SF Pro Display", system-ui, sans-serif - Icon: your app icon as
icon.pngbeside the template (not included) - Ambient glow, keep it quiet:
radial-gradient(760px 620px at 12% 6%, rgba(225,29,44,0.22) 0%, transparent 62%) - Red appears once or twice: the headline accent word, and a status dot. Scattering red across section labels dilutes it.
Imagery rules
Rank by what survives 440px:
- A real photo of the sport — a scoring chance from an elevated side angle, like a press-box camera. Wins on stopping power and reads as sport, not as another dark SaaS card.
- A wide product frame (video pane, a strip of the track/timeline) — colored row bars stay legible as texture with intent.
- A dense UI panel (button walls, small labels) — becomes noise. Do not use.
Sport-photo gate — apply ALL of these before a photo reaches the user
Every one of these came from a real rejection. Filter in code where possible; do not make the user scroll past images that fail a mechanical check.
- Live play, in an arena, on the ice. Not fan zones, arena exteriors, queues, ceremonies, honour guards, anthems, locker rooms, celebrations, mascots, press conferences, skills competitions or all-star events.
- Last three seasons only. Commons exposes
DateTimeOriginalinextmetadata— parse the year and hard-filter. Older frames date themselves through gear, skates, sticks, board advertising, and rosters that no longer exist. Anything that starts to look archaic is out, regardless of composition. - Right sport. Winter Olympics categories mix in short track speed skating, figure skating and curling. Filter titles for those and check before shipping.
- Wide enough to be a play, not a portrait. Single-player telephoto close-ups fail even when the action is real. The frame has to hold the zone.
- Camera height must match how the app records a game. Elevated from the side, at press-box height, looking across the zone — a fixed camera a coach would actually mount. A near-overhead shot looking straight down is disqualifying even when it is otherwise the best chance in the set. This is subtle and cost a whole gallery pass.
- It has to be a chance. See below.
A wide shot of play is not the same as a chance. Why one frame beat two others: the winner had players breaking out past the defence toward a goalie who is set, with the puck live in the slot even though you cannot see it. The rejects had the puck elsewhere, players looking away, or no clear shape to the play. So look for: a set goalie squared to the play, attackers converging on the crease, defenders beaten or trailing, everyone's body oriented at the same point. Empty-ice wide angles and neutral-zone skating do not qualify no matter how clean the composition. No automatic score can see this — it is the one judgement that has to be made by eye, which is why the picking gallery exists.
Expect the openly-licensed pool to fail. Measured on Commons in mid-2026: 201 permissive hockey images, only 29 from 2023 or later, and after removing other sports, skills events and ceremonies, 17 remained — none of which cleared the gate. The recency rule alone removes about 85%. Say this out loud early rather than presenting a large gallery that cannot deliver, and put the real option on the table: use a frame from footage you have the rights to. Do not keep grinding the search.
Treatment: crop to ~1.58 landscape, upscale to 2400 wide, then
Color 1.18 / Contrast 1.12 / Brightness 0.95 and a slight warm shift
(R x1.03, B x0.98). Photos taken from the stands are often flat and cool-toned.
Fade the photo into the page rather than boxing it:
background: linear-gradient(180deg, rgba(11,11,11,0.30) 0%, rgba(11,11,11,0.05) 34%,
rgba(11,11,11,0.86) 84%, #0B0B0B 100%);Licensing — get this right before using any photo
Do not use broadcast frames as the hero of a promo. Prefer:
- CC0 / Public domain — no attribution required. Still check trademark and personality rights.
- CC BY — usable, needs a credit line (caption is enough).
- CC BY-SA — I avoid it. Share-alike obligations may reach a poster built from the photo, and I did not want to rely on an interpretation.
Working source: Wikimedia Commons, searched by deep category, filtered by license. Commons has an open API and machine-readable license metadata. The metadata is supplied by uploaders, so verify it.
Picking works by scrolling and pointing, not searching. Do not hand over a search link or a filter UI. Build the browsable gallery:
export SK="<path to this skill folder>" # harvest.json is read and written in the current folder
python3 "$SK/scripts/harvest_commons.py" # → harvest.json (edit the category list)
python3 "$SK/scripts/build_picking_gallery.py" # → ~/Desktop/poster-gallery/index.htmlThe user opens the HTML, scrolls, and replies with a number. The page shows a license badge per image, filters to "no credit needed" vs "credit needed", and links each photo to its full-size original.
Hotlink thumbnails from Wikimedia with loading="lazy" instead of bulk-downloading them. This avoids bulk downloading. find_cc0_photos.py mirrors thumbs for an offline contact sheet; use it only for small sets and keep its backoff.
If you do mirror files: fetch the bytes fully before opening the output file.
open(fn,'wb').write(get(url)) leaves a 0-byte file when get raises, and that empty
file then looks like a finished download to the next resume pass. A failed fetch once left 0-byte files that looked like finished downloads.
Always re-check the license on each file's own page before shipping
(extmetadata.LicenseShortName), and record photographer + file page in the delivery
notes. A permissive copyright license does not clear trademark or personality rights:
identifiable players, team and league marks need their own check before commercial use.
Build loop
- Read the release notes / source of truth. Pick the ONE claim.
- Write the HTML (copy
reference/poster_template.html). - Render:
node scripts/render.js poster.html poster.png 1200 1500 2 - Downscale to 440px and Read it. Fix what does not survive.
- Render 2-3 variants that differ in a real way (photo vs type-only vs product strip), not in nudges. Show them as one feed-size strip so the comparison is honest.
- Deliver full-res files plus the strip.
Failure modes already paid for
- Three feature columns at 26px: invisible at feed size. Features go in the caption.
- Composite slide inside an app screenshot: the app's button wall turns to static and fights the type. Works only when the copy is one giant claim.
margin-top: autoon the headline with ajustify-content: centerparent: pins the headline low and leaves a dead band. Pick one centering mechanism.- Screenshotting an old build to announce a new feature: the frame silently contradicts the claim. Check what is actually on screen.
- Arguing image strategy in the abstract. Downscale first, then argue.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

