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

@zakkster/lite-vram

v1.0.6

Published

Enterprise-grade VRAM management for HTML5 games. Features hardware tier detection, priority-based hysteresis eviction, and safe scene streaming.

Readme

@zakkster/lite-vram

npm version npm bundle size npm downloads npm total downloads TypeScript Safari Tested License: MIT

Production VRAM management for HTML5 game engines. Device-aware budgets, category-priority eviction, Safari crash prevention, and the data to prove it works on every device.

The VRAM system that PixiJS, Phaser, Construct, and Cocos don't have.

→ Try the Live Diagnostic Dashboard

Why lite-vram?

| Feature | lite-vram | PixiJS | Phaser | Construct | Cocos | |---|---|---|---|---|---| | Device tier detection (GPU + RAM + cores) | Yes (7 rules) | No | No | No | No | | Per-tier VRAM budgets (32–256 MB) | Yes | No | No | No | No | | Category-priority eviction | Yes (TEMP→FX→BG→CHAR→UI) | No | No | No | No | | Safari panic mode (95%+) | Yes | No | No | No | No | | Tier-aware texture resolution | Yes (@0.5x/@0.75x/1.0x) | No | No | No | No | | Decode throttle detection | Yes (3× baseline) | No | No | No | No | | Device crash matrices (30+) | Yes (JSON) | No | No | No | No | | Live diagnostic dashboard | Yes (HTML) | No | No | No | No | | Scene streaming pipeline | Yes (safe transitions) | Manual | Manual | N/A | Manual | | TypeScript declarations | Yes (9 .d.ts) | Partial | Partial | No | Partial | | Zero dependencies | Yes | No | No | N/A | No |

Installation

The runtime cache is a free npm package:

npm install @zakkster/lite-vram

The Playbook (this repository) provides the VRAM management layer, presets, matrices, guides, and examples on top of it.

Quick Start

import {
    createCacheAuto, CategoryRegistry, VramManager,
    AssetResolver, loadScene, transitionScenes, VramHUD
} @zakkster/lite-vram.js';

// 1. Boot — auto-detects device, picks correct budget
const { cache, tier } = createCacheAuto();
const registry = new CategoryRegistry();
const resolver = new AssetResolver({ basePath: 'assets' });

// 2. VramManager — prevents Safari crashes
const manager = new VramManager(cache, {
    registry,
    checkIntervalMs: tier.tier === 1 ? 500 : 2000,
    onEvict: (id, cat) => console.log(`Evicted: ${id} [${cat}]`),
    onPanic: (u) => console.error(`PANIC at ${(u*100).toFixed(0)}%`)
});
manager.start();

// 3. Dev HUD (remove in production)
if (import.meta.env?.DEV) {
    new VramHUD(cache, { manager, position: 'top-right' });
}

// 4. Load a scene
const forest = {
    name: 'forest',
    assets: resolver.resolveSceneAssets([
        { id: 'bg-sky',    category: 'bg' },
        { id: 'hero',      category: 'char' },
        { id: 'hud-hp',    category: 'ui' },   // immune to eviction
    ], tier.tier)
};
await loadScene(cache, forest, registry);

// 5. Safe transition — always unloads before loading
const cave = {
    name: 'cave',
    assets: resolver.resolveSceneAssets([
        { id: 'cave-bg',   category: 'bg' },
        { id: 'hero',      category: 'char' },
        { id: 'hud-hp',    category: 'ui' },
    ], tier.tier)
};
await transitionScenes(cache, forest, cave, registry);

console.log(`${tier.tierName} | ${cache.stats().maxMemoryMB}MB | GPU: ${tier.signals.gpu}`);

Full Module Reference

deviceTier.js — Hardware Classifier

7-rule detection chain that classifies every device into LOW / MID / HIGH:

