Commit Graph
21 Commits
Author SHA1 Message Date
nvrl 6e961d3e0e Fix small front-end faults found in the audit
- A failed likes request shows the error in the panel instead of an empty list.
- A failed sign-out says why instead of doing nothing.
- Long toasts, like a copied link, wrap instead of running off narrow screens.
- Keys no longer act on the feed behind the help; ? still toggles it, and focus
  goes into the help and back to where it was.
- Phones reach the help from the account panel; the bar has no room for ?.
- Cards next to the current one are inert, so Tab no longer walks into buttons
  that are off screen.
- Keyboard focus is visible everywhere, and panels use the shared colour and
  radius tokens.
2026-11-01 19:07:16 +01:00
nvrl 2dcca0bc94 Fix the flat drop on Linux and morph its play/pause in one shape
The kick wave in the vertex shader squared a negative number with pow(), which
GLSL leaves undefined. Mesa returns NaN there, so on Linux the drop's position
pinned to the clamp: it stayed a plain round sphere without wobble, and its
normals split it into a dark yin-yang. The squares are written out now, and the
normal comes from the slope of the displacement instead of two whole positions.

The play/pause icon is one shape whose corners move: each pause bar turns into
half of the play triangle, with a small swing in between, instead of two icons
faded over each other. It sits on a disc of frosted artwork with a lit rim, and a
ring round it shows the track's progress, or runs while the track loads, which
replaces the flat spinner. The surface calms down under the icon gradually
instead of jumping flat, a double-tap no longer flickers the icon, and a mouse
resting on the playing drop shows the pause bars faintly.

Also:
- Low-density desktop screens render the drop at twice the resolution.
- Quality steps follow the display's own frame rate and step back up again.
- A lost WebGL context brings the drop back once it is restored.
- A paused drop keeps breathing at a low frame rate on desktop.
- Without Web Audio (iOS) jumps in the waveform count as kicks, so the drop lands on drops there too.
- Artists without an image get their own colour from their name, so their drop no longer sinks into the page.
- z toggles zen mode: just the drop, bigger, and the music.
2026-11-01 19:04:18 +01:00
nvrl bcdca34244 Rename the site to pl8list rewind with a dubplate mark
The infinity sign becomes a dubplate: a wobbling riddim groove around a red label
with a rewind arrow, after the soundsystem rewind where a tune the dance loves is
pulled back and run again. Icons, manifest, titles, legal pages and the README use
the new name; cookie names, storage keys and the link key info keep pl8inf so no
one is signed out or loses settings.
2026-11-01 18:33:12 +01:00
nvrl 065c9980dc Draw a clean play/pause on the drop and make the app installable
The raised icon was cut into a mesh too coarse for its edges and did not line up
with the icon painted over it, so it came out doubled and jagged, and melting one
shape into the other went through blobby in-betweens. The icon is now only painted:
crisp and white on a dark disc like the page's round buttons, still turning with the
drop, and pause and play fade into each other as the new one grows in.

Some browsers only offer to install an app with a service worker. A minimal one at
/sw.js (served from the root so it covers the whole app) caches nothing and only
shows a short offline note instead of the browser's error page. The manifest gets
an id.
2026-11-01 16:08:59 +01:00
nvrl ca23cf5b7c Put a 3D play/pause on the liquid drop and keep page swipes working
The flat play/pause badge and the flash icon sat on top of the drop as two separate
symbols. With the drop on, both are gone: the icon is stamped out of the drop's front
instead, turns with it and catches the light. Pausing pops up the bars, which melt
into the play triangle; playing melts it back into the bars as they fade.

On touch only a clearly sideways drag turns the drop now, so diagonal swipes turn the
page again. A mouse released outside the window, or after turning the drop, no longer
leaves the pager dragging. The halo behind the drop drew a hard ring at the art's edge;
it is a soft radial glow now.
2026-11-01 15:39:21 +01:00
nvrl 482cfc299b added volume control to desktop 2026-11-01 15:10:03 +01:00
nvrl 2ddc1b5629 Blend the liquid drop into its card and let it be spun by hand
The rim hue drifted with play time until it left the card's colour altogether, so a
pink card could carry a green drop. It now only sways around the accent. The edge
fades into the page, a halo in the accent pulses behind it like the plain artwork's
glow, the surface reflects the accent from above, and the title and the rest of the
card sit on top where the drop spills over them.

