Skip to content

Add localized social creatives for release announcements - #349

Draft
strider-dunadan wants to merge 3 commits into
masterfrom
strider/social-creatives
Draft

Add localized social creatives for release announcements#349
strider-dunadan wants to merge 3 commits into
masterfrom
strider/social-creatives

Conversation

@strider-dunadan

Copy link
Copy Markdown

What

A release post becomes branded images, one set per Telegram channel language,
handed to the poster that already exists.

  • .claude/skills/om-post/ — the skill: workflow, copywriting and layout
    references, assets/brand.css
  • tools/social_post.py — the post.toml schema: what is prose, what is an
    identifier, where a slide's screenshot comes from
  • tools/social_translate.py — slide copy through the same DeepL path as
    translate_md.py: glossary, formality, tidy passes
  • tools/social_build.py — headless Chrome at 2x, Pillow downsample, a contact
    sheet per language
  • tools/telegram_post_all.py — picks the creatives up per channel

social/2026-07-23-620/ is the July release as the first real run: 7 slides,
12 languages.

How to use it

Install once: pip install -r tools/requirements-social.txt, plus a
Chrome-family browser. Everything runs from the repository root.

A news folder maps to its social folder by name —
content/news/2026-08-25/630social/2026-08-25-630 — which is how the
poster finds the images with no flag. Keep the name.

mkdir -p social/2026-08-25-630
# write social/2026-08-25-630/post.toml: cover, features, lists, cta.
# Screenshots are named by filename; `source` points at the news folder, so
# nothing is copied. See .claude/skills/om-post/SKILL.md for the schema.

python3 tools/social_translate.py social/2026-08-25-630 --telegram
python3 tools/social_build.py social/2026-08-25-630 --all-langs
open social/2026-08-25-630/export/*/sheet-4x5.png   # read every language

python3 tools/telegram_post_all.py content/news/2026-08-25/630 --dry-run
python3 tools/telegram_post_all.py content/news/2026-08-25/630 --only ru --to @a_test_channel
python3 tools/telegram_post_all.py content/news/2026-08-25/630

Iterating: --langs ru and --slide 3 on the build, --only 4x5 to skip the
Instagram formats. --no-creatives restores the previous behaviour of posting
the raw screenshots.

The translations are DeepL drafts and need the same proofreading pass as a
translated news post — that is the step between rendering and posting, not an
optional one.

Why

The channels have been getting raw screenshots. Canvas size, brand colour,
which screenshot region survives the crop, and which language each channel is
served are now encoded once instead of redone by hand every release.

A release post becomes branded images, one set per language, described by a
post.toml slide script that is the only file written by hand.

social_translate.py runs the slide copy through the same DeepL path as
translate_md.py, so terminology and register match the news post the images
accompany; only prose is translated, since media paths, themes, badge names
and the short URL are identifiers. social_build.py renders each slide through
headless Chrome and downsamples with Pillow, writing a contact sheet per
language because a build that succeeded is not a build that looks right.

Renders stay out of content/: Zola publishes every file beside an index.md as
a page asset and picks the first one for the OpenGraph preview. They stay out
of git too, at ~40 MB a release, and are rebuilt from the slide scripts.

Two things the layout has to survive. Translations run a third longer than
English, so an auto-fit pass shrinks the type scale until the slide fits,
measured against the slide's real children rather than scrollHeight — the
corner watermark is an absolutely positioned pseudo-element hanging below the
canvas, and counting it as overflow shrinks every green slide to the floor.
And the html overflow is set explicitly, or the body's propagates to the
viewport, the watermark enlarges the scroll area instead of being clipped,
and every right-to-left slide comes out shifted sideways.

The July release ships as the first real run, in twelve languages.
Each channel gets the images in its own language, falling back to English for
a language that was not rendered — and the summary names the language actually
picked, so the fallback is visible before anything is sent rather than after.

A news folder maps to its social folder by name, content/news/2026-07-23/620
to social/2026-07-23-620, so no flag is needed for the usual case; --creatives
points somewhere else and --no-creatives sends the raw screenshots as before.
A post that has creatives never mixes them with its raw screenshots: silently
falling back for one channel would send an unbranded album to that channel and
branded ones to the rest, so a missing render is an error instead.

--to redirects every selected post to one channel, which makes it possible to
rehearse a release on a throwaway group without touching the real twelve.
An iOS screenshot gets an iPhone, an Android one an Android phone: their own
corner radius, rim and side buttons, and the camera cutout drawn back in. The
platform is read off the eyebrow when `device` is not given, which works in
every language because iOS and Android stay Latin in translation.

The cutout is not decoration over the screenshot. It is a hole in the display
that neither system draws into, so the shot has an empty gap in its status bar
exactly where the hardware sits; putting it back is what makes the frame read
as the device it is, and leaving it out is what made every phone look alike.
Its size is a share of the screen taken off the real hardware, so it holds at
any rendered size. The generic `phone` frame keeps no cutout — it exists for a
screenshot whose device is unknown.

The screenshot now sits inside the frame rather than being the frame: side
buttons need a box to hang off, and a box-shadow has none. The frame is handed
the screenshot's own aspect ratio, so it is exactly the size the image would
have been and the fit-inside behaviour is still the image's own.

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 19, 2026

Copy link
Copy Markdown

Deploying organicmaps with  Cloudflare Pages  Cloudflare Pages

Latest commit: b6dc428
Status: ✅  Deploy successful!
Preview URL: https://501d287e.organicmaps.pages.dev
Branch Preview URL: https://strider-social-creatives.organicmaps.pages.dev

View logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant