---
name: Playable
description: Build a single-file HTML5 playable ad of a game from its own assets (a Unity project or an asset folder) — one index.html under 5 MB with every sprite, sound and font inlined, portrait-first and responsive, touch and mouse, a tutorial hand, a guaranteed end card with the install button and the ad-network hooks (MRAID, AppLovin, Unity Ads, Google) — then serve it on the LAN for phone tests and hand it over with a README and the copy-to-site steps. Use when Michelle says "/Playable", "playable", "playable ad for <game>", "build a playable of <game>", "HTML5 playable", "make the playable from the Unity project", or in Portuguese "monta um playable", "faz um playable do <jogo>", "playable ad do <jogo>", "playable em HTML5". Owns the v1 scope and its priority order, the PixiJS single-file stack, the inliner build script (inline_build.py beside this file), the size and performance budget, the test routine and the timebox rule. Never edits the source game project.
---

# Playable — single-file HTML5 playable ad from a game's assets

(Michelle Favero, 2026-11-05.) A playable ad is one web page that runs 20 to 40 seconds of one
mechanic and ends on a card whose button calls the ad network's install hook. Nothing is
installed; the page opens in any browser. This skill builds that page from a game we own the
assets of, in a timebox, and never touches the game project itself. First run: Cat Match
(GeekCats IP), see **Runs**.

## Inputs — ask only for what is missing

- **The game and where its assets are.** A Unity project (sprites, audio, fonts, the script that
  holds the match or movement rules) or a plain asset folder. Read only.
- **Output folder.** A new folder beside the source, `<Source>-Playable` by default. Everything new
  goes there: `src/`, `assets/`, `build/inline_build.py` (copied from this skill), `dist/index.html`,
  `README.md`.
- **CTA target.** The store link, or the game's page on the portfolio site when it is not in a store.
- **The timebox.** The end time is a hard stop. v1 ships whatever is stable at that time.
- **Where it will be published.** A folder in a static site (for Michelle's site: the Next.js project
  in `OneDrive\Portfólio\Site`, file at `public/<game>/index.html`, served at
  `stelko.com.br/<game>/`). Give the copy and deploy steps; do not deploy.

## Tech — fixed

- **PixiJS** (one minified file, inlined) plus vanilla JavaScript. No framework, no bundler.
- **No external request at runtime.** Every image, sound and font is a `data:` URI inside the HTML.
  The build script does this; the source `src/index.html` references files normally.
- **Minified game code.** (Michelle Favero, 2026-11-05.) The build minifies every JS and CSS file
  it inlines with esbuild through `npx` (already-minified `*.min.js` files are left alone), so the
  page parses faster and the source stays readable. The shipped file carries no comments: esbuild
  drops the code comments, including the hook notes, and the build strips the HTML comments; only
  the one-line MIT banner of PixiJS stays, because its licence asks for it. The first run needs
  the network once to fetch esbuild; when it cannot run, the file goes in as written and the build
  report says `NOT minified`.
  `--no-minify` skips the step when debugging the built file. Keep `src/` as the readable source;
  never edit `dist/`.
- **Budget.** Final `dist/index.html` under 5 MB (AppLovin, Unity Ads, Google and Meta all sit at
  or below that). Sprites at the size they are drawn, never larger than 256 px for a tile. Sounds as
  mp3, short, under 100 KB each. Report the final size in the README.
- **Images as WebP.** (Michelle Favero, 2026-11-05.) Sprites and backgrounds go in as WebP,
  quality 85 to 90, alpha kept; PNG or JPG only where WebP is not smaller. `webp_assets.py` beside
  this file converts a folder and prints the table. Measured on Cat Match: the images went from
  1091 KB to 409 KB, and base64 adds a third to every byte, so this is the biggest single saving
  in the file.
- **Layout.** Portrait first, designed at 1080x1920 logical, scaled to fit any aspect ratio; in
  landscape, letterbox over the background and keep the board whole. Touch and mouse, pointer
  events only.
