aboutsummaryrefslogtreecommitdiffstats
path: root/src
Commit message (Collapse)AuthorAgeFilesLines
* Videos grid: a clip opens sooner. Its host is connected to ahead (a ↵Adam Soltys11 hours1-2/+52
| | | | | | | preconnect for the grid's clip hosts: the first clip from a host took 1.8 s on Adam's phone, 0.65 s once connected), and the player starts loading when the finger comes down on the tile; the pager adopts that very element, so the load overlaps the tap and the pager's opening. A press with no tap after it lets its player go. (feed-media-views test: the Live chip, and the warm next/kept previous players.) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos: a warm player gets its sound going before the swipe lands. On an ↵Adam Soltys11 hours1-2/+38
| | | | | | | Android phone a player's first play with sound held a still picture ~250 ms while the audio output started (muted: 60 ms; a player that had played resumes in 20-80 ms). So the next clip (and the one behind) plays at a volume nobody hears until its picture moves, a frame or two in, and pauses there (a seek back to 0 undoes it). Only with the pager's sound on, and for clips up to 25 MB: once played, a player reads the whole file. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos: the clip just left keeps its player, so a swipe back starts at once ↵Adam Soltys12 hours1-10/+16
| | | | | | | too (on Adam's phone it was the slow one: 0.66-0.78 s, built anew, against 0.04-0.08 s onto the warm next clip). The swipe clock records the player's readyState and how far it had buffered. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Videos start the moment a swipe lands, and streams say who's watching.Adam Soltys12 hours2-3/+101
| | | | | | | | - The pager's next clip gets a warm player: once its opening is in the cache it reads to its first frame (preload metadata: Chrome stops ~2-4 MB in at real link speeds) and waits paused, so landing on it is only play and sound. coinosPagerStarts() in the console times every landing (swipe to moving picture, warm or cold, host, size). - A stream's "N watching" names who on hover, and a tap shows their faces: NIP-53 presence (kind 10312, as Shosho and zap.stream say it), fresh for half an hour. coinos says it too while a stream is open (every 5 min, with a key held here only, never for your own stream) and takes it back on leaving. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Zaps are signed as the person zapping: the login identity (extension, ↵Adam Soltys12 hours2-5/+17
| | | | | | | bunker, passkey, Google) when there is one, else the wallet's key. They were always signed by the wallet's own key, so a signed-in person's zaps showed in stream chats and streamers' overlays under a stranger npub. Zap requests also carry created_at now (a real signer refused them without it). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Posts: a relay named in a post (wss://…) is a link to what's on it — the ↵Adam Soltys16 hours2-1/+10
| | | | | | | raw firehose of that relay alone (/feed/all?r=…). Trailing punctuation stays outside the link. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Profiles: past streams move off the top into a Streams tab (beside Posts and ↵Adam Soltys21 hours3-14/+10
| | | | | | | Replies, shown once they've streamed), as the Live chip's grid of tiles. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams: Delete recording is a trash-can button and Share is the share icon ↵Adam Soltys21 hours1-3/+4
| | | | | | | (three joined circles), so the stream's buttons fit on one row on a phone. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Add timestamp comments, reactions and zaps with audio waveform seekingAdam Soltys22 hours7-26/+263
|
* Streams: Delete recording, and Past streams that scroll on.Adam Soltys23 hours2-14/+86
| | | | | | | | | - **Delete recording:** your own ended stream's page has the button. The live server lets the recording go, and the stream is announced again without it, so other apps drop the link too. A deleted one leaves Past streams and says the streamer deleted it. - **Admin:** the Take down button no longer shows on the admin's own streams. - **Past streams** scroll on: 24 at a time as the grid's foot comes near, then older ones from the relays (before the oldest held), until a page brings nothing. They're no longer cut off at a month. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams over WebRTC. Going live also sends the camera to Cloudflare's ↵Adam Soltys26 hours1-3/+107
| | | | | | | | | | | | SFU, which the live server brokers, and a viewer in the app watches from there: 0.1 s behind the broadcaster in go-live-test LATENCY=1, against 3.5 s on HLS. - Switching to the screen and back swaps the track in place. - A reconnect that makes a new stream publishes again, and its viewers follow. - A viewer falls back to HLS if there's no WebRTC for the stream or no connection in 8 s. HLS is still sent, for the recording and the other nostr apps. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Notifications: tapping a zap with no post behind it does something. A zap on ↵Adam Soltys26 hours1-1/+7
| | | | | | | your profile opens the zapper's profile, and a zap on a stream opens the stream. The tap used to do nothing, because the row only knew how to open a post. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Watching a stream: a stream that's on plays through hls.js, held near the ↵Adam Soltys33 hours2-4/+15
| | | | | | | live edge (1.5 s back, up to 1.1× when it drifts past 5 s) — Chrome's own HLS player starts three segments back, never catches up, and fails outright (DEMUXER_ERROR_COULD_NOT_PARSE) if a page changes its speed. With the live server's 1 s segments a viewer is 3.5 s behind the broadcaster, from 8.6 s (go-live-test LATENCY=1 measures it: the broadcaster's camera is a clock in black and white blocks, read off the viewer's frame). Recordings, and streams where hls.js can't run (iOS), stay on the browser's player. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Screen sharing. In a call: Share screen in the call's bar (where the browser ↵Adam Soltys34 hours4-10/+85
| | | | | | | can — desktops) puts your screen in your camera's place, or into the call if your camera's off; Stop sharing, or the browser's own, brings the camera back or stops the picture, and the other side's view follows (a picture that stops coming is hidden). Live: Share screen / Back to camera on the broadcast bar switches without stopping the stream; the browser's Stop sharing goes back to the camera instead of ending it, and a cancelled screen picker leaves the camera going. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Video calls show the whole of the other person's picture (letterboxed), not ↵Adam Soltys34 hours1-1/+5
| | | | | | | cropped to fill the window — a phone's portrait camera on a laptop's wide window was a forehead filling the screen. The page under a full-screen call no longer scrolls behind it (the scrollbar did nothing visible). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A stream's chat is the app's chat: each comment is a bubble like a DM's or a ↵Adam Soltys34 hours3-43/+172
| | | | | | | group's — tap for the emoji row, reply, zap or copy; reactions (kind 7, tagged with the stream and the comment, one per person, deletable) and zap totals show on the comment for every viewer; the zap goes to the commenter, for that comment, on that stream. The composer is the one the other chats use (drafts kept per stream). A reaction no relay took is taken back. (Begun by Codex; finished here.) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Leaving a stream: Feed (and the rest of the nav) leaves it on the first tap ↵Adam Soltys34 hours1-3/+7
| | | | | | | — with the feed under the stream, Feed thought it was already there and only scrolled the hidden feed, and the nav's page-leaving didn't close the stream or Go live. On the stream's own page, the host's ringed face opens their profile instead of the same stream again. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* DMs and calls go to relay.coinos.io and relay.primal.net (both take gift ↵Adam Soltys34 hours2-4/+28
| | | | | | | wraps and pass call messages on live), not nos.lol, which refused or ignored the household IP's publishes. A relay that turns a call message away is left out of the next ones on this device: a day for one that won't take the kind (nip17.com: only kind 1059), ten minutes for a rate limit or ban. publishOn tells its caller which relay refused and why (onrefused). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Calls: the routes found before the offer or answer ride inside it (until ↵Adam Soltys34 hours2-6/+22
| | | | | | | there's a direct and a relayed one, 1.5 s at most) and only later ones go one by one — each route was its own signed message, dozens per call; a household's two devices calling each other got its IP banned by damus and rate-limited by relay.coinos.io, and the answer was refused with them: the callee stuck on Connecting…, the caller ringing on. An offer, answer, hang-up or decline no relay took is tried again (1.5, 3, 6 s) before the call gives up. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A voice call can turn video: Turn on camera in the call's bar puts your ↵Adam Soltys35 hours3-4/+37
| | | | | | | camera in (a renegotiation, NIP-AC's kind 25055); the other side sees you at once and gets the same button for theirs. The call's sound carries on throughout. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams on coinos's server: a ⚑ Report button (what's wrong, a note) for ↵Adam Soltys35 hours2-5/+89
| | | | | | | anyone signed in, and Take down for the admin (asks whether to bar the account too); a taken-down stream says so and plays nothing. Go live asks the server first: a name claimed less than a day ago is told when it can, and a barred account that it can't, Start off. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Streams: one our live server has ended reads ended, whatever its last ↵Adam Soltys35 hours3-6/+75
| | | | | | | announcement says (an app closed mid-stream never says so, and it read live for an hour with no way to stop it); its host gets End — on the stream and on their profile — which publishes the ended announcement with the recording. Each announcement is now newer than the last to the second (an ended stamped the same second as the live before it lost to it). A recording that is a web page (zap.stream's Rumble links) gets a Watch the recording link instead of a player that can't play it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Sign media uploads with the user's Nostr login identityAdam Soltys35 hours3-4/+19
|
* Going live: when the server can't take a dropped stream back (it restarted) ↵Adam Soltys35 hours1-8/+26
| | | | | | | and starts a new one, the app now announces the new one, once it plays, and says the old one is over (no recording: there's nothing in it). It went on announcing the dead address, and viewers saw "The stream isn't playing right now" while the camera sent to an address nobody knew. The streamer's own view follows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Past streams: under the Live chip, the feed's streams of the last month that ↵Adam Soltys35 hours3-13/+66
| | | | | | | left a recording (newest first, when each ended); a profile lists its person's too. A tap plays the recording. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A stream's chat leaves headroom above its first line: the hat on that face ↵Adam Soltys35 hours1-1/+2
| | | | | | | (the crown) was cut off by the scroller. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A Lightning invoice from Receive says to keep coinos open until it's paid ↵Adam Soltys36 hours2-0/+13
| | | | | | | — paid while coinos is closed, the money goes back to the sender — and that it lasts an hour (ark.coinos.io's invoices now expire in 1 h, not 48); when the hour is up the QR gives way to "expired" and a New invoice button. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Settings → Wallet → Transaction history: Export CSV — every payment in ↵Adam Soltys43 hours3-3/+65
| | | | | | | Spending and Savings as a line of a CSV file, oldest first: date (UTC), account, type, rail (Lightning, Ark, on-chain), what was paid, its fee, the change to the balance and its worth in your currency at the time, status, the transaction or payment hash, who it went to, the invoice. A failed payment is left out; a renewal is its fee. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live streams have their own chip, after Videos: a grid of the feed's streams ↵Adam Soltys44 hours3-15/+24
| | | | | | | on now, a red dot on the chip while someone in the feed is streaming — no longer a strip above every feed's posts. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Answering a call no longer takes seconds: while it rings, the connection is ↵Adam Soltys48 hours2-13/+68
| | | | | | | made with the caller's offer and its routes (TURN's too) gather, and the caller's relays and TURN credentials are looked up — Answer only adds the microphone and camera and replies (3.2 s → 0.2 s on a simulated network). An open conversation warms the same for calling out. A remote signer's offer or answer waits for a direct and a relayed route or 1.5 s, not for all of them (up to 4 s). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A call from someone you don't follow and haven't written to no longer ↵Adam Soltys2 days6-12/+65
| | | | | | | vanishes: it doesn't ring, but it's a missed call in your conversation with them, saying it didn't ring and why, a tap away from calling back (with the app shut, the worker notes it for the app, without a notification). A muted person's still leaves nothing. A logged call no longer counts as having written to someone. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Call history: each call is a row in its conversation — Outgoing / Incoming ↵Adam Soltys2 days4-4/+114
| | | | | | | video call · 4:12, Missed, Declined, No answer, Cancelled, Busy — a tap calls back. Kept like a message and sent to our own inbox (kind 1405, gift-wrapped to us alone) so our other devices list it; a call logged by two of our devices shows once, by its call-id. A call that rang while the app was shut and went unanswered is a missed call when it next opens. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Calls ring a closed app: the notifier wakes the phone for a call offer, the ↵Adam Soltys2 days5-11/+110
| | | | | | | service worker fetches the offer's wrap, opens it with your key and rings — "Alice is calling", until answered or missed — for someone you follow or talk to; the tap opens coinos ringing with the offer it kept. A call answered from a push still connects: the caller sends its candidates again once answered. Settings → Notifications → Calls. Also: the worker's DM key mirror retries when the wallet's keys aren't there yet (it waited five minutes). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Allow custom Blossom servers for attachments and post mediaAdam Soltys2 days5-4/+62
|
* Voice and video calls in DMs (NIP-AC, as Amethyst, nospeak and Noscall speak ↵Adam Soltys2 days5-7/+572
| | | | | | | it): 📞 and 🎥 in a conversation's header; a call from someone you follow or have written to rings over any page (tone, buzz, a notification when the app is out of sight) with Answer and Decline; mute, camera off, switch camera, minimize to a bar, hang up. WebRTC device to device (DTLS-SRTP), set up by signed messages in ephemeral gift wraps to the DM inboxes; TURN from coinos's live server (Cloudflare) for the connections that can't go direct. A remote signer puts the candidates inside the offer and answer instead of signing one each. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Live rings and going live. A face whose person is streaming wears a red ring ↵Adam Soltys2 days4-19/+336
| | | | | | | (LIVE under the bigger ones) and opens the stream. Go live (the composer's red dot, or your profile) sends your camera or screen to coinos's live server (coinosv3-server live/: the recording over a WebSocket, HLS out), announces it as your kind 30311 once three segments exist (Chrome's own player won't start a live playlist with fewer), refreshes it each minute with how many watch, reconnects to the same stream if the link drops, and ends it with its recording. Needs a coinos name. Also: the service worker leaves /live/ and /vmedia/hls alone (it froze a live playlist at its first copy). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Hide new posts notice when scrolling upwardAdam Soltys2 days1-9/+6
|
* Live streams (NIP-53), to watch: a row of what's on above a feed (Following: ↵Adam Soltys2 days8-21/+495
| | | | | | | your follows' streams; Everything and Popular: all), a stream's own page at /naddr1… (the HLS stream playing — hls.js where the browser has no HLS — its chat and zaps as they come, a chat line sent as kind 1311, ⚡ to the host), a card for a post linking a stream, and a LIVE line on a streamer's profile. A stream quiet for an hour is over; one that drops is retried; zaps on a stream carry its a tag. Also: the single-file build's video stub gains streamVideo (its uploads threw since the HLS uploads). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A clip in the post a reply answers (the "Replying to" card) goes full ↵Adam Soltys2 days1-4/+16
| | | | | | | screen: a tap on it or its full-screen button used to do nothing, the full-screen handler taking it back out for a media pager that doesn't have it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Short posts in another language get translated: a line like "Weißt Du wie ↵Adam Soltys2 days1-1/+9
| | | | | | | man die kriegt?" had one German common word and passed as maybe-English. More German common words, and letters only some languages write (ß, ñ, ł, ğ…) count as one. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The media pager no longer goes round from its last post to its first (or ↵Adam Soltys2 days1-30/+9
| | | | | | | first to last): a step, a flick or the wheel at an end stays there. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* No white buttons in dark mode: primary buttons, the chosen profile tab, feed ↵Adam Soltys2 days1-9/+18
| | | | | | | chip, new-posts pill, till tip and hat take a lifted grey there (the accent still fills them in light mode). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* Clips too big to play as they are (past 1080p, over the data budget, ↵Adam Soltys2 days1-7/+23
| | | | | | | unmeasurable) stream as HLS from vmedia and play by themselves instead of waiting behind a tap-to-play cover; with Data Saver or a slow link the cover stays. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* HLS for long videos: vmedia serves a long clip as a 360p/720p stream made as ↵Adam Soltys2 days4-18/+209
| | | | | | | it's watched (/vmedia/hls.m3u8), the feed and pager play long clips and posted .m3u8 streams through the browser's own HLS, and a long video posted from the app goes up as an HLS stream made on the device (master playlist on Blossom). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A mouse drag on the feed selects text again instead of grabbing and flicking ↵Adam Soltys2 days2-48/+3
| | | | | | | the page. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The media grid is never all caught up: once the feed's relays have nothing ↵Adam Soltys3 days1-13/+18
| | | | | | | older it reads on from the archive relays, and a bottom it does find is looked past again a few minutes on (no longer kept for a day). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* A touch stops a pager flight on the post most on screen: a tap only stops ↵Adam Soltys3 days1-2/+19
| | | | | | | it, a swipe back from there is the post before, and one the way it was flying takes it on. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The picture pager works like the video pager: pictures join once decoded, ↵Adam Soltys3 days2-26/+93
| | | | | | | | | | | | | | | | | | the screen's way round with the shape toggle, and it flies (and counts) once ten are ready; flights end without the crawl, and the feed beneath doesn't repaint mid-flight. Adam, 2026-10-17: "image pager should work similar. we need the tall only chip there too. i'm noticing some stutter/choppiness when flying images. especially towards the end of the fly as it's snapping to the one it's landing on." Measured on his phone (Pixel, 60 Hz) over synthesized touch flings in the live image pager: frames of 33–183 ms mid-flight, some with no script running (pictures fetched and decoded as the flight came near them: the near observer attached every post within 250% of the screen, a few of them originals — GIFs, hosts the server copies can't reach); the feed under the pager re-rendering (renderThreadStable, 40–55 ms each) during flights; and the flight's ease-out cube spending its last ~400 ms under 3 px a frame, the landing picture stepping a pixel at a time. - A picture post waits out of the carousel until its first picture is decoded (img.decode(), the copy falling back to the original as before). pagerWarmPics keeps four decoding at a time, up to sixteen ready ahead of the reader and three behind; a post whose copy and original both fail stays out. The picture's size, learned from the decode, places it for the shape rule. - The shape rule and its toggle ("Tall only" / "Wide only" / "All shapes", one setting with the videos) are in the picture pager's top bar too. - Flying needs ten posts ready, for pictures as for clips; the counter is hidden until then while posts are still warming (a pager with fewer than ten, all of them ready, counts them). The counter fade on settling applies to every pager (the frame loop's motion flag now runs for pictures too). - A flight eases out on a square instead of a cube: no long crawl at the end, and it sets off nearer the finger's speed. - scheduleRepaint holds off while the pager is moving. - pagerLoadAhead fills to the posts found (waiting ones too), not just the ready ones, so a gated pager doesn't crawl page after page. Tests: new tools/picture-pager-ready-test.js (a picture held back by the server waits out and a step passes over it; it joins above the one on screen without moving it; the wide one is out; no counter while one is warming, 3 / 6 once all are in; the toggle lets the wide one in and out and is as tall as the close button). pager-gone-picture now checks the dead picture is passed over. Picture tests not about shape turn all shapes on; pager-swipe-fly has twelve posts (ten ready before it flies) and waits out the longer flights; pager-loading's fixture gains pagerFound; pager-ready-gate: four clips all ready show their count. All pager tests pass except feed-pager-ahead and feed-video-pager, which fail the same checks as on a clean checkout. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The video pager shows no position counter until ten clips are ready, the ↵Adam Soltys3 days2-0/+4
| | | | | | | | | | | same point it starts to fly. Adam, 2026-10-17: "let's also not show the position/total counter until we have 10". The count is recomputed whenever a clip joins the carousel, so it appears as the tenth one does. Picture pagers and Data Saver are unchanged. tools/pager-ready-gate-test.js: with four clips ready the counter is hidden. pager-seek-hide and pager-swipe-fly pass. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg
* The video pager flies only once ten clips are ready to play; until then a ↵Adam Soltys3 days1-2/+9
| | | | | | | | | | | flick or a spin of the wheel is one post at a time. Adam, 2026-10-17: "let's not allow flying/coasting until we have at least 10 videos fully warmed up". Right after a refresh a fling outran the warming, landing on whatever was ready while clips joined around it. Ready is in the carousel: the clip's first frame on its slide and its opening cached. Picture pagers and Data Saver are unchanged. tools/pager-ready-gate-test.js: with four clips ready a hard flick goes one post (it came round to the first with the gate off). pager-swipe-fly and pager-wheel pass; feed-pager-ahead fails the same two picture checks as before. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_013ZDf1cyCQLkfjftYhymZAg