- new photos on the server appear automatically: the grid polls the
newest page every ~30 s while settled; dedup_new_assets drops
already-known ids (and also guards page fetches against server-side
pagination drift)
- rebuild_keep_view pins the scroll and selection to the same photo
across every relayout (page fetch, poll, sync), so loads no longer
move the view
- R/L month jump anchors the landed month's header to the top of the
screen, and R fetches ahead until the next month is actually loaded
- portrait videos play upright: the asset's exif orientation is kept
(g_asset_rot) and the player rotates decoded frames (draw_video_frame)
- "loading..." texts replaced by a spinning throbber: centered when an
item has no preview yet, a small corner one while the full-res loads
over the thumb (never both)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Grid:
- justified rows like the Immich web timeline: widths follow each
photo's exif aspect ratio (withExif on search/metadata, orientation
aware), rows stretch to span the full screen width
- row-aware d-pad navigation (variable items per row)
Detail view:
- swipe horizontally to change photos, 1:1 with the finger, neighbor
riding alongside; release past a quarter screen commits, less
springs back; d-pad browsing uses the same slide animation
- touch drag pans 1:1 while zoomed
- neighbors prefetch (thumbs first, then full-res / video posters)
so swipes land sharp; opening a cold item loads its low-res thumb
before the full-res
- videos show their poster with a translucent play button instead of
a "press X to play" text; tap or X plays; the gallery opens this
screen rather than auto-playing
Video startup:
- the poster stays on screen through download progress, AVPlayer
startup and the pre-first-frame gap; no more black screen
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Thumbs get blown up in the detail view while loading and full-res
photos get scaled to the screen, so sample them linearly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Opening a photo no longer blocks on a "Loading photo" screen: the
grid thumbnail is drawn scaled to full screen while the worker thread
downloads and decodes the full-resolution image, and O backs out to
the grid at any time (an in-flight result is discarded there).
The synchronous loaders (load_image, load_local_image, decode_jpeg)
are gone; the worker request gained a `detail` flag that decodes to
FULL_MAX instead of THUMB_MAX, and the texture-building half of
consume_worker_result is shared via req_build_texture.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- L/R triggers move to the first photo of the previous/next month
instead of two rows (month_jump walks the date-grouped timeline)
- pressing X on a video tile starts the download/playback right away,
skipping the detail view's "press X to play" stop
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pages now fetch behind the live grid; the HUD's "+" already signals
that more photos are coming, and the fetch only blocks briefly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Dynamic arrays for assets (remove 1000/500 caps)
- Zoom (R/L triggers) and pan (analog stick) in detail view
- Group gallery by month/year with headers
- Fix fast-scroll crashes via texture pooling and thread safety
- Serialize curl calls (OpenSSL 1.0.2 lacks thread support)
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Fix the playback HUD showing "/ 0:00": duration is re-polled in the
render loop until sceAvPlayerGetStreamInfo reports it, instead of being
latched once before async parsing finishes.
When a video reaches its end, hold on the last frame with an
"X replay / O back" prompt instead of returning to the detail screen
(which, for server videos, forced a full re-download to watch again).
X replays from the still-local file via re-init; the decoder claim is
held across replays.
Also add the agentic loop tooling/docs: AgenticLoop.md runbook
(build, install, drive Vita3K via kwin-mcp, zero-context-cost frame
capture), controls.MD key map, deploy.sh, .mcp.json, and gitignore
build-native/ and agent-run/.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The "unsupported protocol" failure was never about HTTPS: the Vita
resolved the public domain to the WAN IP, the router (no NAT loopback)
answered with its own admin page, and curl reported the resulting
HTTP/0.9 garbage as CURLE_UNSUPPORTED_PROTOCOL. serverip= pins the
hostname to the LAN IP via CURLOPT_RESOLVE, keeping Host/SNI intact
for the reverse proxy.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Log libcurl's runtime version/SSL backend/protocol list at startup,
mirror fatal errors into log.txt, and capture curl's verbose debug
stream for the first request.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
curl error 1 (unsupported protocol) was caused by invisible junk in
the config: leading whitespace, tabs or a UTF-8 BOM around the server
URL. Trim all of it, default to http:// when no scheme is given,
validate the scheme with the parsed value shown on screen, and include
the attempted URL in the first-connection error.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Scrollable chronological photo grid with full-screen viewer, fetching
previews from an Immich server via its REST API. Thumbnails stream in
on a background thread over a keep-alive connection. JPEG decoding is
done with libjpeg directly (vita2d's loader rejects Immich's
APP2-first JPEGs). JSON parsed with vendored jsmn (the vitasdk jansson
package is built as PIC, which vita-elf-create can't handle).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>