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

shader-panel

v1.0.0

Published

Drop-in dev panel for tweaking shader uniforms live — sliders, color pickers, keyboard shortcut, copy/write JSON. Zero CSS framework, zero animation library.

Readme

shader-panel

npm version bundle size license

A floating panel for tweaking shader uniforms live — sliders, color pickers, copy/paste JSON. Works with any WebGL, Three.js, or React Three Fiber shader.

No CSS framework, no animation library, two peer deps (react, react-dom), and it compiles out of production builds (~5 KB no-op). Toggle with ⌘⌥D.

npm install shader-panel

Set it up in seconds

Open your shader file in Cursor / Claude Code and paste the setup prompt ». It detects the renderer, finds your tweakable uniforms, builds the panel, and wires up the hook — nothing to configure.

Or wire it by hand

One hook. It owns the state, registers the shader, and injects the panel — no <ShaderDevRoot/>, no extra files.

import { useShaderDev, type ShaderDevFieldDef } from "shader-panel"

type Config = { speed: number; bgColor: string }
const DEFAULTS: Config = { speed: 1, bgColor: "#ff5e1f" }

const FIELDS: ShaderDevFieldDef<Config>[] = [
  { type: "section", title: "Animation" },
  { type: "slider", key: "speed", label: "Speed", min: 0, max: 2, step: 0.01 },
  { type: "color", key: "bgColor", label: "Background" },
]

export function MyShader() {
  const [config] = useShaderDev({
    id: "my-shader",
    title: "My shader",
    defaults: DEFAULTS,
    fields: FIELDS,
  })

  // feed `config` to your shader — Three.js uniforms, mount.setUniforms(...), a useFrame ref
}

config updates as you drag. That's it. (Prefer to mount the panel yourself? See Manual mount.)

Field types

type ShaderDevFieldDef<T> =
  | { type: "section"; title: string }
  | { type: "slider"; key; label; min; max; step }
  | { type: "color";  key; label }                       // "#rrggbb"
  | { type: "toggle"; key; label }                       // boolean
  | { type: "select"; key; label; options: {value; label}[] }
  | { type: "vec2";   key; label; min; max; step }       // [x, y]

Fields are grouped by section headers (collapsible). Anything before the first section lands under "Parameters".

What you get for free

  • Multi-shader switcher — use the hook in several components and a dropdown appears to flip between them.
  • Saves to localStorage — edits survive reload automatically. "Reset to defaults" clears them; opt out with persist: false.
  • Copy / Paste JSON — share a look with a teammate; paste merges known keys.
  • Per-section reset — hover a section header for a that resets just that group.
  • AI prompts — a row of copy-paste prompts (improve quality, optimize GPU, find bugs, reduce shimmer, …) written as expert briefs. Click to copy, paste into Cursor / Claude. Customize with prompts: [...] or hide with prompts: [].

Adapters — skip the uniform boilerplate

Generate the config → uniforms mapping from your field schema instead of writing it by hand.

WebGL / @paper-design/shaders:

import { createWebGLAdapter } from "shader-panel"

const toUniforms = createWebGLAdapter<Config>({ fields: FIELDS })
useEffect(() => mount.setUniforms(toUniforms(config)), [config])

React Three Fiber (mutates .value slots in place — no recompile):

import { createR3FAdapter } from "shader-panel"

const apply = useMemo(() => createR3FAdapter<Config>({ uniforms, fields: FIELDS }), [uniforms])
useEffect(() => apply(config), [config, apply])

Colors auto-convert (hex → vec3 / THREE.Color), vec2s become [x,y] / Vector2. Uniform names default to u_<key>; override with mapping: { bgColor: "u_bg" }.

Production builds

Bundlers building with NODE_ENV=production automatically resolve a tiny no-op stub via package exports conditions — the panel UI drops out (ShaderDevRootnull, registerShaderDev → no-op), but the adapters and helpers you use at runtime stay intact. ~63 KB dev → ~5 KB prod.

Need the panel in a production build (e.g. staging)? Import from the /dev subpath:

import { ShaderDevRoot } from "shader-panel/dev"

Prefer to own the wiring? Pass autoMount: false to the hook (or skip it entirely with registerShaderDev) and render the panel root yourself — once, anywhere (it portals to <body>):

import { ShaderDevRoot, registerShaderDev } from "shader-panel"

// once, e.g. in your layout
<ShaderDevRoot />

// in the shader component
useEffect(() => registerShaderDev({
  id: "my-shader", title: "My shader",
  values: config, defaults: DEFAULTS, fields: FIELDS, onChange: setConfig,
}), [config])

registerShaderDev returns an unregister fn if you want it as the effect cleanup.

Light + dark auto-switch based on html.dark and OS preference. Override any color with CSS variables on the scoped root:

[data-shader-dev] {
  --sd-bg: rgba(20, 20, 20, 0.92);
  --sd-text: #f5f5f5;
  --sd-handle: #00ff95;
  /* ~20 tunables — see src/styles.ts */
}

Force a theme per mount: <ShaderDevRoot defaultTheme="light" />.

Wrap your defaults in marker comments:

// @shader-config-start
export const MY_SHADER_DEFAULTS = { speed: 1.0 } as const
// @shader-config-end

Pass onWriteConfig to registerShaderDev, and on your dev server use patchShaderConfigDefaults(source, "MY_SHADER_DEFAULTS", json) to rewrite the block. A "Write config file" button appears in the panel.

| Export | Purpose | | --- | --- | | useShaderDev({ id, title, defaults, fields, ... }) | The one-call hook. Owns state, registers, auto-injects the panel. Returns [config, setConfig]. | | registerShaderDev(reg) | Lower-level: register a shader manually. Returns an unregister fn. Pair with <ShaderDevRoot/>. | | ShaderDevRoot | The panel root. Rendered for you by the hook; mount it yourself only with autoMount: false. | | createWebGLAdapter({ fields, mapping?, prefix? }) | Returns (config) => uniforms for WebGL / ShaderMount. | | createR3FAdapter({ uniforms, fields, mapping? }) | Returns apply(config) that mutates Three.js .value slots. | | hexToRgb01(hex) | "#rrggbb"[r,g,b] in [0,1]. | | loadPersistedShaderDevValues(id, defaults) | Manual localStorage hydration (the hook does this for you). | | patchShaderConfigDefaults(src, name, json) | Rewrites a defaults block between @shader-config-start/end markers. | | setActiveShaderDev / getActiveShaderDev / getShaderDevRegistrations | Multi-shader registry access. | | DEFAULT_SHADER_DEV_PROMPTS / fillShaderDevPrompt | The built-in AI prompts + the {{shader}} token filler. | | ShaderDevPanel / ControlSlider / ControlColorInput / … | Low-level primitives if you don't want the floating panel. |

License

MIT