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

@threeforged/static-optimizer

v0.1.3

Published

Optimize static geometry in Three.js scenes — merge non-moving meshes to reduce draw calls

Readme

@threeforged/static-optimizer

Analyze and merge static meshes in Three.js scenes. Groups non-animated meshes by material compatibility, estimates draw call savings, and optionally merges them into optimized output files using gltf-transform.

Installation

  1. Install the CLI: npm install -g @threeforged/cli
  2. Install this plugin: npm install @threeforged/static-optimizer
  3. Run: threeforged static ./scene.glb

CLI Usage

# Analyze mode (default — no files written)
threeforged static <path>                          # Detect static merge candidates
threeforged static <path> --json                   # JSON output
threeforged static <path> -o report.txt            # Save to file

# Write mode — merge static meshes into new files
threeforged static <path> --write                  # Merge and output *_merged.glb
threeforged static <path> --write --force          # Overwrite existing output files
threeforged static <path> --write --output-dir out # Write merged files to out/

Safe by default: analyze-only mode unless --write is passed. Never modifies original files. Output files use a _merged suffix (e.g. scene.glbscene_merged.glb).

Programmatic Usage

import { detectStaticMergeCandidates } from '@threeforged/static-optimizer';

// Analyze only
const report = await detectStaticMergeCandidates('./scene.glb');
console.log(report.groups);       // Merge candidate groups
console.log(report.metrics);      // Scene metrics + savings estimates
console.log(report.warnings);     // Actionable warnings

// Merge static meshes and write output files
const writeReport = await detectStaticMergeCandidates('./scene.glb', {
  write: true,
  force: false,
  outputDir: './optimized',
});
console.log(writeReport.fileResults); // Per-file before/after metrics

Merge Pipeline

When --write is enabled, the optimizer runs a three-stage gltf-transform pipeline on each GLB/GLTF file:

  1. dedup — Collapse identical materials into shared references
  2. flatten — Bake world transforms into vertex positions (skips animated nodes)
  3. join — Merge primitives sharing the same material into single draw calls

Animated nodes are automatically detected and excluded from merging.

What It Detects

| Rule | Description | |---|---| | Material Grouping | Groups meshes sharing identical material properties (shader type, textures, base color, metallic/roughness) | | Animation Exclusion | Warns when meshes may be animated — animated meshes cannot be statically batched | | Attribute Compatibility | Flags groups mixing indexed and non-indexed geometry | | Savings Estimation | Estimates draw call reduction from merging (severity: error >=50%, warn >=20%, info >=5%) | | Vertex Budget | Warns when merged vertex count exceeds 65,535 (16-bit index buffer limit) |

Why Static Batching Matters

Without batching:

12 wall meshes with same material = 12 draw calls

With static batching:

12 wall meshes merged = 1 draw call

Static batching is most effective for architecture, terrain, environment props, and decorations — any geometry that never moves at runtime.

Configuration

Create threeforged.config.js in your project root:

export default {
  staticOptimizer: {
    minMeshesPerGroup: 2,     // Minimum meshes to form a merge group
    maxGroups: 20,            // Max groups to report
    maxEntriesPerGroup: 8,    // Max mesh entries shown per group
    maxFiles: 500,            // Max files to scan
    maxMergedVertices: 65535, // Vertex limit warning threshold
    write: false,             // Set true to merge by default
    force: false,             // Set true to overwrite existing output
    outputDir: undefined,     // Default: same directory as input
  },
};

License

MIT