chrissix666-lab

Tree / Self Hosting / Movies & TV Shows / Jellyfin / Experience & Ambience

Destroy

Turns the Jellyfin page you are on into a game level, while 925,870 quotes from its films and actors react to what you destroy. A port of destroy-any-website by ychisbest, a remake of Hugo Duprez's game.

Status
Green · Released
Type
plugin
Hours
about 59
Tokens
about 14 M

Released on GitHub as an Alpha for Jellyfin 10.10.7 and 12.0+, and playable on your own library.

GitHub

In this article
  1. My own library as a level
  2. The page you are on becomes the level
  3. A port that keeps its hands off the original
  4. How it was made, and with what
  5. A copy that has to behave like the page
  6. What made it more than a port
  7. An Alpha, and the label is honest

My own library as a level

There is no gap here, and I will not invent one. Jellyfin was not missing a game. Destroy Any Website is a browser game that turns any web page into a level, and I wanted that for Jellyfin: not on a random website, but on my own library, with heroes from my own films and lines from my own series.

The original could not get there. It needs a Node and Cloudflare proxy and refuses private addresses, and Jellyfin Web is a single-page app, so a proxy would receive an empty page anyway. A self-hosted library on a private address, drawn by JavaScript, is exactly what it cannot play on. It also has no idea what is on the page, and that became the real goal. The page should know what it is and talk back.

So the brief was: play on the live Jellyfin page, on both Jellyfin lines, with one script, without changing Jellyfin. Desktop browser first. Fully playable with a controller alone, because some Jellyfin clients have no mouse.

The page you are on becomes the level

Press the Destroy button in the header, the shortcut, or View and Menu on a controller, and the page you are on becomes the level. Every poster shatters into its own picture. Cards hang on one nail and swing before they fall. Text breaks word by word. The backdrop is never destroyed, but it takes bullet holes, cracks and scorch marks. Close the game and you are back on the same page at the same scroll position, because it only ever played on a copy. Your library and settings stay as they were.

Jellyfin Destroy in action

The hero fits the page. There are 228 pixel heroes, and each belongs to the films or series of its character, so opening a film's page starts its hero. You can run a party of up to six, pick from a roster shown as Jellyfin cards, and free a hero by destroying its film's poster. There are seven standard weapons, signature weapons for the heroes and a grenade for everyone, and each leaves its own kind of mark. Fire spreads from card to card, debris piles up and can be kicked, and an autopilot can play for you.

Then the page talks. Shoot a person card and that actor says one of their own lines from the film you are on. Shoot a film card and it answers with a quote. Search, cast, the user menu, hearts and check marks all have their own jokes. Everything else gets lines built from what Jellyfin knows: franchise, sequels, genre, rating, runtime, an actor's age and roles.

A line is chosen in a fixed order: a person's own line from the title on screen, then a co-star's line from the hero's own films, then a line of the title itself, episode before season before series, and finally Destroy's own lines built from facts. Short well-known lines come up more often, and a line from the last 40 is almost never repeated. People who have died are never mocked. They get their quote instead.

The plugin ships 925,870 lines from 8,610 films and series. 778,404 of them are tied to the person who says them, across 33,151 people, and 304,102 series lines are tied to a season or episode. On top come 2,517 templates of its own in 730 rules and 518 jokes for 140 parts of Jellyfin's pages.

Setup is the plugin catalog: add the repository, install Destroy, restart, reload. Jellyfin picks 1.x for 10.10.7 or 2.x for 12.0+. File Transformation by IAmParadox27 is recommended, and needed where the web folder is read-only, as in many Docker setups. The admin page covers the button, shortcut, controller, start hero, effect quality, one-liners and personal settings per browser. It runs in Jellyfin Web in a desktop browser. Apps that load the server's web page, such as Jellyfin Desktop or Jellyfin for Xbox, should work and are not tested. Native apps cannot run it.

A port that keeps its hands off the original

The game is a port of destroy-any-website by ychisbest (MIT), itself a remake of Hugo Duprez's Destroy Any Website. I want that clear, because the fun physics idea is theirs. Everything specific to Jellyfin was built on top of it.

