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

@fps-games/vite-plugins

v0.1.2

Published

Vite plugin collection for playable ad / HTML5 game builds — asset versioning, GLB compression, PNG optimization, locale fallback, dependency allowlist, Babylon.js tree-shaking & inspector.

Readme

@fps-games/vite-plugins

Vite plugin collection for playable ad / HTML5 game builds.

Covers the full build pipeline: dev-time asset caching, locale fallback, binary compression, image optimization, dependency guardrails, and Babylon.js-specific tree-shaking.

Install

npm install @fps-games/vite-plugins -D

Quick Start

// vite.config.ts
import { defineConfig } from 'vite';
import {
  modelCachePlugin,
  binaryCompressPlugin,
  imageOptimizePlugin,
  depWhitelistPlugin,
  localeAssetsPlugin,
  scriptInjectPlugin,
  inspectorBridgePlugin,
} from '@fps-games/vite-plugins';

// Babylon.js plugins (optional)
import {
  stripBabylonPlugin,
  babylonInspectorPlugin,
} from '@fps-games/vite-plugins/babylon';

export default defineConfig({
  plugins: [
    // Dev plugins
    modelCachePlugin({
      extensions: ['.glb', '.png', '.jpg'],
      roots: ['src/assets', 'src/shared'],
    }),
    localeAssetsPlugin({ locale: 'zh', htmlLang: 'zh-CN' }),
    babylonInspectorPlugin(),
    // Inspector Bridge — 独立的 inspector 命令监听器(与 bridge.js 解耦)
    inspectorBridgePlugin(),
    scriptInjectPlugin({
      src: 'http://localhost:8080/script/bridge.js',
      delay: 2000,
    }),

    // Build plugins
    binaryCompressPlugin({ extensions: ['.glb'] }),
    imageOptimizePlugin({ optipngLevel: 2, webpQuality: 80 }),
    stripBabylonPlugin(),
    depWhitelistPlugin({
      allowedPackages: ['@babylonjs/core', '@babylonjs/loaders'],
    }),
  ],
});

Plugins

Universal (any Vite project)

| Plugin | Mode | Description | |--------|------|-------------| | modelCachePlugin | dev | Appends ?v=<mtime> to new URL() asset imports for cache-busting. Serves versioned assets with immutable cache headers. | | localeAssetsPlugin | both | Resolves @locale-img/file.png to locale-specific directory with fallback. Injects lang and dir attributes on <html>. | | binaryCompressPlugin | build | Brotli-compresses binary assets (GLB, etc.) and inlines as base64 data URL. ~16% smaller than gzip. | | imageOptimizePlugin | build | Post-build PNG optimization via optipng (lossless) and cwebp (lossy). Picks whichever is smallest. | | depWhitelistPlugin | build | Throws build error if project code imports an npm package not in the allowlist. Prevents accidental bundle bloat. | | scriptInjectPlugin | dev | Injects a <script> tag into index.html with configurable URL, delay, async, and error handling. | | inspectorBridgePlugin | dev | Inlines the inspector-bridge IIFE (~2KB) into index.html. Decouples inspector commands (mode.change, asset.import, etc.) from bridge.js. |

Babylon.js (@fps-games/vite-plugins/babylon)

| Plugin | Mode | Description | |--------|------|-------------| | stripBabylonPlugin | build | Tree-shakes unused Babylon.js modules: WGSL shaders, Audio, GUI, XR, Physics, OpenPBR, unused texture loaders, KHR_interactivity. | | babylonInspectorPlugin | dev | Lazy-loads @babylonjs/inspector via globalThis.ensureInspectorReady(). Auto-preloads on ?edit, ?inspector, etc. |

Plugin Details

modelCachePlugin

modelCachePlugin({
  extensions: ['.glb', '.png', '.jpg', '.webp'],  // file types to version
  roots: ['src/assets'],                            // directories to watch
  cacheMaxAgeSeconds: 31536000,                     // 1 year (default)
})

Intercepts new URL('model.glb', import.meta.url) patterns in TypeScript files and appends ?v=<mtime>. The dev server responds with Cache-Control: public, max-age=31536000, immutable when the version param is present, eliminating redundant network requests during development.

binaryCompressPlugin

binaryCompressPlugin({
  extensions: ['.glb'],                    // file types to compress
  mime: 'application/x-brotli',            // output MIME type
  minSize: 10 * 1024,                      // skip files < 10KB
  enabled: true,
  verbose: true,
})

