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

@megaofmegalodon/stackjs

v1.0.0

Published

A lightweight TypeScript/JavaScript library that bridges C-style structs into modern JS runtimes.

Readme

StackJS

A lightweight TypeScript/JavaScript library that bridges C-style structs into modern JS runtimes.

Why StackJS?

1. The Problem: Short-Lived Objects in Hot Loops

In high-frequency JS environments, you constantly need temporary objects for calculations:

function updateParticle(p, d) {
  // Creating short-lived vector objects every single frame
  const velocity = { x: p.vx + d.x ** d.mlt, y: p.vy + d.y ** d.mlt };
  const step = scaleVector(velocity, 0.016);
  p.x += step.x;
}

Creating thousands of small, short-lived objects per second forces V8's garbage collector into overdrive and triggers periodic Garbage Collection (GC). This causes stutters, frame drops, and latency spikes.

2. The Flaw in Current Solutions

Engineers typically try two workarounds to avoid GC pressure, but both introduce major drawbacks:

  • Object Pooling: Preserving a fixed pool of JavaScript objects eliminates allocations, but it creates reference management hell.
    • If a developer forgets to return an object to the pool, memory leaks.
    • If an object is silently used twice, data gets corrupted across systems.
  • Pre-Allocated TypedArrays: Using raw binary buffers avoids the GC, but manual index management quickly degenerates into unreadable, bug-prone "magic number" math.

3. What StackJS Solves

StackJS gives you the pure performance of pre-allocated binary memory with clean ergonomics that mimic C-structs:

  • CPU Cache Locality: All data is stored as raw values inside a single contiguous ArrayBuffer, drastically improving cache efficiency compared to normal JS objects.
  • Zero Allocation: Allocating and deallocating structs cause zero GC overhead.
  • Readable Struct Schemas: Define named fields and primitive types, eliminating "magic number" array math while preserving strict byte-alignment padding.
  • Globally Usable: StackJS isn't locked to a single global memory heap. This allows you to instantiate as many StackJS instances as your program needs (e.g. one for playerBuffer, buildingBuffer, projectileBuffer, shortLivedObjects, etc).

What StackJS is not

StackJS is not intended to replace every single JS object.

Normal JS objects still remain the right choice for complex or dynamic data. StackJS is designed to replace hard to manage buffers and short-lived objects for programs where avoiding GC for consistent code runtime is the goal.

Installation

npm install @megaofmegalodon/stackjs

Quick Start

import { StackJS } from "@megaofmegalodon/stackjs";

// 1. Pre-allocate a 4 MB contiguous memory stack
const stack = StackJS.fromMB(4);

// 2. Define a C-style struct layout
const Particle = StackJS.register({
    x: "f32",
    y: "f32",
    vx: "f32",
    vy: "f32",
    active: "u8",
});

function updateParticleScope() {
  const ptr = stack.allocF(Particle);

  stack.set(ptr, Particle.X, 10.0);
  stack.set(ptr, Particle.Y, 20.0);
  stack.set(ptr, Particle.VX, 1.5);
  stack.set(ptr, Particle.VY, -0.5);

  const currentX = stack.get(ptr, Particle.X);
  const vx = stack.get(ptr, Particle.VX);
  stack.set(ptr, Particle.X, currentX + vx);

  stack.pop();
}

// 3. Run hot-loop: zero short-lived objects allocated
for (let i = 0; i < 10000; i++) {
  updateParticleScope();
}

API Reference

Struct Schema Registry

  • StackJS.register<S extends Schema>(schema: S, defaultValues?: StructValues<S>): CompiledStruct<S> - Creates a reusable struct schema.

StackJS Constructors

  • StackJS.fromKB(kilobytes: number): StackJS
  • StackJS.fromMB(megabytes: number): StackJS
  • StackJS.fromGB(gigabytes: number): StackJS
  • new StackJS(sizeInBytes: number, endianness?: "LE" | "BE")

Scope & Allocation

  • allocFrame(): void - Pushes a new activation record onto the scope stack.
  • alloc(frame: StructFrame): StackPointer - Allocates memory for a struct within the active frame.
  • popFrame(): void - Frees the top activation frame.
  • allocF(frame: StructFrame): void - A shorthand for allocFrame() and alloc() that pushes a new activation record and allocates memory for a struct in the new frame.
  • pop(): void - A shorthand for popFrame(): void.

Data Access

  • set(ptr: StackPointer, field: FieldData, val: number): void - Writes a scalar numeric value into stack buffer memory.
  • get(ptr: StackPointer, field: FieldData): number - Reads a scalar numeric value from stack buffer memory.
  • ext<T>(ptr, frame, TypedArrayConstructor): T - Returns a TypedArray view over the struct.

Use Case Examples:

Buffer Replacement

import { StackJS } from "@megaofmegalodon/stackjs";

const playerStruct = StackJS.register({
    x: "f32",
    y: "f32",
    health: "f32"
}, {
    x: 0.0,
    y: 0.0,
    health: 100.0 
});

// create a 1000 playerStructBuffer that benefits from CPU cache locality
const playerBuffer = new StackJS(playerStruct.byteSize * 1000);
playerBuffer.allocFrame();
for (let i = 0; i < 1000; i++) playerBuffer.alloc(playerStruct);

function updatePlayers(dt) {
    const size = playerBuffer.size;

    for (let i = 0; i < 1000; i++) {
        const ptr = playerStruct.byteSize * i;
        const oldX = playerBuffer.get(ptr, playerStruct.X);
        playerBuffer.set(ptr, playerStruct.X, oldX + dt);
    }
}

Memory Management

import { StackJS } from "@megaofmegalodon/stackjs";

// Creating memory budgets for different systems
const memorySpecs = {
    particles: StackJS.fromMB(4),    // 4MB max for particles
    projectiles: StackJS.fromMB(2),  // 2MB max for bullets
    scratchpad: StackJS.fromKB(256), // 256KB for math vectors
};

License

This project is licensed under MIT.