Halcyon Video: a 3D rental store that renders your Jellyfin, Plex or Emby catalog as aisles
Your Jellyfin or Plex library as a walkable 1990s video rental store, self-hosted
At a glance
- What is it?
- Halcyon Video turns a media catalog into a walkable 1990s video store built with Three.js. It is a GPL-3.0 TypeScript project that reads Jellyfin, Plex, Emby, RomM and Jellyseerr data, and it is honest about the one thing it cannot do: scan folders on its own.
- Who is it for?
- Adopt Halcyon Video if you already run Jellyfin, Plex or Emby and want a second, spatial interface over that same catalog for a couch or HTPC setup. Do not adopt it as a scanner or as a replacement for the server itself: the README states there is no built-in folder scanner, so a shelf of loose files on disk is invisible to it.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem: a media server is a database, not a place
Jellyfin, Plex and Emby all converge on the same interface idea: a grid of posters, sorted and filtered. That works for finding a specific title you already decided to watch. It works less well for the other mode of use, the one where nobody has decided anything and the group is scrolling sideways through a wall of thumbnails.
Halcyon Video attacks that second mode. The README is explicit about the intent: it is not a grid menu wearing a nostalgic skin, it is a store. Libraries become aisles, genres become sections, and titles with more demand get deeper stock on the shelf. Multiple quality versions of the same film collapse into a single box, which is the kind of detail that matters when you have three encodes of the same movie and do not want three identical cases side by side.
The audience is narrow and specific. You need an existing media server, a machine that can run a Node build, and a display you sit far enough from that walking around a room is preferable to scrolling a list. The README frames the target as the couch: keyboard, gamepad, TV remote or phone all drive the same remote-first interface, with first-person walk mode and WebXR layered on top when a headset is available.
How the store is assembled from your catalog
The mechanism is a translation layer. Halcyon does not store your media and does not reimplement a media server. It reads a catalog from a source, then maps that catalog onto 3D geometry. The README describes the mapping directly: libraries become aisles, genres become sections, popular titles get deeper stock. The room is generated, not hand-placed.
The clerk is the most interesting piece of the architecture. She is rendered from an original Blender character model into a directional sprite atlas, which is a 2D billboard technique rather than a fully modeled 3D character. She walks the actual floor plan, restocks, works the terminal, and moves to recommendation points around the store. Her suggestions are derived from the catalog and watch history, using collections, directors, actors, studios and genres. The README states the reasons come from that data rather than generated copy, which is a meaningful distinction: a recommendation here is a query result, not a language model output.
The games department follows the same pattern. Point Halcyon at RomM and enabled platforms become a separate department, with cardboard cartons, clamshells and jewel cases sized to platform-specific proportions. Native builds can hand a selected game to an emulator. Nothing in the material suggests Halcyon emulates anything itself.
Getting it running: launchers, port 1420, and the setup terminal
The quick start is deliberately short. Clone the repository, then run the launcher for your platform. The README lists start.cmd for Windows, and the supplied excerpt is truncated at the macOS entry, so the macOS and Linux launcher filenames are not confirmed in the material I have. What the README does state is what the launcher does: it checks Node, installs dependencies on first use, builds the app, serves it on port 1420, and opens a browser.
There is no configuration file walkthrough in the README. Configuration happens through a setup terminal inside the running store. For streaming aisles, that terminal asks which services you use and stocks them from a bundled snapshot, with no Jellyfin, Plex, Jellyseerr or TMDB key required. A configured TMDB or Jellyseerr source can refresh that data later.
Branding is edited live rather than in a config file. The Brand Editor changes name, colors, emblem and typeface, and the storefront, cases, aisle signs, counters, bags and clerk livery repaint together. The Emblem Studio builds a mark from editable shapes, and an SVG or transparent PNG can replace it entirely. Local assets go in public/user-assets/, which the README notes is git-ignored so a private store identity does not end up in a commit. Larger conversions can use a brand pack supplying per-era palettes, fonts, surfaces and scanned wraps.
For playback, the README describes three routes. The browser player uses direct streams when the browser can decode the file and falls back to HLS when it cannot, with audio and subtitle selection, resume points and automatic next episodes. An HTPC setup with a server running on the same machine can launch the local file in mpv for HDR, lossless audio and native display handling. Streaming aisle titles hand off to the provider's search or watch page, and the README is clear that Halcyon does not impersonate a streaming player.
The missing folder scanner is the load-bearing limitation
The README states it plainly: there is no built-in folder scanner, and shelving personal files requires Jellyfin, Plex or Emby. That single sentence defines the project's boundary. Halcyon is a client, not a library manager. If your media sits in a directory tree with no server indexing it, Halcyon has nothing to render.
The dependency cuts deeper than installation. Metadata quality in the store is metadata quality in your server. The technical table on a rental case is generated from the file's media streams, so versions that your server has not probed will show an incomplete table. Resume points and watch history come from the server too, which means the clerk's recommendations inherit whatever gaps exist upstream. A library with thin actor or studio data produces a clerk with less to work from.
The second limitation is decode. The browser player falls back to HLS when the browser cannot decode a file, and the README does not claim the fallback is transparent for every codec. The mpv route requires a server running on the same machine as the file, which rules it out for the common arrangement where the media server is a NAS in a closet and the display is a different device. HDR and lossless audio are named as mpv benefits, which implies the browser route is not the path for those files.
The third is the public demo. It scales the demo catalog to the browser's measured GPU headroom, from a smaller phone store to the full layout on a discrete GPU. That is a sensible adaptive design, but it also tells you the full store is a real rendering load. A low-power client will get a reduced store.
Where it sits next to Jellyfin's own web client
The obvious alternative is the interface you already have. Jellyfin's web client, or Plex's, is the direct comparison, and the difference is not cosmetic. Those clients are list-and-grid browsers with playback attached. Halcyon is a spatial browser with playback attached. Same catalog, different retrieval model.
That difference decides the use case. If you know what you want to watch, the standard client is faster: type a name, press play, done. Halcyon adds a walk from the parking lot, a shelf, a case, a counter and a checkout sequence before playback. That overhead is the entire point when the goal is browsing, and it is pure friction when the goal is watching a specific episode before bed.
The other meaningful alternative is doing nothing and keeping the standard client on the TV. Halcyon is worth its install cost only if the browsing problem is real for you. If nobody in the house has ever complained about the poster grid, the store is a hobby project rather than a fix.
The RomM and Jellyseerr integrations are where Halcyon does something the standard clients do not. RomM turns enabled platforms into a games department with platform-specific packaging, and Jellyseerr or Overseerr connections let the clerk surface collection gaps, shelve discovery titles as request cases, and place an order without leaving the store. Those are additive, not a reimplementation of what Jellyfin already does.
Maintenance cost and what GPL-3.0 means here
The release cadence visible in the material is fast. v0.17.0 and v0.17.1 landed on 2026-09-09, and v0.18.0 landed on 2026-09-10, adding Emby libraries and completing dropped logos. Three releases in roughly two days at the 0.18 mark tells you the project is pre-1.0 and moving. Expect to rebuild. The launcher rebuilds on run, so pulling a new version means re-running the launcher rather than a manual build step, but the store's internal state (saved store settings, per the Emby row in the source table) is something to verify survives an upgrade before you rely on it.
Licensing is GPL-3.0. Without giving legal advice: that is a copyleft licence, and it matters if you intend to distribute a modified build or bundle Halcyon into something you ship. Running it privately for your own household is the ordinary case and not the one the licence targets. If you plan to fork it, rebrand it and hand it to other people, read the licence text rather than this paragraph.
The brand pack path is the one place where licence and privacy interact. Local assets in public/user-assets/ are git-ignored, so a private identity stays private. A brand pack built for distribution is a different situation, and the README does not describe terms for sharing one.
Who should install it, and what to check first
Install it if you run Jellyfin, Plex or Emby, you have a machine that can run a Node build and serve port 1420, and the browsing problem is real in your household. The Emby support added in v0.18.0 means the three major self-hosted servers are all first-class sources now. A gamepad or TV remote on the couch is the intended input, and the remote-first interface is designed around that rather than adapted to it.
Do not install it if your media is not indexed by a server. The README is unambiguous: no built-in folder scanner, and shelving personal files requires Jellyfin, Plex or Emby. Do not install it expecting better playback than your current client either. The browser player is a competent route, but HDR and lossless audio are named as mpv territory, and mpv needs a server on the same machine as the file.
Verify in this order. First, confirm your server is reachable and that your versions have been probed, because the case's technical table is generated from media streams. Second, decide your playback route before you build the store: browser, same-machine mpv, or streaming handoff. Third, put any private brand assets in public/user-assets/ and confirm they are not staged by git. Fourth, check whether saved store settings survive a version bump, given the release pace. The hosted demo at halcyon-video.github.io/halcyon-video/ is the right first stop, since it needs no signup, no media server and no API key, and playback is intentionally disabled there.
Editorial conclusion
Adopt Halcyon Video if you already run Jellyfin, Plex or Emby and want a second, spatial interface over that same catalog for a couch or HTPC setup. Do not adopt it as a scanner or as a replacement for the server itself: the README states there is no built-in folder scanner, so a shelf of loose files on disk is invisible to it. Before committing, verify three things in order: that your server is reachable from the machine running the launcher, that the browser can decode your files or that an mpv-capable server is on the same box, and that your brand assets land in public/user-assets/, which is git-ignored. If the only copy of your store identity lives outside that directory, a later commit can carry it somewhere you did not intend.
Community notes