npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@r00tkids/rollup-plugin-rootsqz

v0.17.0

Published

Rollup / Vite plugin that compresses and bundles code and assets into one HTML file with rootsqz.

Readme

@r00tkids/rollup-plugin-rootsqz

NPM Version

Rollup / Vite plugin for using rootsqz to compress and bundle code and assets into one HTML file. This is intented for intros in the demoscene or size restricted JS challenges.

Install

npm i -D @r00tkids/rollup-plugin-rootsqz

This installs the rootsqz executable for your platform through @r00tkids/rootsqz. The plugin and the executable share one version.

Usage

// vite.config.js
import { defineConfig } from 'vite';
import rootsqz from '@r00tkids/rollup-plugin-rootsqz';

export default defineConfig({
  build: {
    // Disable module preloading for better compression results
    modulePreload: false,
  },
  plugins: [rootsqz()]
});

Import assets with a query parameter to have them compressed with the code:

import text from "./assets/scroller.txt?rootsqz-txt";             // string
import data from "./assets/rand.bin?rootsqz-bin";                  // Uint8Array
import image from "./assets/logo.jpg?rootsqz-bin&pre-compressed";  // already compressed, stored as it is

The plugin orders the files by type and extension for a better compression ratio. For other file types, e.g. minified shaders, use the fileTransforms option.

Import JSON without a query parameter. Vite then inlines it as a JavaScript object, which packs smaller than the file as it is and needs no JSON.parse. Only when you need the JSON text as a string, e.g. for a library that parses it itself, import it with ?rootsqz-txt&raw:

import levelText from "./assets/level.json?rootsqz-txt&raw";  // string, packed as it is, so minify the file

&raw keeps Vite's own JSON handling away from the import, without it the build fails. The same applies to CSS (style.css?rootsqz-txt&raw). See json-as-string-example.js.

vite build writes the result to rootsqz-output in the output directory, e.g. dist/rootsqz-output/index.html. The dev server does not compress, it inlines the imported files instead.

Notes:

  • The bundle must be a single JavaScript file. If the build fails because of several chunks, set build.rollupOptions.output.inlineDynamicImports to true.
  • The plugin only compresses when NODE_ENV is production. vite build sets this by default; with plain Rollup, set it yourself.
  • Only the JavaScript bundle and the files imported with ?rootsqz-txt or ?rootsqz-bin are packed. Markup in index.html and CSS imported with a plain import "./style.css" are not in the output. Create the elements from JavaScript, and import CSS as a string to add it yourself:
    import css from "./style.css?inline";
    document.head.appendChild(document.createElement("style")).textContent = css;
    document.body.insertAdjacentHTML("beforeend", "<canvas id=c>");
  • Leave build.sourcemap off or set it to 'hidden'. With true, the comment that refers to the source map is packed into the output.
  • To show a loader while the output decompresses, set loader: { preset: "spinner" }, { preset: "bar" } or { preset: "progress" }, or your own { html, js } files. See Loader. To keep the page responsive while it decodes, set decoder: "worker", see Decoder. To decode 5–6 times as fast, for about 1 KB more, set wasmDecoder: true, see WebAssembly decoder.
  • title: "My intro" sets the page title before the output decompresses, and bootJs: "boot.js" runs a script first, see Title and boot script.
  • search: true searches for the model config that packs the bundle smallest before packing, see Config search. It takes about an hour for a 64k intro, so set searchCache to a directory that keeps the config found for the next build of the same bundle. It also keeps the progress there, so a stopped build continues the search; Vite empties dist, so without searchCache a stopped search starts over.
  • With report: true, or with the environment variable ROOTSQZ_REPORT=1 (e.g. ROOTSQZ_REPORT=1 vite build), the plugin writes a compression report to rootsqz-output/report. It names the imported files by their module and maps the bundle back to its original sources, for which it turns on build.sourcemap: 'hidden' if no source map is set. For an imported x.wasm, it gives the report x.debug.wasm (the unstripped file) or x.wasm.map next to it as debug info, or the file that reportWasmDebug: { 'src/x.wasm': 'build/x.full.wasm' } names, so the report names its functions and maps them to source lines. Run npx rootsqz install-skill once to teach coding agents to use it (For coding agents).

See the example for a working example with support for vite-plugin-glsl.

Example Options

