# Level Feed (static hosting)

This directory is the level feed the phone app downloads from. It is plain
static files — any host works (Tailscale Funnel now, GitHub Pages later).

```
manifest.json                the app fetches this on opening the Puzzle Feed
levels/<id>.json             level, same schema as puzzles/level_N.json (+ "meta")
levels/<id>_solution.json    solution alongside, so in-app hints work
```

## Publishing a level

```bash
cd ../puzzle_generator
python3 publish_feed.py path/to/level.json                # auto id/band/title
python3 publish_feed.py level.json --id my_id --title "Nice Name"
python3 publish_feed.py --list                            # show manifest
```

The publisher refuses any level whose solution does not replay cleanly
against the Python engine, and stamps difficulty score/band using the same
corpus model as `rank_levels.py` (run that once first to build the cache).

## Serving

```bash
../serve_feed.sh          # tailnet-only (your devices, Tailscale app on phone)
../serve_feed.sh public   # public via Funnel (beta testers) — needs one-time
                          # enable, see the links inside serve_feed.sh
```

Public URL: `https://ryan.tail3c56f2.ts.net/manifest.json`

## App side

`FeedManager.gd` defaults to the URL above. To repoint an installed app
without rebuilding, create `user://feed.cfg` on the device:

```ini
[feed]
url="https://somewhere.else"
```

The app caches manifest + downloaded levels in `user://levels/`, so a down
server only means "no new levels", never a broken game.

## Uptime caveat

This feed is served from the WSL dev box: when the machine is off, the feed
is unreachable. Fine while the only users are you and friends. The flip
condition (from APP_NEXT_STEPS.md): the day a stranger installs the game,
copy this directory to GitHub Pages and update the base URL.