Dragging the drop turns it (sideways only on touch, where up and down turn the page).
A flick keeps it spinning; it slows down and a weak spring wobbles it back to face the
front. Spun fast it flattens a little and sloshes, and the artwork blurs into colour
where it is seen from the side. A spin is not a tap, so it does not pause.
2026-11-01 15:09:50 +01:00
nvrl b09a7370ca Let the riddim wobble drive the liquid drop and bring back its texture
Two new features follow the bass line itself: its envelope against the last moment,
which rises and falls with every wub, and how open its filter is (spectral centroid
of the bass and mids). Each wub swells the drop, and as the filter opens its surface
crinkles and spikes like before. Every layer keeps a floor, so the drop never goes
still and nothing snaps in from nothing; riddim gets its soft terraces back. Kicks
still make it jump.
2026-11-01 14:54:43 +01:00
nvrl cccdf1d11c Make the liquid drop wobble like jelly and jump on prominent hits
The terraces, snare spikes and fine ripples creased the surface into jagged corners.
The drop now always moves in broad, smooth lobes, and the strongest kick and bass
hits (weighed by prominence against the last seconds) throw it up on a spring: it
stretches as it rises, squashes as it lands and jiggles back. Snares pump its size.
It also swells in from the flat artwork more slowly.
2026-11-01 14:42:39 +01:00
nvrl 2125000644 Merge pull request #2 from narrrl/rust-backend
Rust backend
2026-11-01 14:33:53 +01:00
nvrl 76cfbb12ac Turn artist radio into a station sheet with reasons on each track
The radio button (r) opens a sheet with the artist, their tags and their closest
neighbours instead of switching the feed at once; tapping a neighbour walks the
artist graph. Starting jumps to the radio's first track, the top-bar chip shows the
station, each radio card says why it is there, and an end card offers the way back
when the radio runs dry.

GET /local/artist feeds the sheet and starts crawling a new artist's neighbourhood
(at most every 10 minutes per artist). Artist-radio tracks carry why: seed, related,
or via the neighbour that leads to them.
2026-11-01 14:32:51 +01:00
nvrl e8c0f40128 Start drop detection from the first sound and count onsets in the debug overlay
Previews often open inside a drop; the long loudness average now covers no more than
what has been heard, so that is the baseline rather than a drop.
2026-11-01 14:32:51 +01:00
nvrl 856ccb3b9a Replace loudness pulse with onset tracking and add liquid artwork visuals
The bass meter sat at full scale through every dubstep drop, so the glow froze.
features.ts now tracks band levels against their recent range, kick and snare
onsets from spectral flux, wobble in the mids, and drops, and the pulse follows
the kicks.

The playing card's artwork becomes a WebGL2 liquid drop that moves with those
features; tempo, tags and key set its character. Falls back to the plain artwork
without WebGL2, with reduced motion, or with visuals set to simple (v).
?debug=audio shows what the tracker hears.
2026-11-01 14:15:26 +01:00
nvrl 396bea7af5 Merge pull request #1 from narrrl/rust-backend
Rust backend
2026-11-01 13:50:20 +01:00
nvrl f6c505907a Add discovery modes, track tags and an artist graph
Tracks get tags from their title, description, artist name and BPM
(styles such as riddim, versions such as VIP/dub/flip, and tempo), stored
in track_tags and shown on cards. Related pages the crawler reads are kept
in track_related, which links artists to each other.

The feed takes ?mode=: riddim (140 BPM, riddim artists and their graph
neighbours first), fresh, deep cuts, and an artist radio that plays an
artist and the artists around them. Opening a radio crawls that artist's
related pages first. The crawler searches riddim-adjacent terms first.

The filters panel picks the feed, each card has a radio button (r), and a
chip in the top bar returns to the normal feed.
2026-11-01 13:46:52 +01:00
nvrl b4470850bf Rebuild front end in TypeScript with a pager, crossfades and reactive visuals
The front end moves to web/ (Vite, TypeScript, no framework) and is built
into web/dist, which the server embeds. hls.js is bundled from npm and
loaded on demand instead of vendored.