Uses Brotli quality 11 for maximum compression. Output is a base64 data URL that the runtime decompresses (e.g., via brotli-dec-wasm). Prints a summary table at build end.

localeAssetsPlugin

localeAssetsPlugin({
  locale: 'ar',            // BCP 47 code
  htmlLang: 'ar',          // <html lang="ar">
  isRTL: true,             // adds dir="rtl"
  imgRoot: 'src/assets/ui', // base directory
  alias: '@locale-img',    // virtual import prefix (default)
})

Usage in code:

import logo from '@locale-img/logo.png?url';
// Resolves to src/assets/ui/ar/logo.png if it exists, otherwise src/assets/ui/logo.png

stripBabylonPlugin

stripBabylonPlugin({
  exclude: ['/Audio/', '/GUI/', '/XR/', '/Physics/', ...],  // defaults provided
  stripWGSL: true,            // remove WebGPU shaders
  stripOpenPBR: true,         // remove OpenPBR glTF extension
  stripTextureLoaders: true,  // remove DDS/Basis/KTX/TGA/EXR/HDR/IES loaders
  stripInteractivity: true,   // remove KHR_interactivity extension
})

Typical bundle size reduction: 30-50% of Babylon.js code removed.

depWhitelistPlugin

depWhitelistPlugin({
  allowedPackages: [
    '@babylonjs/core',
    '@babylonjs/loaders',
    '@babylonjs/inspector',
  ],
  projectRoot: process.cwd(),  // optional, defaults to Vite config root
})

Any import of a package not in the list will throw a descriptive build error showing the source, importer, and current allowlist.

imageOptimizePlugin

imageOptimizePlugin({
  optipngLevel: 2,            // 0-7, higher = slower but smaller
  webpQuality: 80,            // 0-100
  skipTransparentToWebp: true, // keep PNG for images with alpha
  scanDirs: ['src'],          // for content-hash → filename mapping in logs
})

Requires optipng and/or cwebp CLI tools installed. On macOS: brew install optipng webp.

scriptInjectPlugin

scriptInjectPlugin({
  src: 'http://localhost:8080/script/bridge.js',
  delay: 2000,               // ms before injection
  enabled: true,
  async: true,
  errorMessage: '[Bridge] Not available',
  // Optional URL rewrite for cloud environments:
  urlRewrite: `
    var e2b = location.href.match(/\\d+-([a-z0-9]+)\\.e2b\\.app/);
    return e2b ? 'https://8080-' + e2b[1] + '.e2b.app/script/bridge.js' : defaultSrc;
  `,
})

babylonInspectorPlugin

babylonInspectorPlugin({
  preloadParams: ['edit', 'inspector', 'debugGame', 'mcp'],  // URL params that trigger preload
  initScript: '/path/to/custom-init.ts',                       // optional custom init script
})

Exposes globalThis.ensureInspectorReady() which returns a Promise that resolves to the inspector module. Also preloads EffectLayer and DepthRenderer scene components for selection outline support.

inspectorBridgePlugin

inspectorBridgePlugin({
  enabled: true,     // default
  apply: 'serve',    // 'serve' | 'build' — default 'serve'
  delay: 0,          // ms before injection — default 0 (inject immediately)
})

Purpose: Decouple inspector commands (mode.change, asset.import, history.undo, etc.) from bridge.js.

How it works:

  1. Injects the inspector-bridge IIFE (~2KB) directly into index.html
  2. The script sets window.__inspectorBridge = { active: true }
  3. bridge.js detects this flag and skips inspector commands
  4. Inspector commands are handled independently without duplication

Recommended setup:

plugins: [
  inspectorBridgePlugin(),                       // inject first (no delay)
  scriptInjectPlugin({
    src: 'http://localhost:8080/script/bridge.js',
    delay: 2000,                                 // bridge.js loads after
  }),
]

Why separate?

  • bridge.js = MCP tools (screenshot, debug, CDP)
  • inspector-bridge = Editor commands (edit mode, asset import, undo/redo)
  • Both scripts run independently; no coupling required

Requirements

  • Node.js >= 18
  • Vite >= 5.0
  • For imageOptimizePlugin: optipng and/or cwebp in PATH
  • For Babylon.js plugins: @babylonjs/core (peer dependency, optional)

License

MIT