# App Hero (Moonarc)

A hero for a mobile app: the headline, the rating line (stars, the average, how many rated and where) and the store buttons beside a phone on a disc of the app's colour. The phone's screen is drawn from rows (AppScreen), so a palette recolours it and no screenshot goes stale; two or three screens take their turn once, then the first returns and rests, and the phone holds still while it is pointed at. On a wide screen a QR code to the app sits beside the buttons, since a reader on a laptop has the phone in their other hand. A card can float beside the phone, the way a notification would. The store buttons are text, as neither store lets its badge be redrawn. Zero JavaScript.

- Pro block. Install: `npx shadcn@latest add @moonarc-pro/hero-app` (license key required)
- Tier B · category section · trigger load
- Readout: `<HeroApp stores={[{ href, name, note }]} rating={{ value, count }} screens={[{ title, rows }]} />`
- Browser support: widely (Chrome 105 · Firefox 110 · Safari 16); elsewhere: without container units the drawn screens keep the page's text size
- Measured cost: 0 B JS of its own · uses Reveal + runtime (with dependencies 3.0 kB raw; CSS 33.9 kB raw)
- Page: https://moonarc.dev/components/hero-app/

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `stores` | `{ href: string; name: string; note?: string }[]` | none | The stores as text buttons: note is the small line over the name ("Download on the" over "App Store"). Slot "actions" replaces them and the QR code, for the stores' official badges. |
| `screens` | `AppScreen props[]` | none | One to three screens. The first is shown at once and is the one at rest; each other one takes a turn of 3.2 s from the third second, then the first returns. |
| `phoneLabel` | `string` | none | What the phone shows, for a screen reader: one name for the picture. Unset, the phone is decoration. |
| `qr` | `{ value: string; caption?: string; label?: string }` | none | A QR code to the app beside the buttons, on a wide screen with a pointer only. value is what it opens; label is what a screen reader hears (default "QR code to" and the value). |
| `rating` | `{ value: number; count: string; source?: string }` | none | The rating line: "4.8 out of 5 from 12,400 ratings on the App Store". count is written as given. |
| `callout` | `{ title: string; text?: string; app?: string }` | none | A card floating over the disc's edge, beside the phone. Decoration: hidden from a screen reader. |
| `headline` | `string` | none | The headline, split by word. Slot "headline" wins and may hold an <em>. |
| `eyebrow` | `string` | none | A short line above the headline. Slot "eyebrow" wins. |
| `copy` | `string` | none | A paragraph under the headline. |
| `note` | `string` | none | A short line under the buttons. |
| `block` | `1 | 2 | 3 | 4 | 5` | `1` | The colour block of the disc and the callout's icon. |
| `model` | `'island' | 'notch' | 'punch'` | `'island'` | The phone's cut-out (PhoneFrame). |
| `level` | `1 | 2` | `1` | Heading level of the headline. |
| `media` | `'right' | 'left'` | `'right'` | Side of the phone on a wide screen. |
| `tone` | `'surface' | 'muted' | 'ink' | 'brand'` | `unset (paints nothing)` | The hero's ground. |
| `density` | `'compact' | 'cozy' | 'roomy'` | `'cozy'` | Block padding ×0.8 / ×1 / ×1.25 through --ma-density. |

## Usage

```astro
---
import HeroApp from '@/components/moonarc/pro/HeroApp.astro';
---
<HeroApp
  eyebrow="For iPhone and Android"
  copy="Small habits, one tap a day. The streak keeps itself."
  stores={[
    { href: 'https://apps.apple.com/app/id000000000', note: 'Download on the', name: 'App Store' },
    { href: 'https://play.google.com/store/apps/details?id=com.example', note: 'Get it on', name: 'Google Play' },
  ]}
  qr={{ value: 'https://example.com/get', caption: 'Point your phone\'s camera here' }}
  rating={{ value: 4.8, count: '12,400', source: 'on the App Store' }}
  phoneLabel="The app's today screen: three of four habits done"
  screens={[
    { title: 'Today', rows: [{ kind: 'ring', value: 0.75, text: '3 of 4', label: 'habits done' }, { kind: 'checks', items: [{ text: 'Walk', done: true }, { text: 'Read' }] }] },
    { title: 'This week', rows: [{ kind: 'bars', values: [3, 4, 2, 4, 4, 3, 1], labels: ['M', 'T', 'W', 'T', 'F', 'S', 'S'], highlight: 4 }] },
  ]}
  callout={{ app: 'Sitename', title: '12 days in a row', text: 'Your longest streak yet' }}
>
  <span slot="headline">Keep the <em>small</em> promises</span>
</HeroApp>
```

## Reduced motion

The first screen only, with no turns; the callout is there at once.

## With ClientRouter

CSS and Reveal; a fresh page plays the turns from the start.

## Craft

- The turns are CSS delays written at build: each later screen fades in at its moment and out when the first returns, so the phone rests on the screen the page leads with, and nothing moves beside the headline after ten seconds.
- Each screen's own motion (its ring filling, its bars growing) is delayed to the screen's turn through --ma-as-at, so a screen fills as it is shown, not while it is hidden.
- Pointed at or holding focus, the phone holds still: the turns and the screens' own motion pause together.
- The QR code is for a wide screen with a pointer: on a phone it would ask the reader to scan the screen they are holding.
- The store buttons are the page's ink on its ground, the colour pair the stores' own badges use, on any palette.

## Replaces

- App landing page heroes with phone mockups
- App download sections with store badges

## Source

Pro block. The source is served by the license-gated registry: `npx shadcn@latest add @moonarc-pro/hero-app` with a key in components.json (https://moonarc.dev/account/). Everything it composes is free: split-text, reveal, phone-frame, app-screen.