- **Performance.** 60 fps target on a mid-range phone: one sprite sheet or at most a dozen textures,
  no per-frame allocations in the game loop, tweens on a single ticker.
- **Audio** unlocks on the first touch (WebAudio rule); a mute button in a corner.
- **Hooks.** A `CTA_URL` constant. On the CTA click: `window.mraid.open(url)` if `mraid` exists,
  else `window.open(url)`. A comment block marks where AppLovin (`mraid` + `ad-ready` events),
  Unity Ads (`playable:ready`) and Google (`ExitApi.exit()`) go. v1 ships the mraid-or-open path
  only; per-network QA is a later pass.

## Gameplay — v1 scope in priority order

Build in this order and stop adding when the clock says so. Each step must leave a playable page.

1. **The mechanic, one level.** The game's core loop reduced to one screen, with its own HUD art.
   For a match-3: 6x6 board, 5 piece types, swap by drag or tap-tap, match 3+, pop effect, gravity,
   refill, cascades, a move counter and a goal bar.
2. **Guaranteed outcome.** Tune the goal so an average player wins by two thirds of the moves. Out
   of moves still goes to the end card. A hard cap of 30 seconds of play also goes to the end card.
3. **Tutorial hand.** After 2 s idle at start, the game's own hand sprite animates a valid move;
   repeats every 4 s idle; gone after the first successful move.
4. **End card.** Background, logo, characters, a pulsing CTA button with the game's own button art,
   calling `CTA_URL`. A win shows the game's own win moment first.
5. **Sound.** Move or pop sound, a chain sound by combo length, the win sound, one character sound
   on the tutorial hand.
6. **One special**, only if time: the game's power piece (for a match-3, a 4-match makes a bomb
   that clears its row).

## Working method

- **Checkpoints every 45 minutes.** Serve `dist/` with `python -m http.server 8080` from the output
  folder and print the LAN URL (`http://<machine IP>:8080/`). Michelle opens it on her phone on the
  same Wi-Fi. A checkpoint that does not open on the phone is not a checkpoint.
- **Rebuild** with `python build/inline_build.py` after every change; test the built file, not the
  source, because inlining is where fonts and audio break.
- **Timebox rule.** At the end time, stop, rebuild, write the README, and say which of the six
  steps are in. Nothing half-built stays in the shipped file; comment it out.
- **Never** edit the source game project, commit in any repo, or deploy the site. The README tells
  Michelle the copy and deploy steps.

## README — what it carries

Size of `dist/index.html`, which gameplay steps are in, how to rebuild, what each asset came from
(path in the source project), the CTA target, how to copy it into the site and deploy, and what the
next pass would add (per-network hooks, specials, polish).

## Runs

- 2026-11-05, Michelle Favero: **Cat Match** (GeekCats IP, Michelle's own match-3). Source: the
  Unity 6 project `C:\GeekCats\CatMatch` (JuiceFresh-based, 330 levels, migrated 2026-10-08).
  Sprites in `Assets\JuiceFresh\Textures` (Items/item_01..06 = the six cat faces at 160 px,
  item_0X_bomb = colour bombs, ingredient_01/02 = fish and bird; backgrounds/background_01..05;
  menu/game_menu = HUD strip, finger.png, score and moves banners, star bar, tutorial overlay;
  effects/ and effects/Expl = pop frames). Audio in `Assets\JuiceFresh\Audio` (Combo 01..06,
  Cheers, Button, Color_bomb, Miau* and the Cat Meow Pack). Fonts in `Assets\JuiceFresh\Fonts`
  (BorisBlackBloxx, Candy Script). Logo and characters in `Originais`. Look reference:
  `Screenshots\Finais`. Rules reference: `Scripts\LevelManager.cs`. Minimal asset set measured
  under 500 KB. Output folder `C:\GeekCats\CatMatch-Playable`; publish at
  `stelko.com.br/catmatch/`; CTA default `https://stelko.com.br/#cat-match`. Timebox: one evening,
  v1 only. Result: pending — the building session records it here.