| # | Condition | → Tier | Reason | |---|---|---|---| | 1 | iOS && RAM ≤ 3GB | LOW | Safari process limits leave ≤100MB for textures | | 2 | Android && RAM ≤ 2GB (Chrome deviceMemory) | LOW | Budget Android | | 3 | Mobile && gpuIsLow | LOW | Weak mobile GPU (Mali T6/T7, Adreno 3xx–5xx, PowerVR) | | 4 | Desktop && gpuIsLow | MID | Old integrated GPU — desktop is still permissive | | 5 | RAM ≤ 4GB | MID | Memory-constrained | | 6 | Desktop && cores ≤ 2 && RAM ≤ 8GB | MID | Weak desktop | | 7 | Everything else | HIGH | Sufficient hardware |

const { tier, tierName, signals } = detectDeviceTier();
// signals: { isIOS, isIPad, isMobile, memory, memoryReal, cores, gpu, gpuIsLow, reason }

presets.js — Tier-Aware Cache Factory

| Tier | Budget | Target Devices | |---|---|---| | SAFE | 32 MB | iPhone 6–7, Safari under heavy pressure | | LOW | 48 MB | iPhone SE, iPad 6th gen, 2GB Android | | MID | 96 MB | iPhone 12, mid-range Android, 4GB laptops | | HIGH | 192 MB | Desktop, gaming laptops, iPad Pro | | ULTRA | 256 MB | High-end desktop, WebGPU, cinematic |

const cache = createSpriteCacheForTier(DeviceTier.LOW);
const { cache, tier } = createCacheAuto();       // auto-detect
const defaults = getTierDefaults('ultra');        // inspect without creating

categoryRegistry.js — Eviction Priority

Eviction order (first to die → last to die):
  TEMP → FX → BG → CHAR → UI (immune)

| Method | Description | |---|---| | register(id, category) | Tags an asset. Invalid categories coerce to TEMP with warning. | | registerBatch(assets) | Bulk-register [{ id, category }] arrays. | | getIdsByPriority() | Returns all IDs sorted TEMP-first. UI excluded. | | isEvictable(id) | false for UI, true for everything else. | | getCategory(id) | Returns the category, or undefined. | | size | Number of registered assets (getter). |

vramManager.js — Pressure Monitor + Eviction Engine

| Option | Default | Description | |---|---|---| | registry | required | CategoryRegistry instance. Throws if omitted. | | checkIntervalMs | 2000 | Polling frequency (ms). LOW devices should use 500. | | highWatermark | 0.90 | Usage ratio that triggers category-based eviction. | | lowWatermark | 0.75 | Usage ratio below which eviction stops (hysteresis). | | panicWatermark | 0.95 | Usage ratio that triggers panic mode (mass eviction). | | onEvict | null | (id, category?) => void — analytics callback. | | onPressure | null | (usage) => void — entering pressure state. | | onRelief | null | (usage) => void — returning below low watermark. | | onPanic | null | (usage) => void — emergency eviction engaged. |

| Method | Description | |---|---| | start() | Begin periodic checks. Idempotent. | | stop() | Stop periodic checks. | | pause() / resume() | Disable/enable eviction (e.g., during scene transitions). | | check() | Manual immediate pressure check. | | stats() | Diagnostic snapshot with pressured, paused, usageRatio, registrySize. | | destroy() | Stops timer, nullifies references. Idempotent. |

assetResolver.js — Tier-Aware URL Construction

const resolver = new AssetResolver({
    basePath: 'assets',      // default
    extension: '.png',       // default
    suffixes: { 1: '@0.5x', 2: '@0.75x', 3: '' }  // default (LOW/MID/HIGH)
});

resolver.resolve('hero', DeviceTier.LOW);   // 'assets/[email protected]'
resolver.resolve('hero', DeviceTier.HIGH);  // 'assets/hero.png'

// Bulk resolve with categories preserved for loadScene()
const assets = resolver.resolveSceneAssets([
    { id: 'bg', category: 'bg' },
    { id: 'hero', category: 'char' }
], tier.tier);

sceneStreaming.js — Safe Scene Pipeline