The feed is a custom pager instead of CSS scroll snapping: drag and flick
with a spring that keeps the finger's speed, a rubber band at the ends,
one page per wheel or trackpad gesture, and only three cards in the DOM.

Playback uses two decks. The next track is buffered shortly after the
current one starts and tracks crossfade through a Web Audio graph; on iOS,
where that would break lock-screen playback, they switch with a cut. An
analyser drives a bass pulse of the artwork and its glow, and each card
takes its accent colour from the artist image. Styles start from design
tokens and respect reduced motion.

Docker gets a Node build stage; legal pages use their own small stylesheet.
2026-11-01 12:57:17 +01:00
nvrl 27225332fb Add opt-in pl8list connection with library sync, follows and resync
At sign-in users can choose to stay connected to pl8list on that device.
The pl8list session is then stored in the device's session row, encrypted
with XChaCha20-Poly1305 under a key derived from the device's local token
(only the browser has it) and a server key kept outside the database. It
is only decrypted during that device's own requests, re-encrypted when the
token rotates or pl8list sends a new cookie, and deleted when pl8list
rejects it.

Every sign-in now syncs the personal feed, saved tracks (imported as likes)
and saved artists (imported as follows). Connected devices resync on use
every six hours and push new likes and follows to the pl8list library with
addOnly, so nothing is ever removed there. Without the connection, the
resync button runs the email-code sign-in again.

Artists can be followed from each card (f); follows feed the ranker. The
account menu shows the sync state, resync and disconnect. Privacy policy,
export and account deletion cover the new data.
2026-11-01 12:36:00 +01:00
nvrl 54a436ae48 Rewrite backend in Rust, add Impressum, privacy policy and account tools
New axum server in backend/ with the same HTTP API and database as the
Python one. The pl8list session is only held in memory during the feed
crawl and logged out afterwards. Local sessions use a __Host- cookie,
30-day idle expiry and weekly token rotation; the old cookie is migrated.

The audio and image proxy only accepts known parameters, fixes the content
type, follows redirects only to pl8list's file host and caches segments and
images on disk. Strict security headers, origin checks on POST, body and
concurrency limits.

/impressum and /datenschutz are rendered from env variables. The account
menu offers data export, sign out on all devices and account deletion.
hls.js is self-hosted and artist images are proxied, so the browser only
talks to this server. The Docker image builds a static binary on scratch.
2026-11-01 12:02:37 +01:00
nvrl 61af1a6dd2 Harden Python server: rate limits, login caps, upstream logout
Take the client IP from the right-most X-Forwarded-For entry so a spoofed
header no longer resets the per-IP limit. Cap resends per login, count them
against the per-email limit, add a server-wide login mail limit and cap
pending logins at 500. Count code attempts under the lock.

Log the pl8list session out upstream once the feed has been read, also when
reading fails or the account has no handle, and always drop it from memory.
2026-11-01 12:02:37 +01:00
nvrl 87af563a95 Add tap controls, lock-screen playback and other comfort features
- Tap/click a track to play or pause, double-tap/double-click to like
  with a heart burst; any key or tap starts playback
- Media Session API: lock-screen, notification and headphone controls,
  with next/previous working while the screen is locked
- Drag the waveform to seek, hover shows the time
- "Not for me" button feeds a dislike signal into the ranker
- Share button (native share sheet or copy link)
- Likes newest first, each playable right away
- Filters remembered per browser, clear button, active indicator
- Panels close on outside click or Esc; help overlay on "?"
- Buffering spinner, paused badge, toast messages, first-run hint
- Installable as an app (manifest and icons)
- Refreshed README screenshots and controls
2026-10-31 20:49:47 +01:00
nvrl 4a7f6903a3 Add pl8list infinite-scroll app with pl8list sign-in
Endless TikTok-style feed over pl8list's Remix loaders. A guest crawler
builds a shared catalogue; a per-user ranker learns from likes, full
listens and skips. Users sign in with pl8list's email code; only a hash
of the local session token is stored. Ships as a hardened Docker image
with a Traefik override for pl8.narl.io.
2026-10-31 20:22:27 +01:00