---
name: web-ui-replication
description: "Replicate mobile UIs from screenshots into HTML/CSS."
version: 1.0.0
author: Hermes Agent
license: MIT
platforms: [linux, macos, windows]
metadata:
  hermes:
    tags: [frontend, html, css, javascript, mobile, ui-replication, banking, mockup, web-app]
    related_skills: [plan, inspecting-hermes-desktop-dom]
---

# Web UI Replication

Replicate real-world mobile and web app UIs from screenshots using HTML, CSS, and vanilla JS. Produce standalone pages that look native on phones — including dark-mode banking interfaces, transaction flows, and multi-screen navigation.

## When to Use

- User shares a screenshot of a mobile app screen and asks "make this in HTML"
- Building demo / study pages that mimic a real banking, social, or commerce app
- Creating a multi-page static prototype that navigates like a real app
- Need a mobile web page that hides the browser chrome and feels native

## Workflow

### 1. Analyze the Screenshot

Identify these elements before writing any code:

| Element | What to Note |
|---------|-------------|
| **Background** | Solid color, gradient, or image? |
| **Typography** | Font sizes, weights, colors (light/dark mode) |
| **Layout rhythm** | Padding, gaps, border radius values |
| **Icons** | SVG inline, emoji fallback, or icon font? |
| **Interactive rows** | Tappable lists with chevrons, buttons |
| **Data** | What's static vs. dynamic (dates, times, amounts) |
| **Safe area** | Notch, status bar, home indicator offsets |

**PRIVACY RULE:** When the screenshot contains financial, medical, or personal data (account numbers, card numbers, balances, names), ALWAYS replace with dummy data. Ask the user if unsure, but default to placeholders.

### 2. Build the HTML Structure

Use semantic divs with class names that match the visual hierarchy:

```html
<div class="container">
  <div class="header">
    <div class="back-btn">←</div>
    <h1>Screen Title</h1>
  </div>
  <div class="balance-section">...</div>
  <div class="list">...</div>
</div>
```

### 3. CSS for Native Mobile Feel

**Critical viewport meta:**
```html
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
```

**Standalone web app meta (hides browser chrome on home screen):**
```html
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#121212">
```

**Safe area padding (iPhone notch / status bar):**
```css
body {
  padding-top: max(28px, env(safe-area-inset-top, 28px));
  padding-bottom: max(12px, env(safe-area-inset-bottom, 12px));
}
```

**Dark mode banking defaults:**
```css
body {
  background: #121212;
  color: #ffffff;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.detail-box {
  background: #1e1e1e;
  border-radius: 12px;
  padding: 16px;
}
```

### 4. Multi-Page Flow

For flows (login → select account → overview → detail), create separate HTML files with `<a href="page2.html">` navigation.

Keep all pages in one directory so relative links work.

### 5. Bottom Button Positioning

When a screenshot shows a prominent button at the bottom of a screen (e.g., "Log in"), check whether it is:

- **Fixed/sticky** (always visible, overlays content) — use `position: fixed; bottom: 0;`
- **Flow-based** (sits at the bottom of the content, scrolls with the page) — use standard block layout with `text-align: center;`

For centered pill buttons at the bottom of the content:
```css
.login-section {
  padding: 16px 16px 40px;
  text-align: center;
}
.login-btn {
  display: inline-block;
  width: auto;
  min-width: 220px;
  padding: 16px 40px;
  border-radius: 28px;
}
```

NOT full-width block. NOT `position: fixed` unless the screenshot clearly shows an overlay.

### 6. Dynamic Data with JavaScript

Generate dates, times, and amounts client-side so they update on refresh:

```javascript
(function() {
  const now = new Date();
  // Transaction date: "3 August 2026"
  const months = ['January','February',...];
  const txDateStr = now.getDate() + ' ' + months[now.getMonth()] + ' ' + now.getFullYear();
  document.getElementById('tx-date').textContent = txDateStr;
  
  // Time: 14 minutes ago
  const txTime = new Date(now.getTime() - 14 * 60 * 1000);
  const timeStr = pad(txTime.getDate()) + '-' + pad(txTime.getMonth()+1) + '-' + txTime.getFullYear() 
                  + ' at ' + pad(txTime.getHours()) + '.' + pad(txTime.getMinutes()) + ' time';
  document.getElementById('tx-time').textContent = timeStr;
})();
```

### 6. Test on Real Mobile

Serve locally and expose via Tailscale Funnel:

```bash
# Terminal
python3 -m http.server 8765 --directory /path/to/project --bind 127.0.0.1

# Another terminal
sudo tailscale funnel --bg 8765
# URL: https://your-machine.tailnet.ts.net/page.html
```

Add the page to your phone's home screen to test the no-URL-bar experience.

## Pitfalls

1. **Don't copy real PII/financial data from screenshots unless the user explicitly asks.** Use dummy names, account numbers, and card numbers by default. Replace with placeholders like `BE12 3456 7890 1234` or `5127 88XX XXXX 6152`.

2. **Don't forget `viewport-fit=cover`**. Without it, the page leaves white bars at the top/bottom on iPhones with notches.

3. **Don't use `&` backgrounding in `terminal()`**. Use `background=true` parameter instead. The tool handles process lifecycle properly.

4. **Test pull-to-refresh behavior** on iOS Safari when in standalone mode. If the page doesn't scroll, pull-to-refresh may not work. Ensure `body` has `min-height: 100vh` and content exceeds viewport.

5. **Server caching on mobile browsers**. Hard-refresh or restart the local server after CSS changes — mobile browsers cache aggressively.

6. **Verify the HTTP server's working directory.** `python3 -m http.server` inherits the process cwd. If it launches from a subdirectory (e.g., via a background process from a different working directory), relative paths like `kbc-flow/index.html` will 404. Always check: `ls -la /proc/<PID>/cwd` or use absolute paths in the `--directory` argument.

7. **Separate hero vs. account images.** When a user provides multiple photos (login hero + profile avatar), copy them to distinct filenames in the project directory. Do not overwrite one with the other.

## Banking UI Patterns

Common patterns seen in banking apps:

- **Amount display**: Large bold text (`font-size: 40px; font-weight: 700;`), centered, with `letter-spacing: -1px`
- **Gray detail boxes**: `background: #1e1e1e; border-radius: 12px; padding: 16px;`
- **Labeled rows inside boxes**: `<span class="box-label">Date:</span>` with `font-weight: 600; color: #fff;`
- **List rows with chevrons**: Flex row with icon + text + right chevron SVG
- **Bottom nav bars**: Fixed position with 4 icon+label items
- **Search bars**: Dark rounded input with magnifying glass icon

## References

- `references/banking-transaction-detail.md` — condensed layout recipe for the gray-box transaction detail screen with dynamic dates
- `references/biometric-login-webauthn.md` — WebAuthn Face ID/Touch ID setup for home-screen web apps
- `references/home-screen-icon.md` — custom home screen icon setup with `apple-touch-icon` meta tags

## Related Skills

- `plan` — for planning multi-page frontend projects before building
- `inspecting-hermes-desktop-dom` — for reading live app DOM via CDP if you need to inspect a real web app
