# Living Logo

> Design a living character logo from a one-sentence brief, entirely as code — no image models. Builds a simple, cute, rounded mascot as a parametric SVG rig with CSS keyframe animation and delivers three packs from it - the mark (animated logo on a solid background), six looping states (idle, happy, thinking, error, sleep, loading) and a sticker pack (12–16 expressions) with optional GIF/WebM/APNG export for WeChat, Telegram, Discord, Slack, LINE and Feishu. Use when the user asks for an animated or living logo, a mascot or IP character that moves, 会动的 logo, 动态吉祥物, 表情包, emoji or sticker pack, 微信表情, loading / empty-state / 404 characters, or wants three directions and six animated candidates to pick from.

- Skill: `zluckyhou/living-logo` (Agent Skill, multi-file: 5 files)
- Install (CLI): `npx skillmds@latest add zluckyhou/living-logo`
- Raw SKILL.md: https://api.skillmd.com/api/skills/zluckyhou/living-logo/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Design & Media
- Author: zluckyhou (https://skillmd.com/u/zluckyhou)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/zluckyhou/living-logo

---


# Living Logo

Turn a one-sentence brief into a character that is **alive**: one simple rounded mascot,
built as an SVG rig, animated with CSS keyframes, delivered as a logo, a set of UI states
and a sticker pack. It is alive because the whole head *turns* — a real 3D yaw with the two
eye-holes sliding and foreshortening across it — not because something wiggles in place. Everything is code — readable, recolorable, animatable, under 3 KB a
file — and plays in any browser, README, docs tool or chat app. No image-generation model is
called at any point; do not offer one.

## What you deliver

```
<name>/
├── manifest.json                 brief, rationale, tokens, rig recipe, file list — executable by compose.py
├── character/mark.svg            the logo: whole silhouette centred on --c3, head turning
├── states/                       idle · happy · thinking · error · sleep · loading   (transparent)
├── stickers/                     01-hi … 16-awkward, each with a die-cut plate       (transparent)
│   └── export/<platform>/        only if export tooling ran (gif / webm / apng)
└── preview.html                  one page where everything above is playing
```

Every SVG is self-contained: `viewBox="0 0 512 512"`, one `<style>` block, three color
tokens on the root element, no text, no fonts, no scripts, no external references, a
`prefers-reduced-motion` guard. Read `references/rig-spec.md` before writing the first file.

The head turn uses a 3D `rotateY` on SVG elements. Chromium and WebKit render it; an engine
that flattens SVG 3D degrades to a correct **static** face, because the orbit is identity at
yaw 0 — never restructure it in a way that loses that property.

## Workflow

1. **Parse the brief.** Note the explicit subject (if any), product, audience, personality,
   palette or brand color, and which packs are wanted. Default packs when unspecified:
   mark + states. Offer the sticker pack as the third pack; build it when the user says yes.
2. **Infer context before asking.** In a product repository read the README, app metadata,
   landing copy and design tokens (a brand color there feeds `--from-brand`). Treat context
   as sufficient when you can state what the product does, who it is for and how it should
   feel. Otherwise ask **one** consolidated round of three questions (does / for whom / feels
   like) and continue with the best interpretation — never a second questionnaire.
3. **Propose three directions** in one compact line each:
   `<subject> — <product connection> — <silhouette: body + species feature>`.
   With an explicit subject, vary treatment (body shape, feature, mouth, palette mood).
   Without one, propose three genuinely different subjects, each tied to a different product
   promise; familiar animals first, objects/robots/ghosts only with a product reason. Every
   direction names its species feature (a bear is its muzzle, a cat its ears, a seal its
   flippers) — ears on a round head are not a character.
   End with: *"I'll build six animated candidates — two per direction, A1/A2, B1/B2, C1/C2
   — unless you'd rather adjust."*
   Do not build before agreement unless the brief already authorizes it.
4. **Build the six candidates as marks** — one `scripts/compose.py … --kind mark` command
   each (`candidates/A1-<subject>.svg` …), or hand-assembly from
   `references/parts-library.md` when Python is unavailable. Two variants of a direction
   differ in one deliberate axis (body, feature, lens, palette hue), not in random noise.
   Vary the color strategy across the six (see `references/color-system.md`).
5. **Show them on one wall.** `python3 scripts/export.py wall candidates/*.svg --out
   candidates/preview.html --auto-label --caption "A1=…" …`, or fill
   `references/wall-template.html` by hand. Tell the user where it is and list each label
   with its direction and one-line rationale. Deliver all six; do not rank, filter, or
   quietly regenerate any of them.
6. **On the pick, write `manifest.json` and build the packs** from it:
   `python3 scripts/compose.py --manifest manifest.json --out-dir <name>/` produces the mark,
   every listed state and sticker, and `preview.html`. By hand: `references/states.md` and
   `references/stickers.md` hold the same recipes. The rig stays identical across files —
   only face slots, `<style>` and overlays change.
7. **Validate.** `python3 scripts/validate.py --kind mark character`, `--kind state states`,
   `--kind sticker stickers`. Fix every FAIL; fix WARNs unless the user asked for the
   deviation. Without Python, check by eye against the budgets below.
8. **Export when asked or when a chat platform is the target** and the tooling exists
   (`scripts/export.py gif|webm|apng --platform …`). If Playwright/ffmpeg are missing, say
   so, deliver the SVGs, and give the one-line install command — never fake a GIF.
9. **Report** (see Delivery).

Generate refinements only when the user asks. A new draw is a new set of labels (A3, A4 …).

## Budgets — the taste, written down

**Shape.** One dominant continuous silhouette from **1–5 primitives** inside `#character`
(stickers may add 2 for a mouth, brows or a prop; the plate and the mask are not counted):
body (1, cloud body 3) + one species feature (0–2) + limbs (0–2). Thick rounded masses;
every tip visibly blunt; paired features in pairs. **Flat fill only** — no outlines,
gradients, highlights, shading, texture, nostrils or decorative marks. A darker lower mass
in particular is forbidden: dark reads as *feature* here, so a shade grows a phantom muzzle.
The plumpness comes from the silhouette and the saturation, never from a tone. Must read at
32 px.

**Color.** Three semantic tokens on the root: `--c1` body, `--c2` sticker ink (mouth and
brows only), `--c3` the ground the character sits on. Bands: `--c1` L 0.55–0.68 with the
chroma left high — the body carries the identity; `--c3` L 0.94–0.97, chroma ≤ 0.02;
`--c2` L ≈ 0.22 tinted toward the body hue. **One ratio decides everything: `--c1` on
`--c3` ≥ 2.5:1** — the eyes are holes onto `--c3`, so that single number governs whether
the silhouette reads *and* whether the face reads. Sticker ink `--c2` on `--c1` ≥ 4.5:1.
Transparent stickers always carry the `--plate` die-cut backing (white by default).
`compose.py --from-brand "#hex"` derives a compliant palette and darkens the body until it
earns the ratio.

**Face.** Two lenses, punched **through** the body with a `<mask>` so they are holes, not
shapes laid on top — that is what keeps them right on a transparent file and on the mark's
ground alike. Never draw an eye as a filled shape over the body. The anchor is derived from
the body's own bbox, never a fixed canvas coordinate: eye line at 0.40 of the body height,
spacing at ±0.205 of its width, sizes scaled by the body width. **The mark and the states
are mouthless** — the two lenses carry the whole expression, by re-posing one primitive
(shape, w, h, tilt, dy). Only the sticker pack may add a mouth, brows or cheeks.

**Composition.** The **whole** silhouette, centred, with a margin, on a plain `--c3` ground.
Nothing is ever cropped and there is no rounded-rect container: a cropped or boxed
silhouette reads as a tile, and the silhouette *is* the identity. The transform is derived
from the rig, never guessed (`rig-spec.md`). States and stickers: the same composition,
transparent.

**Motion.** Five tracks, each on its own element so their transforms compose instead of
overwriting each other: `#character` the state's personality (a root preset), `#tilt` the
head roll, `#squash` a counter-phase vertical squash, `#eye-l`/`#eye-r` the 3D orbit,
`.lens` the foreshortening with the blink folded in. Two animations on the *same* element
do not compose — the later one wins outright — so anything sharing an element shares one
keyframe track. The head turn is a real `rotateY` under `perspective`, so the browser
interpolates it continuously; **never sample a smooth curve into many keyframes with
per-segment `ease-in-out`**, which brakes to a stop at every one of them. Head roll ≤ 3°,
squash ≤ 1 %; the turn 9 s for idle, 2–5 s for active states; give the layers coprime
periods so the loop does not announce itself. Reduced-motion guard always. Presets live in
`references/motion-presets.md`.

**Character.** Large head, compact proportions, soft cheeks, widely spaced simple eyes, calm
friendly expression by default. Simplicity and lovability beat anatomical correctness.

## Building a file

Prefer `scripts/compose.py` — the parts, presets, recipes and composition math are encoded
there, so the agent decides the recipe and the script guarantees the geometry
(`python3 scripts/compose.py --list` shows every body, feature, limb, lens, mouth, state,
sticker and palette). The face anchor, the yaw cylinder and the perspective compensation are
all derived from the body's bbox — never hand-place an eye. By hand: start from `assets/examples/seal/states/idle.svg`, keep the
slot structure from `references/rig-spec.md`, swap parts from `references/parts-library.md`,
paste presets from `references/motion-presets.md`. Static poses go on
`<g class="pose" transform="…">` wrappers; animated elements never carry a `transform`
attribute. Name the character if the user has not; it goes into `aria-label` and the
manifest.

Two complete example sets to imitate: `assets/examples/seal/` (manifest, mark, six states,
sixteen stickers, `preview.html` — all generated from the manifest) and
`assets/examples/wall/` (six candidate marks from six bodies/features, with their wall).

## Tooling (optional, never required)

- `scripts/compose.py` — stdlib only; builds any mark/state/sticker from a recipe, a whole
  set from a manifest, a palette from a brand color; prints contrast notes.
- `scripts/validate.py <files|dirs> --kind mark|state|sticker [--json]` — stdlib only;
  FAILs on portability/accessibility breaks, WARNs on budget, structure and contrast drift.
- `scripts/export.py wall …` — stdlib only; builds `preview.html`.
- `scripts/export.py gif|webm|apng|mp4 <svg> --platform <name>` — needs `pip install
  playwright && python3 -m playwright install chromium` and ffmpeg; renders frames by
  stepping the Web Animations clock, encodes with platform presets, retries under the size
  budget. `scripts/export.py platforms` prints the presets.

Runtimes that cannot run Python still get the full deliverable: the SVGs and a hand-filled
wall. Say which platforms accept SVG directly and which need a conversion.

## Delivery

Report, in this order: the pick (label, subject, species feature, rationale); tokens and
their contrast notes; the rig recipe; every file path grouped by pack with its motion
recipe; the preview page; validation summary (or "checked by eye: …"); export results with
sizes versus platform limits; what was not built and why. Keep it to one screen. Then offer
the next pack or a refinement round — not both at once.

## Never

- Call an image/video model, trace a raster, or describe the output as AI-generated art.
- Use `<text>`, fonts, scripts, gradients, filters, external refs, or a fourth semantic color.
- Add shading of any kind, or crop the silhouette, or put it in a rounded-rect container.
- Draw the eyes as filled shapes on top of the body instead of punching them through the mask.
- Give the mark or a state a mouth, or exceed the primitive budget without being asked.
- Ship a transparent sticker without its plate unless the user asked for that.
- Rank, filter, or silently regenerate candidates; deliver what you drew.
- Inline two rigs on one page without prefixing ids (use `<img>`).
- Ask a second round of discovery questions.

