# SKAP design prototype

A clickable prototype of every SKAP page: static HTML, CSS and a little vanilla JS, no build step.
The UI is Norwegian bokmål (launch market Norway); code and comments are English.
Product context lives in `PRODUCT.md`, the visual system in `DESIGN.md` and on `prototype/system.html`.

## Run it

```sh
cd skap/design
python3 tools/serve.py            # http://127.0.0.1:8765/prototype/map.html
```

`serve.py` is a tiny static server with no-cache headers and byte ranges (the films need them).
Opening the files straight from disk mostly works too, but the photo cut-out and the films need http.

Demo account: `nora.bakken@eksempel.no` / `garderobe`. Everything you change is kept in
`localStorage` (key `skap.db.v1`); "Nullstill alle data" on `map.html` resets it. When the demo
data changes, `SEED_VERSION` in `assets/js/store.js` goes up and the demo account is rebuilt.

## Layout

| Path | What |
|------|------|
| `prototype/*.html` | one file per page; `map.html` links them all |
| `prototype/assets/css/tokens.css` | generated from `design-tokens.json`, do not edit |
| `prototype/assets/css/{base,layout,components,feedback}.css` | shared styles, bundled by `skap.css` |
| `prototype/assets/css/pages/*.css` | per-page styles |
| `prototype/assets/js/ui.js` | shared parts: header, tab bar, footer, films (`data-component="…"`), cards |
| `prototype/assets/js/store.js`, `data.js` | demo data and the localStorage store |
| `prototype/assets/js/cutout.js`, `cuteditor.js` | photo check, background removal, the cut step of the photo dialog |
| `prototype/assets/garments/photo/*.webp` | demo wardrobe: real garment photos, cut out |
| `prototype/assets/media/*` | muted background films and their posters |

## Rebuild generated files

| Command | Writes |
|---------|--------|
| `python3 tools/build_tokens.py` | `assets/css/tokens.css` from `design-tokens.json` |
| `python3 tools/build_icons.py` | `assets/js/icons.js` (Lucide sprite plus SKAP glyphs) |
| `python3 tools/build_media.py` | `assets/media/*` films (needs ffmpeg) |
| `<rembg venv>/bin/python tools/build_garment_photos.py [ids…]` | `assets/garments/photo/*.webp` (see the script header for the venv) |

## Background removal

Adding a garment opens one dialog: tips first, then the cut step.

- **Automatic cut:** [IMG.LY background-removal](https://github.com/imgly/background-removal-js) 1.6.0
  (ISNet model, about 40 MB, cached by the browser after the first download).
- **Correct by tapping:** [MediaPipe Interactive Segmenter](https://developers.google.com/edge/mediapipe/solutions/vision/interactive_segmenter/web_js)
  (`@mediapipe/tasks-vision` 1.0.1, magic_touch v1, about 0.3 s a tap on a laptop CPU).
  "Dette er plagget" selects the object under the tap, "Ikke dette" takes the tapped object away.
  v2 of the model understands "not this" strokes natively but takes about 7 s a tap on CPU.

Both load from CDNs at runtime. In the real product the cut runs on the server in the AI job
queue (a segmentation model such as rembg / BiRefNet); the browser cut here is for the prototype.

## Credits and licences

| What | Source | Licence |
|------|--------|---------|
| Garment photos | Pexels (ids in `tools/build_garment_photos.py`) | Pexels License, free for commercial use |
| Films | Pexels: Alena Darmel, Liza Summer and others (ids in `tools/build_media.py`) | Pexels License |
| Icons | [Lucide](https://lucide.dev) 1.48.0 | ISC |
| Fonts | Brygada 1918, Schibsted Grotesk via Google Fonts | SIL Open Font License |
| Automatic cut | IMG.LY background-removal | **AGPL-3.0**: fine for this prototype, not for the closed product |
| Tap cut | MediaPipe tasks-vision and magic_touch model | Apache-2.0 |
