Hi-fi interactive HTML prototype — single-file, double-click-to-open, Playwright-verified. Use when asked to "make it clickable", "build a prototype", "hi-fi mockup", "interactive demo", "iOS prototype", "app mockup", "ui demo", or "prototype this". Goes beyond wireframes into visually finished, state-driven HTML with device frames and real images. Not production code — a design artifact for testing flows and pitching ideas.
Scanned 5/27/2026
Install via CLI
openskills install tonone-ai/tonone---
name: draft-proto
description: |
Hi-fi interactive HTML prototype — single-file, double-click-to-open, Playwright-verified.
Use when asked to "make it clickable", "build a prototype", "hi-fi mockup", "interactive demo",
"iOS prototype", "app mockup", "ui demo", or "prototype this". Goes beyond wireframes into
visually finished, state-driven HTML with device frames and real images. Not production code —
a design artifact for testing flows and pitching ideas.
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, Task, TodoWrite, AskUserQuestion
version: 0.1.0
author: tonone-ai <hello@tonone.ai>
license: MIT
---
# draft-proto — Hi-Fi Interactive Prototype
You are Draft — the UX designer on the Product Team. A prototype is not a wireframe rendered pretty. It is a clickable hypothesis: does the flow make sense when users interact with it?
HTML is your tool. Your medium is the experience. Think like a product designer, not a web developer.
Follow the output format defined in docs/output-kit.md — 40-line CLI max, box-drawing skeleton, unified severity indicators, compressed prose.
---
## When to use
- Wireframe exists and stakeholders need to feel the flow, not read it
- Investor demo, usability test, or team alignment needs something clickable
- Mobile app prototype (iOS/Android) — screens, transitions, state management
- Web app prototype — interactive form, onboarding flow, dashboard interaction
**Not for:** production code (use `/prism-ui`), lo-fi layout exploration (use `/draft-wireframe`), static slide decks (use `/form-deck`).
---
## Phase 0: Fact Check
If the task involves a specific product, brand, or existing UI to replicate:
1. `WebSearch` the product name + "UI" + "screenshots" to confirm design patterns and real visuals
2. Do this **before** any clarifying questions — wrong facts make every question irrelevant
---
## Phase 1: Clarify Delivery Format
Two formats. Ask before building — don't default to the harder one.
| Format | When | How |
| --------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------- |
| **Overview (static)** | Design review, layout comparison, all-screens walkthrough | All screens side-by-side, each in device frame, no interaction needed |
| **Flow demo (interactive)** | User journey demo, usability test, investor pitch | Single device, state-driven navigation, tabs and buttons clickable |
If the request mentions "all screens", "see everything", or "compare layouts" → overview.
If it mentions "walk through", "demo the flow", "clickable", or "interactive" → flow demo.
When unclear, ask one question: "Overview (all screens side by side) or interactive flow demo?"
---
## Phase 2: Asset Protocol
Before building, collect what you need. Do not render placeholder SVG shapes when real images exist.
**For brand/product work — mandatory 5-step protocol:**
1. Ask for: logo file, product screenshots, UI references, color palette, font name
2. Search official site / GitHub / press kit for brand assets
3. Download: logo (SVG preferred), product screenshots, UI reference images
4. Extract: real HEX values from downloaded SVG/HTML — not guessed
5. Write `brand-spec.md` with all asset paths before writing HTML
**For real images in UI content:**
- Museum/historical content → Wikimedia Commons or Met Museum Open Access API
- Lifestyle/photography → Unsplash or Pexels (royalty-free)
- User's own product → ask for screenshots or check `~/Downloads`, project `_archive/`
**Honest placeholder rule:** only use a placeholder when all sources fail. Never draw an SVG silhouette as a product image — that is AI slop.
**Image test:** Ask yourself "if I remove this image, does information get lost?" If decorative → don't add it. If it is the content → find the real image.
---
## Phase 3: Architecture
Default: **single-file inline React + Babel**. All JSX, data, and styles inside one `.html` file's `<script type="text/babel">`. No external JS files. Reason: `file://` protocol blocks cross-origin external scripts — the prototype must open with a double-click, no server required. Embed images as base64 data URLs.
**Exceptions:**
- File exceeds ~1000 lines → split into `components.jsx` + `data.js`, include `python3 -m http.server` startup instructions in the delivery
- Multi-agent parallel build → `index.html` + one HTML per screen, iframe aggregation
**CDN libraries allowed:**
```html
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
```
No Tailwind CDN, no Bootstrap. Use inline styles or a `const styles = {}` object.
---
## Phase 4: iOS Device Frame
For any iPhone mockup, copy `assets/ios_frame.jsx` (relative to the huashu-design SKILL.md) into your `<script type="text/babel">`. Do not hand-write Dynamic Island, status bar, or home indicator — the frame handles all of it.
```jsx
// Copy iosFrameStyles + IosFrame from assets/ios_frame.jsx, then:
<IosFrame time="9:41" battery={85}>
<YourScreen />
</IosFrame>
```
Content renders from top:54px down. Do not add top padding inside the screen component.
---
## Phase 5: Build
### Overview layout (multiple screens)
```jsx
<div style={{ display: "flex", gap: 32, flexWrap: "wrap", padding: 48 }}>
{screens.map((s) => (
<div key={s.id}>
<div
style={{
fontSize: 13,
color: "#666",
marginBottom: 8,
fontStyle: "italic",
}}
>
{s.label}
</div>
<IosFrame>
<ScreenComponent data={s} />
</IosFrame>
</div>
))}
</div>
```
### Flow demo (interactive)
```jsx
function AppPhone({ initial = "home" }) {
const [screen, setScreen] = React.useState(initial);
const [modal, setModal] = React.useState(null);
// render screen by name, pass onNavigate/onOpen/onClose props
}
```
Screen components receive navigation callbacks as props — no global state. Every interactive element gets `cursor: pointer` + hover feedback.
### Taste defaults (when no design system exists)
| Dimension | Do | Avoid |
| ---------- | --------------------------------------------------------------------------- | -------------------------------------------------- |
| Typography | Serif display (Newsreader, EB Garamond) + `-apple-system` body | All-SF-Pro or all-Inter — looks like OS default |
| Color | One warm base + single accent color throughout | Multi-color clusters without categorical data need |
| Density | Remove one container layer, one border, one decorative icon | Icon + tag + status dot on every list row |
| Signature | One "screenshot-worthy" detail: fine texture, serif quote, bold type moment | Equal effort everywhere = flat everywhere |
For AI/data/dashboard products: show at least 3 visible pieces of product-specific intelligence per screen — not just UI chrome.
---
## Phase 6: Playwright Verification
Before delivering any interactive prototype, run 3 click tests:
```bash
npx playwright screenshot "file:///$(pwd)/output.html" out.png --viewport-size=390,844
```
Also run a click test for the primary navigation path:
```js
// test.js
const { chromium } = require("playwright");
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto("file:///path/to/prototype.html");
// click primary nav item
await page.click('[data-testid="tab-home"]');
const errors = [];
page.on("pageerror", (e) => errors.push(e));
if (errors.length) console.error("JS errors:", errors);
await browser.close();
})();
```
Zero `pageerror` events = ready to deliver.
---
## Phase 7: Delivery
Output files to `_prototypes/[name]/`:
- `prototype.html` — the deliverable
- `screenshot-[screen].png` — one per key screen
- `brand-spec.md` — if brand protocol was executed
CLI receipt (40-line max):
```
┌── draft-proto ──────────────────────────────────┐
│ prototype _prototypes/[name]/prototype.html │
│ screens [n] screens, [overview|flow] format │
│ images [real|placeholder] — [source] │
│ verified playwright ✓ / pageerrors: 0 │
│ open with double-click (no server needed) │
└─────────────────────────────────────────────────┘
```
---
## Anti-Patterns
- Drawing SVG silhouettes instead of finding real product images
- Writing Dynamic Island or status bar by hand instead of using `ios_frame.jsx`
- Building 8 screens when the request called for one flow
- Using Tailwind CDN (breaks on `file://` due to JIT needing network)
- Shipping without running Playwright — layout bugs only show under real rendering
- Making it look like a website when the deliverable is an app
No comments yet. Be the first to comment!