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

indiecake-engine

v0.1.0

Published

Lightweight game engine for Indie Cake platform with 2D graphics, input handling, and audio support

Readme

Indie Cake Engine v0.1.0

A lightweight 2D runtime for Indie Cake microgames, with platform integration, TypeScript types, and CDN-ready builds.

Highlights

  • Small production runtime (dist/indiecake-engine.min.js, ~9 KB gzipped)
  • Multiple output formats (ESM, CJS, IIFE)
  • Built-in systems for graphics, input, audio, assets, game state, platform events, and difficulty
  • Type definitions generated in dist/index.d.ts
  • Release-ready scripts for bundle-size checks and Subresource Integrity (SRI) hashes

Install

npm install indiecake-engine

Quick Start

ESM (recommended)

import { IndieCake } from 'indiecake-engine';

IndieCake.init({
  canvas: 'gameCanvas',
  width: 800,
  height: 600,
});

IndieCake.graphics.clear('#000');
IndieCake.graphics.drawRect(100, 100, 50, 50, { color: '#ff0000' });

if (IndieCake.input.isKeyPressed('Space')) {
  IndieCake.platform.setScore(10);
}

CommonJS

const { IndieCake } = require('indiecake-engine');
IndieCake.init({ canvas: 'gameCanvas' });

Browser via jsDelivr

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/indiecake-engine.min.js"></script>
<script>
  window.IndieCake.init({ canvas: 'gameCanvas' });
</script>

CDN URLs

  • Latest: https://cdn.jsdelivr.net/npm/indiecake-engine@latest/dist/indiecake-engine.min.js
  • Pinned: https://cdn.jsdelivr.net/npm/[email protected]/dist/indiecake-engine.min.js
  • Fallback: https://unpkg.com/[email protected]/dist/indiecake-engine.min.js

Build Scripts

  • npm run build: production build (clean -> rollup -> size checks)
  • npm run build:rollup: non-production rollup build
  • npm run build:rollup:prod: production rollup build
  • npm run dev: watch mode
  • npm run check:sizes: gzip size validation
  • npm run generate:sri: generate SRI hashes and write dist/sri.json

