Project thumbs — timing & unstable loading
Large project grids (hundreds of crews × many timecode columns) can stampede the
browser and the CREWS static server if every thumbnail loads at once.
CREWS throttles hydrate from the client; knobs live in options.json.
1. Timing options
Stored in options.json at the CREWS app root (not uploaded by FTPS).
Also exposed via GET /api/options and mergeable with
POST /api/options. The viewer reads them on boot
(frames_ui/thumb_hydrate.js → loadHydrateConfig /
pumpThumbQueue).
| Option | Default | Range | Meaning |
|---|---|---|---|
thumb_hydrate_concurrency |
3 |
1–16 | Max parallel thumb network fetches |
thumb_hydrate_batch_size |
4 |
1–64 | After every N completed loads, insert a pause |
thumb_hydrate_pause_ms |
120 |
0–2000 | Pause length in ms (0 = no batch pause) |
thumb_hydrate_cache_concurrency |
6 |
1–32 | Parallel Cache API / HTTP-cache probes before network |
2. How to change them
Inspect current values:
curl -sS "https://crews.championship.technology/api/options" | python3 -m json.tool
Slow the client down (example — gentler on a busy host):
curl -sS -X POST "https://crews.championship.technology/api/options" \
-H "Content-Type: application/json" \
-d '{"thumb_hydrate_concurrency":2,"thumb_hydrate_batch_size":3,"thumb_hydrate_pause_ms":200}'
Or edit options.json on the host:
{
"thumb_hydrate_concurrency": 2,
"thumb_hydrate_batch_size": 3,
"thumb_hydrate_pause_ms": 200,
"thumb_hydrate_cache_concurrency": 4
}
After changing options, hard-refresh the shell and reopen the project tab
so the iframe reloads hydrate config. Python defaults live in
server.py → DEFAULT_OPTIONS
(restart CREWS after deploying Python changes that add/coerce these keys).
3. Troubleshooting unstable loading
Symptoms we chased and how they map to fixes:
| Symptom | Likely cause | What to do |
|---|---|---|
| UI freezes / server hangs when opening a large tab | Too many concurrent image requests (browser + Python static server) | Lower thumb_hydrate_concurrency (e.g. 2) and raise thumb_hydrate_pause_ms (e.g. 200–300) |
| Thumbs stay blank / placeholders forever | Hydrate never kicked (iframe visibility race) or requests starved | Hard-refresh; click the tab again; confirm frames_ui/thumb_hydrate.js loads (Network). Shell injects it into baked viewers. |
| Row height jumps; empty cells look square | Unloaded / absent cells used square aspect in table layout | Placeholders use explicit height calc(var(--thumb-size) / 2.4) — hard-refresh so frames_ui/head.html / hydrate CSS apply |
| Broken image icons in empty timecode columns | Missing frames still emitted as <img> |
Re-extract (or rebuild viewer) so empty cells use .frame-absent |
| Fast on second open, slow first time | Cold hydrate vs warm HTTP / Cache API path | Normal. First open fills cache; later opens reuse it under the same throttle. |
| Slideshow waterfall + thumbs both fighting the host | Waterfall advances one row; hydrate still fills the grid | Stop waterfall (play icon / Play all) while cold-loading, or slow hydrate further |
| Options POST ignored / keys missing | Process still on old server.py, or typo in key name |
Restart CREWS after deploying Python; confirm keys in GET /api/options |
4. Quick triage order
- Hard-refresh shell → reopen project tab
GET /api/options→ confirmthumb_*values- Browser Network: many parallel
.jpg? → lower concurrency / raise pause - Host CPU / load while tab open — if pegged, slow hydrate more
- Verify
frames_ui/thumb_hydrate.jsandslide_waterfall.jsreturn 200
5. Where it’s implemented
frames_ui/thumb_hydrate.js— queue, concurrency, batch pauseserver.py→DEFAULT_OPTIONS/_coerce_option_value//api/optionsoptions.json— persistent overrides on the hostframes_ui/head.html— placeholder / absent cell sizingframes_ui/slide_waterfall.js— sequential row slideshow (separate from hydrate)
crw >x< crush · viewer docs · thumb hydrate timing