Sticker packs
A shared DEPO sticker library — SVG, PNG, GIF, WebP and WebM, still and moving. Emoji and words call each sticker up in a chat picker; likes, a shared trash that is never emptied, packs downloaded as ZIP. Open API and MCP server.
Summary
A sticker library for DEPO chats, made the way demo30 made the UI kit: one shared database, a page to browse and edit it, an API and an MCP server on top. The aim is a collection of stickers that can be packed and taken away.
Collections and stickers. Every sticker belongs to one collection and has a number (#001, one counter for the library). It is a file in one of five formats — SVG, PNG (APNG), GIF, WebP, WebM — still or moving; "moving" is found from the file itself (APNG acTL, GIF frames, WebP ANIM, SMIL or CSS animation in SVG, every WebM). The seed is 47 stickers drawn for this demo in four collections: Moods (12 faces — wink, laughing, in love, cool, wow …), Kit bag (camera with a flash, aperture, light bulb, lipstick, fire, coffee …), Studio talk (the words a set runs on, in English and Ukrainian: Shoot!, One more!, That's a wrap, Published, Дякую!, Привіт!) and Cover stars (die-cut portraits from the DEPO magazine covers). 24 of them move. On 2026-10-19 the owner's brand set Depo beta 0.01 was added (folder DEPO-20-Final, brand edition 01): 20 stickers with the original DEPO eyes and Lazurski lettering — Hey you!, Thank you!, What a shot!, This deserves a cover., It's live!, All eyes on you. … — each as a moving VP9 WebM with alpha and a still PNG (40 stickers, #048–#087), with English and Ukrainian words (config/demo32/depo-beta-0.01.json, php demo/bin/demo32-stickers.php import). 87 stickers in all.
Emoji and words. Each sticker carries one or more emoji (😉😜) and the words people type for it (wink, deal, підморгнути, домовились). That is what calls it up: the chat panel at the top of the page shows the stickers as you type — an emoji matches the stickers that carry it (skin tones and variation selectors ignored: 👍🏽 = 👍, ❤ = ❤️), a word matches the start of a keyword in any language (прив → Привіт!), a whole phrase equal to a keyword wins. ✎ on a sticker opens it: add or remove emoji and words for everyone, download the file.
Packs and archives. Click stickers to put them in the tray (the click order is the pack order; drag to reorder), name the pack and Build pack · ZIP. A pack is stored for good — re-tagging a sticker later does not change it — and downloads as <pack>.zip: stickers/NN-###.<ext>, manifest.json (format depo-sticker-pack/1: emoji, keywords, format, size, animated of every sticker) and a README.txt table. "Load into the tray" starts a new pack from an old one.
Likes. The ♥ on a sticker is one like per visitor (cookie st32, a year; over MCP one per caller address) and is never taken back; Order: by likes puts the most liked first.
Shared trash (as in demo30's buttons). 🗑 on a sticker (or To the trash in its window) moves it to one trash for everybody: it leaves the library, the picker, the collection counts and new packs; packs already built keep it. A toast offers Undo. 🗑 Trash in the tool row shows the trashed stickers, greyed, newest first, each with ↺ Restore. The trash cannot be emptied — there is no delete anywhere. Uploading a file that is in the trash answers "duplicate" with its number.
Adding. Add stickers takes up to 20 files at once (drop or choose), each with its emoji (at least one), words and title, into a collection (or a new one). Files are checked by their bytes, not their names; an SVG is cleaned (no scripts, handlers, outside links, foreignObject) and served with a CSP that forbids scripts. The same file twice is answered "already in the library as #…".
API (/demo32/api.php, no keys): ?q= search as the picker does, ?sticker=, ?collections=1, ?packs=1, ?zip=<pack> (search takes &order=likes, &trash=1); POST actions add, collection, tag, pack, like, trash, restore. GET /demo32/api.php describes it for people. MCP server (/demo32/mcp.php, Streamable HTTP, JSON answers, no keys): stickers_overview, search_stickers, get_sticker (returns the picture itself for PNG / GIF / WebP, the code for SVG), add_stickers, create_collection, tag_sticker, build_pack (from numbers, a whole collection or a search), list_packs, like_sticker, trash_sticker, restore_sticker; prompt draw_stickers asks a model to draw SVG stickers with emoji and words and add them.
Prompt
The brief this page was built from.
Build one page of the DEPO demo album (album.dev0.dphub.net): a shared sticker library for DEPO
chats, after the pattern of demo30 "UI kit" — a database, a page, an open API and an MCP server.
Function:
- Stickers in collections. Formats SVG, PNG (incl. APNG), GIF, WebP, WebM — still and animated;
detect "animated" from the file. Every sticker has a number, a title, one or more emoji and
keywords in any language (English and Ukrainian at least).
- The emoji and keywords call the sticker up: a chat composer on the page shows matching
stickers above the input as you type an emoji or a word (prefix match, emoji normalised —
no skin tones / variation selectors); a click sends the sticker into the chat.
- Visitors can add stickers (files, up to 20 at once, each with emoji + words + title) to a
collection or a new one, and add / remove emoji and words of any sticker.
- Pick a collection, select stickers (click order = pack order, drag to reorder) and build a
sticker pack: stored for good and downloaded as a ZIP archive with the files, a manifest.json
(emoji, keywords, format, size, animated per sticker) and a README.
- Likes: one per visitor and sticker, never taken back; order the library by likes.
- A shared trash, as in demo30: a sticker sent there leaves the library, the picker and new packs
for everyone; the trash view shows them with Restore; the trash can never be emptied.
- The same file is never added twice (content hash). Files are checked by their bytes; SVG is
cleaned of scripts and outside links and served with a script-free CSP. Daily limits.
- API (GET search / sticker / collections / packs / zip; POST add / collection / tag / pack) with
a page describing it, and an MCP server (Streamable HTTP, JSON, no keys) with tools for the
same, plus a prompt that asks a model to draw SVG stickers and add them.
- Seed: about 45 stickers drawn for the demo in four collections (faces, shoot-day objects,
studio words in EN/UA, die-cut portraits from the album's magazine covers), every format
present, about half animated; a generator script renders them (SVG → PNG / WebP / GIF / WebM).
Design: light and warm, different from the dark demo30 — dotted paper ground, die-cut stickers
(thick white edge, soft shadow, peel-up hover), Unbounded for display and Onest for text (both
with Cyrillic), DEPO lime #53f57e as the one accent, the chat picker as a dark ink panel in the
hero, collections as cards with three fanned stickers, a dark floating tray for the pack.
Self-hosted fonts, including Noto Color Emoji so the emoji look the same everywhere.
Look
- Type: Unbounded 500–900 (headings, numbers, badges, sticker lettering) and Onest 400–800 (text), both with Cyrillic; Noto Color Emoji for every emoji — all self-hosted in
public/demo32/fonts/. - Palette: paper
#f3efe6with a 22 px dot grid; ink#15201a; DEPO green#1d5a37; lime#53f57e(the one accent: the hero word, order badges, the send button); chat panel#121a15. Stickers bring their own colours (green, warm yellow, pink, lilac, sky). - Layout: a sticky bar (DEPO mark, Library / Packs / API & MCP, New collection, Add stickers); the hero — a huge Unbounded line "Stickers that answer to a word." with the lime word, the lead, four counts — next to the dark chat picker (a conversation, the suggestion strip above the composer, quick emoji under it); collections as cards with three fanned stickers; the library — a sticky tool row (search, Still / Moving, format chips, count, select all) over a loose grid of stickers with emoji, a format badge, the number and the words (matches marked lime), a ♥ pill with the like count on each, ✎ and 🗑 on hover, Order and 🗑 Trash in the tool row; packs as cards with an 8-sticker preview; the API / MCP block in ink. The pack tray floats at the bottom once something is picked. Dialogs: one sticker (big preview on a checker mat, facts, emoji and word chips), Add stickers, New collection.
- Motion: stickers themselves (SMIL in SVG, GIF / WebP frames, WebM video, which plays only while on screen); hover lifts and tilts a sticker with a growing shadow; collection fans spread on hover; chat messages and the tray pop in with a small overshoot; order badges spring in.
prefers-reduced-motionstops the page's own motion.
Built with
| Part | What |
|---|---|
| HTML | public/demo32/index.html |
| CSS | public/demo32/css/demo32.css |
| JS | public/demo32/js/demo32.js — vanilla (Intl.Segmenter for emoji, HTML5 drag and drop, <dialog>) |
| Server | public/demo32/api.php (API), mcp.php (MCP server), api-doc.php (the API for people), stickers-db.php (SQLite public/_db/demo32-stickers.sqlite, checks, search, ZIP via PHP ZipArchive) |
| Files | public/demo32/media/<hash>.<ext> — every sticker file, named by its content hash; ZIPs cached in public/_db/demo32-zip/ |
| Imports | php demo/bin/demo32-stickers.php import <folder> <config.json> — a finished set with a manifest.json (animated/.webm, static/.png) into one collection; Depo beta 0.01 = DEPO-20-Final + config/demo32/depo-beta-0.01.json |
| Seed | config/demo32/art.js (the 47 stickers drawn as SVG), art.html, bin/demo32-art.mjs (renders them with Playwright: PNG frames, ImageMagick for WebP / GIF, Chrome MediaRecorder for VP9 WebM with alpha) → config/demo32/seed/ + seed.json; php demo/bin/demo32-stickers.php seed loads them |
| Libraries | none |
| Fonts | Unbounded, Onest (latin + cyrillic subsets) and Noto Color Emoji (11 subsets, loaded on demand) from Google Fonts, self-hosted in public/demo32/fonts/ |
| Images | sticker art drawn for this demo; Cover stars cut from /_img/photos/photo-01 … 10.jpg; avatar /_img/photos/photo-03.jpg; DEPO mark /_img/site/logo/logo.png |
Borrowed
- The MCP transport (JSON-RPC over POST, JSON answers, no sessions kept) and the API shape follow demo30's
mcp.php/api.phpin this album. - Noto Color Emoji — Google, SIL Open Font License 1.1 (Google Fonts v47). Unbounded (NaN), Onest (Dmitri Voloshin) — SIL OFL 1.1.
- Nothing else borrowed: the sticker art is drawn in
config/demo32/art.js.
Config
config/demo32/nginx.conf: /demo32/api.php and /demo32/mcp.php run in the front PHP pool (bodies up to 9 MB: 20 files as base64 JSON); /demo32/media/ serves only .svg .png .gif .webp .webm, with Content-Security-Policy: default-src 'none'; style-src 'unsafe-inline'; img-src data:; media-src 'self'; sandbox and a week of cache; stickers-db.php is never run from the web. PHP needs pdo_sqlite, zip, intl (slugs, Unicode normal form) and imagick (GIF frame count; optional) — all installed on dev0.
Visitor data on the live tree (never delete or replace): public/_db/demo32-stickers.sqlite, public/_db/demo32-zip/, public/demo32/media/.
Notes
- WebM: the size is taken from the browser on upload (or
width/heightin the API), not parsed on the server. The seed WebMs are VP9 with alpha (Chrome, Firefox play the transparency; Safari shows WebM without alpha). - Depo beta 0.01 is drawn for dark chats (thin yellow outlines): it reads best in the dark picker; on the paper grid it is lighter.
- GIFs are 320 px with 1-bit transparency, so their white edge is a little rough — as GIFs are.
- Telegram-ready packs (512 px WebP / PNG, ≤ 3 s VP9 WebM ≤ 256 KB) could be checked per sticker and flagged in the manifest — not done yet.
Suits a site for…
What kind of website would this design fit? Agree with a tag by clicking it, or add your own — a tag can be several words.
No tags yet — be the first.
Comments 0
No comments yet — be the first.