GitHub - halcyon-video/halcyon-video: Your Jellyfin library as a walkable 1990s video rental store — three.js, first-person, self-hosted
Pangram verdict · v3.3
We believe that this entire text is AI.
AI likelihood · overall
AIArticle text · 1,741 words · 1 segments analyzed
Halcyon Video — a 3D video store for your media server Your Jellyfin library, rebuilt as a walkable 1990s video rental store. Every movie you own is a case on a shelf. Browse the aisles under warm fluorescents, pull Back to the Future off the wall, flip it over and read the back of the box, carry it to the counter, and watch the clerk drop it in a bag that crinkles around it. Then take it home to the living room and put it in the VCR. It is not a menu with a skin on it. It's a store. Walk in from the parking lot — brick facade, glazed-tile stripe, the blue board on the gable, your movie posters in the windows. Try it right now, no server, no signup: https://halcyon-video.github.io/halcyon-video/ — the full store running on a synthetic demo library. Or take the 45-second tour ▶ first. Heads-up: the demo boots the entire ~2,000-title store into your browser — expect a few GB of memory and real GPU use, and prefer a plugged-in machine over a laptop on battery. (It's built to live on a dedicated HTPC, where it idles near zero; a leaner demo is on the list.) The same library, four ways None of this is a preset you pick once. Era, lighting, floor plan and media format are independent settings, and every combination is a store you can walk around in. More ↓ Four decades of fit-out — board signage and VHS in 1990, the fascia-band era in 1993, arched plaques in 2000, wire-black DVD shelving in 2010. Day, sunset, night — the light through the front glass, on eight measured-sun HDR skies. Three floor plans — herringbone, straight, or diagonal shelf runs, packed to fit the room. VHS or DVD — the whole store re-cased, on correctly-proportioned rental shells. Does it…? The short answers, so you don't have to go looking for them. Run in Docker? Yes — one docker run, or docker compose up -d from a clone. Quick start ↓ Do video games? Yes — point it at RomM and a whole department appears: per-platform bays, period-correct boxes and jewel cases, and "renting" one launches it. More ↓ Work with Plex or Emby? Not yet — Jellyfin today. The media layer is one module and adapters are the top roadmap item (#32). Run on a Raspberry Pi? Yes — 2.5D mode runs the same store as plain HTML/CSS. More ↓ Work away from home? Yes — Remote Play streams the live store to any browser, with its own TURN relay for off-LAN viewers. More ↓ Look like my video store? Yes — brand, logo, colors, themes, fixtures and sign art are all data you drop in a folder, not code. More ↓ Work with no media server at all? Yes — that's the demo link above. What it is A Vite + TypeScript + three.js app (optionally Tauri-wrapped) that connects to Jellyfin and procedurally builds a period video store from whatever you have: every library becomes an aisle, genres become signposted sections, duplicate quality versions stack behind the face copy, the worst-rated titles literally end up in the Bargain Bin. It runs 24/7 on an HTPC as our family's way to pick a movie — and when nobody's touching it, it renders nothing at all and idles at near-zero CPU/GPU for days. The screenshots in this README show the store running its built-in demo catalog — public-domain classics on every shelf, no media server attached (the same thing the live demo link runs). Point it at your Jellyfin and every case becomes something you own. This isn't a tech demo that gets old in five minutes; it's how our family has picked a movie every night for months. Browse the aisles A real floor plan. Shelf runs pack the floor in herringbone, straight, or diagonal arrangements. Genre boards ride the shelf tops, category blades hang from the ceiling, and the New Releases wall wraps the back of the store backed by gold "NEW RELEASE RENTAL" clamshells. Every case is your art on a correctly-proportioned VHS or DVD rental case — 4K editions wear a 4K sticker, popular titles show multiple copies deep on the shelf, and a title with both a 4K and 1080p version collapses to one box with the quality choice made at play time. Move like a person. Cursor-browse shelf to shelf with duplicate-skipping and over-the-top wrap, or press F and walk the store in first person — WASD, mouse-look, and click any case within reach to pick it up. No click-to-teleport, no Street-View lurching: you walk. Doors swing open as you approach. Footsteps alternate ears. The ceiling CRTs are playing something family-safe from your own library, with positional audio that gets louder as you walk under them. The New Releases wall Your most recent arrivals, faced out floor-to-high with the multi-copy depth of a real street date, under the "2-EVENING NEW RELEASE RENTAL $3" sign. Pick up a case Enter lifts the case into your hands — retail art in front, the store's rental copy behind it. Flip it: The back of the box is typed, not templated. Real synopsis, director, cast, year, runtime, rating — plus genre-matched review pull-quotes ("AN EXPLOSIVE SCI-FI SPECTACLE!") and a bordered technical specifications table built from the file's actual media streams: aspect ratio, HDR10 / Dolby Vision, audio tracks, subtitles, the works. Click an actor's name to jump to that actor's shelf. TV series are 3D season boxsets — rotate the box to the side panel to pick an episode. The flip cycle ends on the spine — the rental copy angled with a sliver of front showing, exactly how you'd hold it deciding. The search terminal Press / and the camera walks you behind the counter and docks to the clerk's CRT. Type on amber phosphor; matches come back by title, director, or genre, and Enter flies you to the title's spot on the shelf. Rent it like it's 1994 Carry mode: take a tape and it joins a hand-fanned stack at the bottom of your view. C walks you to the counter; hold Enter goes straight to checkout with a gold hold-meter pill. The bag is a real soft body. The glossy white pillow bag is a ~340-node cloth simulation — two welded sheets, die-cut handle punched through both layers. Drop a case in and the plastic visibly pushes out around it; pick it up and it droops and sways under gravity, then settles. (And then the solver goes to sleep, because nothing here is allowed to burn watts at idle.) The checkout exit is choreographed — wrap, slide, a first-person walk-around while your bag waits at the counter's edge, grab, carry-out. Rental mode (optional, "hardcore") enforces real early-90s rental-chain rules on the wall clock: two tapes on a weeknight, due back noon tomorrow; four on a weekend, due Monday 8 AM. The store locks you out until then — DST-safe, with a diegetic DUE BACK slip. Return them through the classic "▼ RETURN TAPES HERE ▼" chute on the counter's entrance shoulder, one clatter-thunk at a time. The living room After checkout you're home — rented clamshells and the receipt on the coffee table, a CRT and VCR with a blinking clock. Inspect your tapes from the couch, insert one, and the movie plays on the TV in the room, with positional audio at the set. Snacks for tonight? (optional) Flip on candy delivery and checkout adds one question — the wire rack's real rows (gummy bears, popcorn, movie mints…), a quantity, a ZIP, and a hand-off deep link to DoorDash. No payment in-app; off by default and byte-identical to before when disabled. The clerk A Doom-style directional sprite — five hand-drawn views picked by the angle between her heading and your camera, procedurally painted onto a sprite sheet at boot. She isn't decoration: She walks the store on grid-A* over the real floor plan — restocks shelves with a high/mid/low reach cycle, types at the terminal, idles at the register. (There's a pathing audit that simulates seven minutes of her roaming and fails CI if she ever clips through a fixture.) "ASK FOR RECOMMENDATIONS!" clasps clipped to the shelf lips summon her to wherever you're standing, and her suggestion is scoped to the section you're in. Her reasons are true, never generated. The recommendation engine only says things it can prove from your library: "You have three of the Alien films", "Because you have HEAT", director, actor, studio, genre — in that order of strength. It also learns your taste from what you inspect, with a gentle decay so it drifts as you do. "Something else?" rotates her through alternatives — including titles you don't own, with an "Order it for me" option (see below). Discovery — the store stocks what you're missing With Jellyseerr connected, the store quietly merchandises around your collection: Collection gaps: own 3 of the 4 Alien films? The missing one stands on the shelf as an empty box with a blue REQUEST corner label. Select it and the label restamps gold COMING SOON, live, while the clerk toasts that she's ordered it. Discover titles — trending films you don't own — are shelved inline with your stock as request cases, not exiled to a separate row. Staff picks from your actual watch history: the overlap of "people-also-liked" lists across everything you've watched, overlap-ranked so a film recommended by three of your favorites beats one recommended by one. Owned winners sit unmarked on the shelf; not-owned winners take the genre endcaps wearing a FOR YOU starburst. Not interested? Hold ▼ on any suggested case and it's gone — from every shelf, permanently. The hold is deliberately a beat longer than checkout's, so you can change your mind mid-meter. No Jellyseerr configured? None of this is hidden — it's simply never built. The store doesn't hang an "ask me" button its clerk can't answer. The games department Point it at RomM and a freestanding gondola appears: per-platform bays with brand-colored blades — SNES and N64 cardboard boxes in landscape, PlayStation jewel cases, Genesis clamshells — 13 platform toggles, top-rated titles first. "Renting" a game launches it: a native emulator under Tauri, or RomM's in-browser EmulatorJS player otherwise. Off by default; zero requests when disabled. Set Emulator Command in the manager terminal's Video Games page — retroarch -L /path/to/core.so {path}, where {path} becomes the rom. The