Build Outputs

  • dist/indiecake-engine.min.js: IIFE, minified (primary CDN artifact)
  • dist/indiecake-engine.iife.js: IIFE, non-minified
  • dist/indiecake-engine.esm.js: ESM, non-minified
  • dist/indiecake-engine.esm.min.js: ESM, minified
  • dist/indiecake-engine.cjs.js: CommonJS, non-minified
  • dist/indiecake-engine.cjs.min.js: CommonJS, minified
  • dist/index.d.ts: Type declarations
  • dist/*.map: source maps

Using SRI Hashes

Generate hashes:

npm run generate:sri

Then use the generated value in script tags:

<script
  src="https://cdn.jsdelivr.net/npm/[email protected]/dist/indiecake-engine.min.js"
  integrity="sha384-..."
  crossorigin="anonymous"
></script>

Monorepo Notes

  • In this repository, server build copies dist/indiecake-engine.esm.js to apps/server/public/uploads.
  • Root turbo build now enforces indiecake-engine#build before @indiecake/server#build.
  • The server copy script also has a fallback that builds the engine if the artifact is missing.

Engine Systems

Graphics

  • Canvas rendering
  • Rect/circle/text/image primitives
  • Basic transforms

Input

  • Keyboard/mouse/touch support
  • Press/state checks and event hooks

Audio

  • Sound/music playback through Web Audio API

Assets

  • Async loading and retrieval for image/audio/json/text

Platform

  • Completion events
  • Score integration
  • Platform-friendly helpers

Difficulty

  • Difficulty level setters/getters
  • Scaled game behavior helpers

API Reference

Core Engine

IndieCake.init(config);            // Initialize all systems
IndieCake.destroy();               // Cleanup all systems
IndieCake.isInitialized();         // Engine initialized state

IndieCake.complete(success);       // One-shot game completion
IndieCake.win();                   // Alias for complete(true)
IndieCake.lose();                  // Alias for complete(false)

IndieCake.random(min, max);        // Utility random number
IndieCake.clamp(value, min, max);  // Utility clamp
IndieCake.lerp(a, b, t);           // Utility interpolation
IndieCake.distance(x1, y1, x2, y2);

Graphics (IndieCake.graphics)

graphics.clear(color?);                                // Clear frame or fill background color
graphics.save();                                       // Save canvas state (styles/transforms)
graphics.restore();                                    // Restore last saved canvas state

graphics.drawRect(x, y, width, height, options?);      // Draw rectangle
graphics.drawCircle(x, y, radius, options?);           // Draw circle
graphics.drawLine(x1, y1, x2, y2, options?);           // Draw line segment
graphics.drawText(text, x, y, options?);               // Draw text label
graphics.drawImage(image, x, y, width?, height?, options?); // Draw sprite/image

graphics.resize(width, height);                        // Resize render surface
graphics.getCanvas();                                  // Get underlying canvas element
graphics.getContext();                                 // Get 2D context for custom drawing
graphics.getWidth();                                   // Current logical canvas width
graphics.getHeight();                                  // Current logical canvas height

Input (IndieCake.input)

input.isKeyPressed(key);                              // True while key is held
input.isKeyDown(key);                                 // Alias of isKeyPressed

input.isMousePressed(button?);                        // True while mouse button is held
input.getMousePosition();                             // Current pointer position { x, y }

input.getTouches();                                   // Active touch points [{ x, y, id }]
input.isTouching();                                   // Any active touches present

input.addEventListener((event) => { ... });           // Subscribe to keyboard/mouse/touch events
input.removeEventListener(callback);                  // Unsubscribe input listener

Assets (IndieCake.assets)

await assets.loadAsset(id, url, type);                // Load one asset (image|audio|json|text)
await assets.loadAssets(assetList);                   // Load multiple assets in parallel
await assets.loadAssetsWithProgress(assetList, onProgress); // Batch load with progress callback

assets.get(id);                                       // Get raw cached asset by id
assets.getImage(id);                                  // Get image asset as HTMLImageElement
assets.getAudio(id);                                  // Get audio asset as HTMLAudioElement
assets.getJSON(id);                                   // Get parsed JSON asset
assets.getText(id);                                   // Get text asset contents

assets.unloadAsset(id);                               // Remove one cached asset
assets.isLoaded(id);                                  // Check if asset exists and is ready

// Platform-aware helpers
await assets.loadImage(filenameOrAlias);              // Load uploaded asset by alias/filename
await assets.loadImageByHash(hash);                   // Load uploaded asset by content hash
await assets.preloadPlatformAssets();                 // Warm cache with platform registry assets
assets.getByHash(hash);                               // Read cached asset by hash

Audio (IndieCake.audio)

await audio.loadAudio(id, url);                       // Preload audio asset
audio.unloadAudio(id);                                // Remove audio from cache
audio.isLoaded(id);                                   // Check audio readiness

audio.play(id, { volume, loop, delay });              // Play sound with options
audio.pause(id);                                      // Pause one track
audio.stop(id);                                       // Stop and reset one track
audio.stopAll();                                      // Stop all currently playing audio

audio.setMasterVolume(volume);                        // Set global output volume (0..1)
audio.getMasterVolume();                              // Read current global volume
audio.setMuted(boolean);                              // Mute/unmute all audio
audio.isMuted();                                      // Read mute state

Game State (IndieCake.game)

game.start();                                         // Enter running state
game.stop();                                          // Enter stopped state
game.pause();                                         // Pause updates
game.resume();                                        // Resume from paused state
game.complete();                                      // Mark game as completed

game.isRunning();                                     // True when running
game.isPaused();                                      // True when paused
game.isStopped();                                     // True when stopped
game.isCompleted();                                   // True when completed
game.getState();                                      // Current state string

game.createScene(id);                                 // Create scene container
game.setActiveScene(id);                              // Switch active scene
game.getScene(id);                                    // Get scene by id
game.removeScene(id);                                 // Remove scene and objects

game.createObject(template?);                         // Create game object
game.getObject(id);                                   // Get object by id
game.removeObject(id);                                // Remove object by id
game.addObjectToScene(objectId, sceneId);             // Move object into scene

game.checkCollision(objA, objB);                      // AABB collision test
game.getObjectsAt(x, y);                              // Objects under point
game.getAllObjects();                                 // All objects across scenes
game.getActiveObjects();                              // Objects with active=true
game.getVisibleObjects();                             // Objects with visible=true

Platform (IndieCake.platform)

platform.complete({ success, score?, timeElapsed?, metadata? }); // Send completion payload to host
platform.isGameCompleted();                            // Prevent duplicate completion submissions

platform.setScore(score);                              // Set current score
platform.addScore(points);                             // Increment score
platform.getScore();                                   // Read current score
platform.getElapsedTime();                             // Seconds since platform init/reset
platform.resetGameTime();                              // Reset elapsed timer for new round

platform.setCallbacks({ onGameComplete, onScoreUpdate }); // Register host/game callbacks
platform.getPlatformInfo();                            // UA/device capability info

platform.saveData(key, value);                         // Persist JSON in localStorage
platform.loadData(key);                                // Read JSON from localStorage
platform.removeData(key);                              // Delete persisted key

Difficulty (IndieCake.difficulty)

difficulty.setLevel(level);                           // Set level (clamped to 1..5)
difficulty.getLevel();                                // Read current level
difficulty.getSettings(level?);                       // Full settings for specific/current level
difficulty.getCurrentSettings();                      // Full settings for active level

difficulty.getSpeedMultiplier();                      // Numeric speed scaling factor
difficulty.getTimeMultiplier();                       // Numeric time scaling factor
difficulty.getSpeedScale(baseSpeed);                  // Scale a speed value by difficulty
difficulty.getTimeScale(baseTime);                    // Scale a time value by difficulty

difficulty.onLevelChange(callback);                   // Subscribe to level changes
difficulty.removeCallback(callback);                  // Unsubscribe callback

difficulty.isEasy();                                  // Level 1-2
difficulty.isMedium();                                // Level 3
difficulty.isHard();                                  // Level 4
difficulty.isExpert();                                // Level 5
difficulty.isCasual();                                // Level 1
difficulty.isStandard();                              // Level 2
difficulty.isChallenging();                           // Level 3
difficulty.isLegendary();                             // Level 5

Time (IndieCake.time)

time.update(deltaMs?);                                // Update timing from custom delta or performance.now()

time.deltaTime;                                       // Seconds since last frame
time.totalTime;                                       // Total seconds since init
time.currentFPS;                                      // Estimated FPS (smoothed/updated internally)
time.now;                                             // Current performance.now() value

time.getDelta();                                      // Alias for deltaTime
time.getElapsed();                                    // Alias for totalTime
time.getFPS();                                        // Alias for currentFPS

Common Usage Patterns

1) Basic game loop with engine time

function tick() {
  IndieCake.time.update();
  const dt = IndieCake.time.deltaTime;

  // update your game state using dt
  // render via IndieCake.graphics

  requestAnimationFrame(tick);
}
tick();

2) Complete a game safely once

// IndieCake.complete() is one-shot per session
if (playerWon) {
  IndieCake.win();
} else {
  IndieCake.lose();
}

3) Load assets with progress

await IndieCake.assets.loadAssetsWithProgress(
  [
    { id: 'player', url: '/sprites/player.png', type: 'image' },
    { id: 'music', url: '/audio/theme.mp3', type: 'audio' },
  ],
  (p) => console.log(`Loading ${p.loaded}/${p.total} (${p.percentage.toFixed(0)}%)`)
);

4) Tune gameplay by difficulty level

const level = IndieCake.difficulty.getLevel();

// Option A: Direct multiplier-based scaling
const enemySpeed = 140 * IndieCake.difficulty.getSpeedMultiplier();
const timeLimit = 20 * IndieCake.difficulty.getTimeMultiplier();

// Option B: Use built-in scaling helpers
const spawnIntervalMs = IndieCake.difficulty.getTimeScale(1200);
const projectileSpeed = IndieCake.difficulty.getSpeedScale(220);

// Optional named checks for branching behavior
if (IndieCake.difficulty.isLegendary()) {
  // Add advanced patterns, extra enemies, etc.
}

console.log('Difficulty level:', level);

Difficulty cheat sheet

| Level | Label | Good for | Helpful checks | | --- | --- | --- | --- | | 1 | Casual | New players, generous timing, slower pacing | isCasual(), isEasy() | | 2 | Standard | Default balance for most games | isStandard(), isEasy() | | 3 | Challenging | Tighten timing and speed a bit | isChallenging(), isMedium() | | 4 | Expert | Faster reactions, less forgiveness | isHard() | | 5 | Legendary | Fastest pace and shortest time windows | isLegendary(), isExpert() |

For scaling, a good default pattern is:

  • Use getTimeScale(baseTime) when you want harder modes to reduce or stretch timing in a consistent way.
  • Use getSpeedScale(baseSpeed) when you want movement or enemy speed to respond to the selected level.
  • Use getCurrentSettings() when you need the full label, description, color, and multiplier set.

Configuration Example

IndieCake.init({
  canvas: 'gameCanvas',
  width: 800,
  height: 600,
  backgroundColor: '#000000',
  fps: 60,
  enableAudio: true,
  enableInput: true,
  enableGraphics: true,
  enablePlatformIntegration: true,
  debug: false,
});

Release Flow (Repository)

  1. Bump version in package.json
  2. Run npm run build
  3. Create GitHub release tag (v0.1.0 style)
  4. GitHub Actions publishes package to npm
  5. jsDelivr serves the new version automatically

License

MIT. See LICENSE.