Open-source project
jeffshee/gnome-ext-hanabi avatar
jeffshee/gnome-ext-hanabi

Hanabi: a GNOME live wallpaper extension with three branches and one video sink

Live Wallpaper for GNOME

1,646 stars71 forksTypeScriptGPL-3.0

At a glance

What is it?
Hanabi is a GPL-3.0 GNOME Shell extension that plays a video as the desktop wallpaper, and it now ships a TypeScript rewrite for GNOME 50 on Wayland while the older JavaScript branch stays in maintenance mode for GNOME 45 to 50. Its troubleshooting notes cover a missing GTK4 media backend, proprietary NVIDIA decode paths and a clash with Blur My Shell.
Who is it for?
Hanabi is a good pick for a GNOME user on Wayland who wants a moving wallpaper and is willing to install a media backend and pick a video sink, since the extension does the compositor work and the scriptable preferences cover the rest; it is the wrong pick for an X11 session on GNOME 42 to 44, where only a legacy branch exists and the support status is marked with a warning, and before you install you should check the branch table, because the main branch is Wayland only and cloning the wrong one produces an extension that never starts.
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 last received commits 14 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Pick the branch before you clone anything

Hanabi is a GNOME Shell extension that plays a video as the desktop wallpaper, named after the Japanese word for fireworks. The project is by Jeff Shee.

The install instructions begin with the branch, because the branch determines whether the extension will work on your machine at all. The support table has three columns of GNOME versions and three branches. GNOME 42 to 44 is on the legacy branch with a warning status, GNOME 45 to 50 is on the javascript branch with a supported status, and GNOME 50 and later is on main with a supported status.

The consequence is spelled out in the migration note. Hanabi has migrated to TypeScript, and the rewrite has landed on the main branch, targeting GNOME 50+ and Wayland only. The javascript branch is in maintenance mode for GNOME 45 to 50, where bugs still get fixed but no new fireworks are added. The new features, meaning the video sink options and the scripting guide, land on main only.

That last detail is a real planning input. If you are on GNOME 47, you are on the JavaScript branch and you will not get the clappersink option or the scripting API. If you are on GNOME 50 with Wayland, you are on the TypeScript branch and you get both. The project is explicit that main is Wayland only, so an X11 session on GNOME 50 needs the javascript branch.

The repository is not archived, the last push was on 2026-10-09, and there are no GitHub releases, so the branch is the versioning mechanism rather than a tag.

Clone, make install, restart the shell

The installation is a clone, a make target, and a shell restart.

For GNOME 50 and later, the default branch is the TypeScript one:

bash
git clone https://github.com/jeffshee/gnome-ext-hanabi.git

For GNOME 45 to 50, the JavaScript branch is what you want:

bash
git clone https://github.com/jeffshee/gnome-ext-hanabi.git -b javascript

Then the install script runs:

bash
cd gnome-ext-hanabi
make install

The build dependencies differ by branch, and this is worth noticing because it is the visible sign of the rewrite. The main branch needs meson, node and npm, while the javascript branch needs only meson. The TypeScript version compiles through Node before the meson install, the JavaScript version does not.

After the install you restart GNOME Shell, enable the Hanabi extension, and choose your video wallpaper in the extension preference window.

The Makefile is where the real mechanics sit, and it is a good example of a GNOME extension project done properly. The extension UUID is [email protected], and the install target removes any previous install directory, sets up meson with a prefix at $HOME/.local/ and runs ninja to install into it. So the extension lands in the user directory rather than system wide, which is the right default for an extension that you are building from source.

The other targets cover the whole lifecycle: enable, disable, prefs, reset and uninstall all call gnome-extensions with the UUID, the renderer target runs the built renderer directly with gjs -m, log follows the GNOME Shell journal, and the build and typecheck targets depend on node_modules, which npm install creates from the lockfile.

The video sink choice is where the real configuration lives

Hanabi uses gtk4paintablesink, from GStreamer, as the default video sink, and the advanced usage section explains the alternative.

The default is described as offering good performance and broad compatibility, and it is the sensible starting point. The alternative is clappersink, from the Clapper project, and you can select it through Preferences, Developer, Prefer clappersink. Two constraints come with it. Clapper must be installed from the package manager and not from Flatpak or Snap, and there is a known compatibility issue with clappersink on native installs with GStreamer 1.26 or newer, so the documentation says to disable the option if you hit crashes after enabling it.

That is a level of honesty in a preferences dialog documentation that is not common. The instruction is effectively: try it, and if the desktop starts crashing, turn it back off.

For deeper control there is a scripting guide, at docs/scripting.md, for writing scripts for the extension. The Makefile has a renderer target that runs the built renderer directly with gjs -m and accepts extra arguments through ARGS, which is what makes iterating on a script practical rather than a matter of reloading the whole shell every time.

The extension is also scriptable in the sense that the preferences window is not the only interface, which is unusual for a wallpaper extension and is probably why the developer wrote a guide for it.

Three failure modes worth knowing before you file a bug

The troubleshooting section is specific and covers the three problems most likely to hit you.

The first is that the video does not play, or the extension is enabled and nothing happens. The cause is that the GTK4 media backend is not pre-installed on some distributions, and PopOS is named as an example. The fix is one package:

bash
sudo apt install libgtk-4-media-gstreamer

The second is high CPU usage during playback on proprietary NVIDIA hardware. The explanation is that hardware acceleration may not work properly, and a GStreamer issue is linked for the details. The suggested remedy is to delete the GStreamer cache, and then to check whether gst-inspect-1.0 nvcodec reports all its features:

bash
rm -rf ~/.cache/gstreamer-1.0/