| Function | Description | |---|---| | loadScene(cache, scene, registry?) | Parallel load. Registers categories before decode. | | unloadScene(cache, scene, registry?) | Immediate dispose of all scene assets. | | transitionScenes(cache, from, to, registry?) | Unloads FIRST, then loads. Safari-safe. | | preloadScene(cache, scene, registry?) | Loads without unloading current. Budget check first! | | cleanupPartialLoad(cache, scene, result, registry?) | Rollback: disposes only the assets that succeeded. |

vramHud.js — Live Telemetry Overlay

| Option | Values | Description | |---|---|---| | position | 'top-left' / 'top-right' / 'bottom-left' / 'bottom-right' | Corner placement | | mode | 'raf' / 'interval' | RAF for dev (60Hz), interval for background-tab safety | | display | 'full' / 'compact' | Multi-line or single-line | | intervalMs | 500 (default) | Update frequency in interval mode | | manager | VramManager instance | Enables pressure/eviction fields |

safariStressTest.js — Crash Threshold Finder

const result = await runSafariStressTest('https://cdn.example.com/texture.png', {
    iterations: 200,
    ceilingMB: 512,
    warmUpCount: 5,
    throttleMultiplier: 3
});
// result: { totalLoaded, peakMemoryMB, avgDurationMs, baselineDurationMs, stopReason }

const sweep = await runResolutionSweep('https://cdn.example.com/texture.png');
// Tests 512×256, 1024×512, 2048×1024 — builds VRAM cost matrix

Recipes

const freeMB = parseFloat(cache.stats().maxMemoryMB) - parseFloat(cache.stats().memoryMB);
if (freeMB > 10) {
    // Budget allows overlap — preload next scene
    for (const a of nextScene.assets) {
        if (a.category) registry.register(a.id, a.category);
    }
    await cache.loadAll(nextScene.assets);
} else {
    // Too tight — safe sequential transition
    await transitionScenes(cache, currentScene, nextScene, registry);
}
manager.pause();
// Both scenes in VRAM temporarily
await loadScene(cache, cutscene, registry);
playCutscene();
// After cutscene
unloadScene(cache, cutscene, registry);
manager.resume();
let hud = null;
window.addEventListener('keydown', e => {
    if (e.key === 'F2') {
        e.preventDefault();
        if (hud) { hud.destroy(); hud = null; }
        else { hud = new VramHUD(cache, { manager, position: 'top-right' }); }
    }
});
const result = await loadScene(cache, bossScene, registry);
if (!result.ok) {
    console.warn(`${result.failed} assets failed — rolling back`);
    cleanupPartialLoad(cache, bossScene, result, registry);
    // Show fallback UI
}
const resolver = new AssetResolver({
    basePath: 'https://cdn.example.com/game',
    extension: '.webp',
    suffixes: { 1: '_lo', 2: '_md', 3: '' }
});
// LOW: https://cdn.example.com/game/hero_lo.webp
// HIGH: https://cdn.example.com/game/hero.webp
const result = await runSafariStressTest(textureUrl, {
    iterations: 100,
    ceilingMB: 48,
    throttleMultiplier: 3
});
if (result.stopReason !== 'complete') {
    process.exit(1); // Fail the build
}

What's in the Box

├── src/              9 JS modules + 9 .d.ts + diagnostic HTML
├── vram-diagnostics-dashboard/   Live VRAM graph, decode timing, exportable reports
│ 
└── vram.test.js       48 vitest tests covering all modules

🆓 Help Us Build Better Presets — Run the Dashboard!

The Diagnostic Dashboard is completely free. You don't need to install anything or run a local server.

👉 Run the Live VRAM Diagnostic Tool (Netlify)

It takes 60 seconds to run a test:

  1. Open the link above on your target device (especially older phones or iPads).
  2. Set the Tier Dropdown to the preset you want to test.
  3. Click ▶ Start and watch the VRAM load.
  4. If the Safari tab crashes (reloads), you know the exact megabyte limit for that tier.
  5. Click Export Report.

Contributing Data

If you test lite-vram on an older device (like an iPhone 8 or a budget Android), please send us the JSON report! Your data helps us refine the presets.json watermarks for the whole community.

