A complete Twitch channel visual identity, built in code. No graphics editor.
Seven stream screens, five channel panels, twelve emotes, six bit badges, thirteen channel-point icons and one seal — every piece is HTML/CSS or PIL geometry, rendered to PNG.
HTML + CSS ──▶ Playwright (screenshot) ──▶ PNG ──▶ PIL (alpha work) ──▶ final PNG
There is no image model anywhere in this. The shapes are hand-written SVG <path> data —
one of the cats' bodies is literally this, in src/gatos.py:
CORPO = '''<path d="M56 53c-16.5 0-27 16.5-27 34 0 8 3 13.5 8.5 13.5h37C80 100.5 83 95 83 87c0-17.5-10.5-34-27-34z"/>
<circle cx="56" cy="42" r="23.5"/>'''A Twitch emote has to stay legible on both the light and the dark theme. The fix is a keyline derived from the artwork's own alpha channel: dilate, blur, threshold, then composite a solid-colored mask behind the original piece.
gros = a.filter(ImageFilter.MaxFilter(7)) \
.filter(ImageFilter.GaussianBlur(.7)) \
.point(lambda v: 255 if v > 90 else 0)
back = Image.new('RGBA', im.size, (27,27,27,255)); back.putalpha(gros)
out = Image.alpha_composite(back, im)Light pieces get a dark keyline. Dark pieces (the cats) get a bone keyline plus a thin dark line outside it — two dilations at different radii, stacked.
Where gameplay or webcam goes, the overlay doesn't paint a black rectangle — it has alpha zeroed out. Render opaque, then punch.
def punch(path, rects):
im = Image.open(path).convert('RGBA'); px = im.load()
for (x, y, w, h) in rects:
for j in range(y+1, y+h-1):
for i in range(x+1, x+w-1):
px[i, j] = (0, 0, 0, 0)
im.save(path)Sticker-style contour cutting: a flood fill seeded from the outer border isolates only the exterior background (so interior whites survive), the silhouette is then dilated to leave a ~5px "paper" border, and a largest-connected-component BFS drops stray fragments.
The bit badges aren't drawn. They're two circles subtracting each other, supersampled 8× so they survive being displayed at 18 pixels.
npm install
pip install -r requirements.txt
playwright install chromium
python src/emotes.py # 9 subscriber emotes
python src/gatos.py # bit-tier emotes
python src/cafe.py
python src/badges.py # bit badges
python src/icones.py # channel-point icons
python src/icones2.py # the three default-reward icons
python src/selo.py # the seal
python src/assets.py # packs everything into assets.json
python src/build.py # the 7 stream screens
python src/hires_bits.py # hi-res bit emotes used by the carousel
python src/carrossel.py # the 11-slide brand manualPaths are resolved from the file's own location (src/kitpath.py), so the scripts
run from any folder on any OS — no editing, no sed. Playwright still needs a
file:// URL for the local fonts; uri() builds a valid one on Windows, macOS
and Linux.
The channel is Brazilian, so identifiers and palette names are in Portuguese:
| term | meaning |
|---|---|
osso / tinta |
bone (off-white) / ink (near-black) |
vinho |
wine — the single accent color |
grao |
grain (the noise overlay) |
moldura |
frame |
selo |
seal / sigil |
contorno, gros, fora |
keyline; the inner and outer dilations |
telas |
the full-screen states (starting / away / ended) |
diecut, rasgado |
contour cut; torn-paper edge |
One of the panels used third-party illustration. It was removed from this public
repository — src/pain3.py renders an empty frame in its place. The plan is to
commission an illustrator once the channel pays for itself.
This code was written with AI (Claude), under human direction: brief, references, brand, tone, vetoes, and a verdict on every iteration.
No image generator was used at any stage. There is no artist's illustration in here and nothing was copied. What exists is geometry written as code, coordinate by coordinate — and it's all open to inspect.
Reverse image search will turn up "similar": a sitting black cat exists in ten thousand cliparts, a rabbit inside an inverted triangle is centuries-old occult iconography, a crescent moon is a crescent moon. That's visual convention — the same reason every trash-can icon looks like every other trash-can icon. The proof isn't in an image search. It's in the code, which shows each shape being constructed from nothing.
Code: MIT. Brand and visual pieces: all rights reserved. You want the method, it's yours. You want the rabbit, it isn't. See LICENSE.
Made by @bnuuyCode · twitch.tv/heychiwa