Deleting the cache is the right first move here because GStreamer caches its plugin registry and a stale entry pointing at a missing decoder produces exactly this kind of behaviour.

The third is an interaction with another extension rather than a bug in Hanabi. Blur My Shell with Applications blur and Enable all by default turned on makes the wallpaper semi-transparent. The fix is to add an exception, in Blur My Shell's settings under Applications, Applications blur, Blacklist, with the value io.github.jeffshee.HanabiRenderer. That string is the renderer process identifier, and it is the one piece of this extension's internals the user has to know.

Distro-specific installation instructions live in a docs/distro/ directory, which is the place to look if the generic steps do not match your distribution's packaging.

The TypeScript rewrite and the GIR type packages

The package.json shows what the rewrite involved at the type level, and it is a specific choice rather than a generic one.

The dev dependencies are almost entirely @girs packages, which are generated TypeScript type definitions for GObject introspection libraries. There is one for each API the extension touches: gnome-shell at version 50, gjs, gtk-4.0, gdk-4.0, gio-2.0, glib-2.0, gobject-2.0, and a set of versioned 18 packages for clutter, cogl, meta, shell and st, which cover the Clutter and Shell libraries the extension uses. There are also gst, gstaudio and gstplay for GStreamer, and upowerglib for power management.

The versioned names are the point. By depending on clutter-18 and shell-18 rather than the older clutter and shell packages, the code is pinned to the API generation that GNOME 50 uses, so a TypeScript type error is raised at compile time rather than a runtime failure in the shell. That is the practical benefit of a rewrite in TypeScript for a platform whose API surface changes every six months.

The build uses esbuild, and the scripts are lint, build and typecheck, where typecheck is tsc --noEmit, so nothing is emitted during a type check. The main entry point in package.json is src/_build/extension.js, which is the compiled output directory, and the package is marked as an ES module.

The licence is GPL-3.0-or-later in the package metadata, and the licence file is at the repository root, which is the standard and expected licence for a GNOME Shell extension, since extensions are loaded into the user's session.

Translations, the renderer, and the project structure

The extension is translated, and the build system treats that as a first-class concern rather than an afterthought.

The Makefile defines a UUID of [email protected] and a POT directory at src/po, with the template file named after the UUID. There is a pot target that finds the TypeScript sources and generates the translation template, and a merge-po target that merges an updated template into all the .po files. The .licensure.yml file at the repository root suggests the licences of the bundled resources are tracked separately from the extension's own licence.

The renderer is a separate process from the extension itself, which is why the Makefile has a renderer target that runs gjs -m against the built renderer.js. The UUID in the Blur My Shell blacklist entry, io.github.jeffshee.HanabiRenderer, confirms that the renderer is a distinct process with its own bus name, and separating it means a crash in the video pipeline does not have to take the shell with it.

The top level of the repository shows the pieces: build-aux/ for the meson build support, build.js as the Node build entry, docs/ for the distro guides, the development guide and the scripting guide, res/ for resources including the sparkler.svg logo, src/ for the sources and the translations, tools/ for helper scripts including the ESLint runner, plus meson.build, a Makefile, a package.json with a lockfile, a tsconfig.json and an eslint.config.js.

Translations are managed on Hosted Weblate, and the project is a single maintainer with a sponsorship page, a Discord server, and the usual set of funding links. The readme is enthusiastic in a way that says more about the project's tone than its content, but the substance of the documentation is good: the install steps, the branch table and the three troubleshooting cases are exactly what a user needs.

Editorial conclusion

Hanabi is a good pick for a GNOME user on Wayland who wants a moving wallpaper and is willing to install a media backend and pick a video sink, since the extension does the compositor work and the scriptable preferences cover the rest; it is the wrong pick for an X11 session on GNOME 42 to 44, where only a legacy branch exists and the support status is marked with a warning, and before you install you should check the branch table, because the main branch is Wayland only and cloning the wrong one produces an extension that never starts.

Frequently asked questions

How do I install the Hanabi live wallpaper extension on GNOME?

Clone the branch matching your GNOME version, then run the install script. For GNOME 50 and later the default TypeScript branch is cloned with git clone https://github.com/jeffshee/gnome-ext-hanabi.git, and for GNOME 45 to 50 you add -b javascript. Then cd gnome-ext-hanabi, run make install, restart GNOME Shell and enable the extension.

Which GNOME versions does the Hanabi TypeScript rewrite support?

GNOME 50 and later, and Wayland only. The javascript branch is in maintenance mode for GNOME 45 to 50, where bugs are still fixed but no new features are added, and GNOME 42 to 44 is covered only by a legacy branch marked with a warning.

Why is my Hanabi video wallpaper not playing?

The GTK4 media backend is not pre-installed on some distributions, PopOS is named as an example. Installing it with sudo apt install libgtk-4-media-gstreamer resolves it.

How do I fix Hanabi high CPU usage on NVIDIA?

Hardware acceleration may not work properly with the proprietary driver. Delete the GStreamer cache with rm -rf ~/.cache/gstreamer-1.0/ and then check whether gst-inspect-1.0 nvcodec reports all its features.

What licence is the Hanabi GNOME extension released under?

GPL-3.0-or-later, as declared in package.json, with the licence file at the repository root. The repository is not archived, the last push was on 2026-10-09, and there are no GitHub releases, so the branch is the versioning mechanism.

Official sources

  1. Issues
  2. jeffshee/gnome-ext-hanabi on GitHub
  3. License: GPL-3.0
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jeffshee-gnome-ext-hanabi.svg)](https://hysenlabs.com/projects/jeffshee-gnome-ext-hanabi)

Was this useful?