When submitting a report, please fill out the environmental hardware fields in the exported JSON:

{
  "deviceModel": "iPhone 11 Pro",
  "osVersion": "iOS 17.2",
  "browserVersion": "Safari 17",
  "batteryStart": "82%",
  "deviceTemp": "cool | warm | hot",
  "network": "WiFi 5GHz | WiFi 2.4GHz | LTE | 5G",
  "notes": "Tab crashed cleanly at 192MB, no severe system stutter before the crash."
}

Your anonymous device report is the most valuable contribution you can make. Every JSON adds a real data point to our device matrices. Every data point makes the presets safer. Every safer preset prevents a Safari crash for some studio shipping a game to millions of players.

We desperately need reports from:

  • iPhone 7, 8, SE 2nd gen — the LOW / MID boundary
  • iPhone 12, 13, 14, 15 — the MID / HIGH boundary
  • iPad 6th, 7th, 9th gen — Safari memory limits differ from iPhone
  • 2GB / 4GB Android — Chrome's deviceMemory edge cases
  • MacBooks with Intel HD 4000–620 — the desktop gpuIsLow boundary
  • Any device that has ever crashed a web game — we need its profile

Every report you send saves a studio from shipping a crash.

Read the full Dashboard README for report format, field mapping, and how we use the data.


Testing

npx vitest run vram.test.js

48 tests across 10 describe blocks: CategoryRegistry (registration, eviction order, size, batch, clear, isEvictable, getIdsByPriority), DeviceTier (constants, detection, signal fields), AssetResolver (all 3 tiers, custom suffixes, scene assets, standalone function, edge cases), Presets (all 5 tiers, overrides, auto-detect, fallback), VramManager (mandatory registry throw, watermarks, pause/resume, stats, start/stop, destroy), SceneStreaming (load, unload, transition, partial cleanup with mock cache).


Changelog

v1.0.0

Architecture: 7-rule device detection Added Android ≤2GB rule (Chrome deviceMemory), scoped gpuIsLow to mobile-only (desktop gets MID not LOW), expanded Intel GPU regex to catch 3-digit Skylake/Kaby Lake (HD 515, 520, 530, 610, 615, 620; excludes 540+, 630+).

Safety: VramManager requires CategoryRegistry Constructor throws immediately if no registry is provided. Previously defaulted to null and crashed silently when VRAM pressure hit 90% — the exact moment the system was supposed to save the device.

Safety: ES2015 catch binding } catch {} catch (e) { in GPU probe. Optional catch binding is ES2019 — fatal SyntaxError on iOS 12 / early iOS 13, killing the game on exactly the oldest devices that need VRAM protection the most.

Dashboard: Decode timing panel Baseline, last decode, multiplier, peak, and color-coded throttle bar. The only real-time Safari VRAM pressure signal available to web developers.

Dashboard: Per-tier watermarks from presets.json SAFE 0.75/0.55/0.88 through ULTRA 0.92/0.80/0.96. Graph draws correct watermark lines per tier.

Dashboard: Crash-proof RAF loop try/catch with requestAnimationFrame after the catch block. Visibility API pauses on tab switch. Session timer resets per boot. Tier selector auto-syncs to detected tier. Flush resets all metrics.

Examples: Production-hardened Multi-scene streaming: 300ms throttled stats, visibility handler, transition race prevention, pattern double-click guard, resize listener. Safari Safe Mode: 100 iterations (was 60 — now hits budget ceiling and forces eviction), shared canvas (zero GC), early stop on throttle/95%, tracked peak VRAM, baseline guard. Tier-aware loading: anchored suffix regex, --text-dim variable, !! boolean coercion. VramHUD demo: cached canvas resize, dynamic tile limit, zero-GC stat polling (250ms), correct category rotation, VramManager with visible watermarks.


License

MIT — Built by @zakkster at NiceWorks Studio


VRAM management isn't a feature. It's the difference between your game running and your game crashing. On Safari, there is no middle ground.