A C# server part adds one script tag and serves the game script, sprites and quote blocks itself, so nothing loads from outside. The JavaScript part copies the live, rendered page into a same-origin frame, reads the styles from the browser, leaves the scripts out, fills in pictures that have not loaded yet, and runs the game on that copy in a shadow-DOM overlay. Nothing can leak back into Jellyfin.

The rule for the port was "port, do not adapt". The upstream code is never edited. Every game change is an exact patch applied at build time, and a patch that stops matching breaks the build. That keeps what is theirs and what is ours visibly apart.

How it was made, and with what

Two Claude Code sessions wrote everything on top of the upstream game. One wrote the code, patches, tools, plugin and hero art. The other built the data under a written briefing and could only deliver into its own folder, and a delivery entered the build only if its checksum was accepted. A separate session audited the admin page. I set the goals, decided the roster rules, sent reference images, tested by eye on my own server and marked hero corrections pixel by pixel.

Sources came before code. A feature and mode matrix was derived from the Jellyfin Web source for both lines before the first live run. A pixel art study produced four style drafts, of which I chose one. An effects field study went through 25 repositories and articles, and became one concept with budgets. A regression list of 24 invariants, each from something I had asked for, is checked in the running game. An autopilot bot plays the page for live tests.

The data pipeline used English Wikiquote for the quotes, under CC BY-SA, with TMDb and Wikidata for film, series and cast IDs. Lines are matched by the same IDs Jellyfin uses. The briefing was strict: accuracy first, no invented quotes, public screen persona only, nothing about private life, PG-13.

For the showcase video, Playwright captured the runs and RIFE v4.6 smoothed them. For a possible hero rework, ComfyUI with SDXL and pixel-art-xl ran as a pilot.

A copy that has to behave like the page

The hardest part of the game was not the game. It was making a copy of a live page behave like the page. A real library looks nothing like a test library. On my real server, with ArtworkPlus active, the first run showed black boxes, posters losing their pictures and blurred pieces. On the test servers the posters had kept their pictures. The copy needed specific handling for WebGL canvases, crossfading image twins, drawn logos and loaded fonts.

A copy of the live page, breaking apart poster by poster.

The lines took longest. Getting close to a million quotes into a form that can be chosen by person, title, season and episode meant matching names and IDs at scale. Packing them was harder than expected too, at 28.7 MB rather than the estimated 12 to 18. Licences shaped the choices too, and two datasets could not ship.

The heroes were the most subjective problem. Only the first ten or so were written directly as pixel rows. The rest came from a kit of parts in code with hand-made heads for masks and non-humans, and then round after round of my corrections by eye: hair, eyes, stubble, likeness. A batch process gets you 228 characters. It does not get you 228 people who look right.

Performance has a limit that the game cannot fix alone. Heavy missile salvos stutter, and the measurements put about 1 ms in the game and the rest in the browser.

What made it more than a port

  • Worked: playing on a copy of the page. It is the idea that makes the whole thing safe, and it solved the private address problem completely.
  • Worked: the exact-patch build. Upstream stayed untouched, and any drift stopped the build.
  • Worked: one effects system with budgets, in place of effects grown separately in five places.
  • Worked: the two-session split with checksum acceptance. Data work ran beside code work without touching it.
  • Worked: the context lines. They are what makes this more than a port.
  • Partly: touch and TV remote code exists in the build, but it was never checked on a real device, and the project is desktop only.
  • Partly: the AI hero pilot with ComfyUI and SDXL. It ran, and I have not adopted it. Higher resolution, AI as reference only, or dropping it are all still open.
  • Did not work: taking character art from a GPL Broforce mod. The licence was unclear and the hero I wanted was not there. Only mechanics and timings served as a model, and the heroes are our own.
  • Did not work: multiplayer. It would need a WebSocket server, so it was dropped.
  • Did not work: a public quote CSV and an IMDb dataset. The first states no licence, so that table ships empty in the release. The second is personal-use only.

An Alpha, and the label is honest

A working game to start from and a strict port rule kept the code work disciplined here. What could not be automated was taste and the real library. The test servers said fine, and my own server said no.

Automatic effect quality is not verified. Open items are a stutter fix, the decision on the heroes, and further effects packages. Credit for the game itself stays with ychisbest and Hugo Duprez.

Connected

Next: Playnite Bridge