rootsqz({
    /**
     * Full path to the rootsqz executable.
     * By default the plugin uses the executable installed with the npm package,
     * or the one named by the environment variable ROOTSQZ_BINARY_PATH.
     */
    rootsqzPath: undefined,

    /**
     * Embedded compression preset: "64k" (default), "4k" for small intros, "64k-wasm",
     * which also models WebAssembly files, "64k-semi-fast" or "64k-fast", which decode about
     * 1.7 and 2 times as fast as "64k" but pack about 2% and 6% larger. The decoder of "64k"
     * and "64k-wasm" needs up to about 1 GB of memory, that of the fast ones 0.6-0.7 GB.
     */
    sizeProfile: "64k",

    /**
     * Pack the output as a Brotli stream that the browser decodes with
     * DecompressionStream('brotli') (Firefox 147+ / Safari 18.4+, not Chrome).
     * Cannot be combined with `config`, `report` or a 64k size profile.
     */
    brotli: false,

    /**
     * Path to a complete JSON compression config.
     * Takes precedence over `sizeProfile`.
     */
    config: undefined,

    /**
     * Write a compression report to rootsqz-output/report/: report.json, a summary
     * for analysis (also by an LLM), report.html, and data.bin for `rootsqz report`.
     * The environment variable ROOTSQZ_REPORT=1 also turns it on.
     */
    report: false,

    /**
     * Also record what every submodel predicted. Implies `report`.
     */
    reportModels: false,

    /**
     * Also write these views of the report as TSV files, e.g. ["lines", "tokens"].
     * Implies `report`.
     */
    reportDetail: [],

    /**
     * Debug info of imported wasm files, by their path: the unstripped .wasm or a .wasm.map.
     * Without it, x.debug.wasm and x.wasm.map next to x.wasm are used. Implies `report`.
     */
    reportWasmDebug: {},

    /**
     * Loader shown while the output decompresses: a built-in `preset` ("spinner", "bar" or "progress"),
     * or your own `html` and `js` files (paths relative to the working directory).
     * `keep` leaves it in place when the bundle runs, so the demo can continue the progress.
     * See https://github.com/r00tkids/rootsqz#loader
     */
    loader: { preset: "bar", keep: false },

    /**
     * How the output decodes: "serial" (in one go), "sliced" (in slices on the main thread)
     * or "worker" (in a web worker). By default "sliced" with a loader script, otherwise "serial".
     * See https://github.com/r00tkids/rootsqz#decoder
     */
    decoder: "worker",

    /**
     * Decode with a WebAssembly decoder generated for the config, with any decoder: 5–6 times
     * as fast, for about 1 KB more. See https://github.com/r00tkids/rootsqz#webassembly-decoder
     */
    wasmDecoder: false,

    /**
     * Hide the packed bytes while the page loads, instead of the browser showing them as text.
     * Adds 19 bytes. By default on with the 64k size profiles, off with 4k and brotli.
     */
    hideData: true,

    /**
     * Title of the page, set before the output decompresses.
     */
    title: "My intro",

    /**
     * File with JavaScript that runs first, before the loader and decompression, e.g. to set
     * up the page. It is not bundled, but minified with the boot code.
     */
    bootJs: "boot.js",

    /**
     * Search for the model config that packs the bundle smallest, counting the decoder bytes of
     * each change. `searchCache` keeps the config found for the next build of the same bundle,
     * `searchThreads` sets how many configs are tried at once.
     * See https://github.com/r00tkids/rootsqz#config-search
     */
    search: false,
    searchThreads: undefined,
    searchCache: undefined,

    /**
     * Name of the global that the boot code of the executable puts the files in.
     * By default `rsqz`. Set it to `wsqz` when `rootsqzPath` names an executable up to 0.4.0.
     */
    runtimeGlobal: undefined,

    /**
     * Further arguments passed to the executable as they are.
     */
    rootsqzArgs: [],

    /**
     * Hooks that process files before they are imported in code or compressed by rootsqz.
     * The first hook that matches a module id and returns a result is used.
     */
    fileTransforms: [
        {
            /**
             * Module ids that the transform applies to. By default all.
             */
            include: /\.glsl$/,

            /**
             * Module ids that the transform does not apply to.
             */
            exclude: undefined,

            /**
             * Returns the content to pack for the module `id`, given the content of its file as a Buffer.
             * `ctx` is the Rollup plugin context.
             */
            transform: async (ctx, id, content) => {
                return {
                    /**
                     * The content to pack, as a Buffer.
                     */
                    content: Buffer.from("Hello World", "utf-8"),

                    /**
                     * Whether the content is already compressed and should be stored as it is.
                     */
                    isCompressed: false,

                    /**
                     * Whether the content is text. The import then gives a string instead of an Uint8Array.
                     */
                    isText: true,

                    /**
                     * Optional, by default taken from the file path.
                     */
                    fileExt: ".glsl"
                };
            }
        }
    ]
})