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

tiny-rpg-studio-sdk

v1.4.0

Published

SDK for creating RPG games and generating playable URLs for [Tiny RPG Studio](https://andredarcie.github.io/tiny-rpg-studio/).

Readme

tiny-rpg-studio-sdk

SDK for creating RPG games and generating playable URLs for Tiny RPG Studio.

npm install tiny-rpg-studio-sdk

Usage

import { TinyRPG } from 'tiny-rpg-studio-sdk';

const game = new TinyRPG()
  .setTitle('My RPG')
  .setAuthor('You')
  .setPlayerStart({ x: 1, y: 1, room: 0 });

game.room(0)
  .ground([
    [1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1],
  ])
  .addEnemy({ type: 'skeleton', x: 3, y: 3 })
  .addNPC({ type: 'villager-man', x: 2, y: 2, text: 'Hello!' })
  .addKey({ x: 6, y: 6 });

game.room(8)
  .addEnd({ x: 4, y: 4, message: 'You won!' });

const url = game.buildURL();
// https://andredarcie.github.io/tiny-rpg-studio/#<code>

The playable URL always has the form <base>#<code>, where <base> defaults to https://andredarcie.github.io/tiny-rpg-studio/ and <code> is the encoded share string.


API

new TinyRPG() — game builder

All methods return this for chaining, except variable(), room(), toSharePayload(), toShareCode() and buildURL().

| Method | Signature | Description | |---|---|---| | setTitle | (title: string): this | Sets the game title. Max 80 characters — throws if exceeded. | | setAuthor | (author: string): this | Sets the author name. Max 60 characters — throws if exceeded. | | setPlayerStart | ({ x, y, room }: { x: number; y: number; room: number }): this | Sets the player's starting position. x and y must be integers in [0, 7], room in [0, 8]. Throws otherwise. | | setPalette | (colors: string[]): this | Sets a custom 16-color palette. Must be exactly 16 strings matching #RRGGBB. Throws otherwise. | | hideHUD | (hide?: boolean): this | Hides the game HUD. Defaults to true. | | disableSkills | (disable?: boolean): this | Disables the in-game skill / level-up system. Defaults to true. | | disablePixelFont | (disable?: boolean): this | Renders text with the system font instead of the bitmap pixel font. Defaults to true. | | setBackgroundMusic | (videoIdOrUrl: string, volume?: number): this | Sets looping background music from a YouTube video id or URL. volume is an integer in [0, 100] (default 100). Throws on an invalid id/URL or out-of-range volume. | | setSkillOrder | (ids: string[]): this | Sets the order skills are offered in on level-up. Validates each id against the known skill list — throws on unknown ids. | | enableOnline | (config?: { spawnPoints?: Array<{ x: number; y: number; roomIndex: number }> }): this | Enables online multiplayer with optional spawn points. | | variable | (name?: string, opts?: { initial?: boolean }): VariableRef | Allocates the next boolean variable slot (var-1..var-16) and returns a handle. name is an authoring label only. Set initial: true to start it ON. Throws after MAX_VARIABLES (16) allocations. | | defineSprite | (opts: { group; key; variant?; frames }): this | Defines custom pixel art that overrides a built-in sprite or adds a new one. See Custom sprites. | | room | (index: number): RoomBuilder | Returns the RoomBuilder for room index. index must be an integer in [0, 8]. Throws otherwise. Rooms are created lazily and cached. | | toSharePayload | (): SdkSharePayload | Returns the raw data object passed to the encoder. | | toShareCode | (): string | Returns the encoded share hash string. | | buildURL | (baseUrl?: string): string | Returns the full playable URL <base>#<code>. Uses the official studio URL by default. |


Variables

The share format addresses up to 16 boolean variables (var-1 .. var-16). Switches, logic gates, variable-doors, LEDs, traps, pressure-plates, NPCs and enemies all reference these by id. Instead of typing raw var-N strings, allocate handles with game.variable():

import { TinyRPG, MAX_VARIABLES } from 'tiny-rpg-studio-sdk';

const game = new TinyRPG();
const open = game.variable('door open');         // var-1
const lit  = game.variable('lamp', { initial: true }); // var-2, starts ON

game.variable(name?, { initial? }) returns a VariableRef:

type VariableRef = {
  readonly id: string;    // encoded id, e.g. 'var-1'
  readonly index: number; // 1-based slot index (1..16)
  readonly name?: string; // optional authoring label (not encoded)
};

Every method that takes a variable accepts VariableRef | number — you may pass the handle returned by variable() or a 1-based slot index 1..16 directly. MAX_VARIABLES is exported as a constant (16); allocating a 17th variable throws.


room(i) — RoomBuilder

All methods return this for chaining. Each call validates coordinates and types immediately — errors point to the exact call that caused them. No two objects may occupy the same tile (placing a second object on an occupied tile throws).

Tiles

| Method | Signature | Description | |---|---|---| | ground | (matrix: number[][]): this | Sets the ground tile layer. Must be an 8×8 matrix of integers. Throws if dimensions are wrong. | | overlay | (matrix: (number \| null)[][]): this | Sets the overlay tile layer. Must be an 8×8 matrix of integers or null. Throws if dimensions are wrong. |

Entities

| Method | Signature | Description | |---|---|---| | addEnemy | ({ type: EnemyType; x; y; defeatVariable? }): this | Adds an enemy at (x, y). Max 9 enemies per room. defeatVariable (VariableRef \| number) is set ON when the enemy is defeated. Throws on invalid type, out-of-range coordinates, or a full room. | | addNPC | ({ type: NpcType; x; y; text?; conditionVariable?; conditionText?; rewardVariable?; conditionalRewardVariable? }): this | Adds an NPC at (x, y) with optional dialog. When conditionVariable is ON the NPC shows conditionText. rewardVariable is set ON after the player reads the NPC; conditionalRewardVariable is set ON instead when the conditional dialog is shown. Variable fields accept VariableRef \| number. |

Collectibles & equipment — unique per room

These throw if called twice for the same item type in one room.

| Method | Signature | Description | |---|---|---| | addKey | ({ x; y }): this | Places a key at (x, y). | | addDoor | ({ x; y }): this | Places a key-locked door at (x, y). | | addPotion | ({ x; y }): this | Places a life potion at (x, y). | | addXpScroll | ({ x; y }): this | Places an XP scroll at (x, y). | | addSword | ({ x; y; tier?: 'wood' \| 'bronze' \| 'iron' }): this | Places a sword at (x, y). tier defaults to 'iron'. Each tier maps to a distinct item (sword, sword-bronze, sword-wood) and counts as its own unique type. |

Equipment & objects — multiple per room

| Method | Signature | Description | |---|---|---| | addArmor | ({ x; y }): this | Places armor at (x, y). | | addBoots | ({ x; y }): this | Places boots at (x, y). | | addPushBox | ({ x; y }): this | Places a pushable box at (x, y). |

Logic & variable-driven objects — multiple per room (except where noted)

| Method | Signature | Description | |---|---|---| | addSwitch | ({ x; y; variable: VariableRef \| number; on? }): this | Lever the player toggles by stepping on it; flips variable. on sets its starting state (default false). Multiple allowed per room. | | addVariableDoor | ({ x; y; variable: VariableRef \| number }): this | Door that stays locked until variable is ON. One per room — throws on a second call. | | addLed | ({ x; y; variable: VariableRef \| number }): this | Indicator lamp that lights up while variable is ON. | | addTrap | ({ x; y; variable?: VariableRef \| number }): this | Spikes that hurt the player. Active unless the optional variable is ON. | | addPressurePlate | ({ x; y; variable: VariableRef \| number }): this | Floor plate that holds variable ON while a player or push-box rests on it. | | addLogicGate | ({ type: LogicGateType; x; y; inputA?; inputB?; output; hidden? }): this | Logic gate that writes output = gate(inputA, inputB) whenever an input changes. not uses only inputA. hidden: true hides it in-game (still active) while keeping it visible in the editor. Inputs/output accept VariableRef \| number. | | addChest | ({ x; y; contains?: ChestItemType; random? }): this | Chest revealing a fixed item (contains) or a random one (random: true). Throws if neither is supplied, or on an unknown item. |

Goal — unique per room

| Method | Signature | Description | |---|---|---| | addEnd | ({ x; y; message? }): this | Places the game-ending tile at (x, y) with an optional victory message. One per room — throws on a second call. |


Custom sprites

game.defineSprite(opts) defines custom pixel art. When group + key match a built-in sprite (e.g. group 'enemy', key 'skeleton') it overrides that sprite; otherwise it adds a brand-new one. Each frame is a matrix of palette indices (0–15) or null (transparent); supplying multiple frames animates the sprite.

game.defineSprite({
  group: 'enemy',     // 'tile' | 'npc' | 'enemy' | 'object' | 'player'
  key: 'skeleton',    // built-in key to override, or a new key
  variant: 'base',    // optional: 'base' (default art) | 'on' (activated state)
  frames: [
    // each frame is a rectangular matrix of 0..15 or null
    [/* ...8×8 rows of palette indices... */],
  ],
});

| Option | Type | Notes | |---|---|---| | group | 'tile' \| 'npc' \| 'enemy' \| 'object' \| 'player' | Required. Throws on an unknown group. | | key | string | Required, non-empty. | | variant | 'base' \| 'on' | Optional. 'base' is the default art, 'on' the activated state. | | frames | (number \| null)[][][] | Required, at least one frame. Each frame must be a non-empty rectangular matrix; every pixel is an integer in [0, 15] or null. Throws on empty frames, ragged matrices, or out-of-range values. |


Logic-gate puzzle example

A complete, runnable example: two switches feed an AND gate. The gate's output drives a status LED and unlocks a variable-door — the door opens only when both switches are ON.

import { TinyRPG } from 'tiny-rpg-studio-sdk';

const game = new TinyRPG()
  .setTitle('AND Gate Puzzle')
  .setAuthor('You')
  .setPlayerStart({ x: 1, y: 4, room: 0 });

// Allocate the wiring.
const a    = game.variable('switch A');
const b    = game.variable('switch B');
const open = game.variable('door open');

game.room(0)
  .ground([
    [1, 1, 1, 1, 1, 1, 1, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 0, 0, 0, 0, 0, 0, 1],
    [1, 1, 1, 1, 1, 1, 1, 1],
  ])
  // Two switches the player toggles.
  .addSwitch({ x: 2, y: 2, variable: a })
  .addSwitch({ x: 2, y: 5, variable: b })
  // open = a AND b, recomputed whenever a or b changes.
  .addLogicGate({ type: 'and', x: 4, y: 3, inputA: a, inputB: b, output: open, hidden: true })
  // Lamp that lights while the door is unlocked.
  .addLed({ x: 5, y: 3, variable: open })
  // Door that stays locked until `open` is ON.
  .addVariableDoor({ x: 6, y: 3, variable: open });

game.room(0).addEnd({ x: 6, y: 4, message: 'Both switches flipped — you escaped!' });

const url = game.buildURL();
// https://andredarcie.github.io/tiny-rpg-studio/#<code>
console.log(url);

Types

EnemyType

'giant-rat' | 'bandit' | 'skeleton' | 'dark-knight' |
'necromancer' | 'dragon' | 'fallen-king' | 'ancient-demon'

NpcType

// Human variants
'old-mage' | 'villager-man' | 'villager-woman' | 'child' |
'king' | 'knight' | 'thief' | 'blacksmith' |

// Elf variants
'old-mage-elf' | 'villager-man-elf' | 'villager-woman-elf' | 'child-elf' |
'king-elf' | 'knight-elf' | 'thief-elf' | 'blacksmith-elf' |

// Dwarf variants
'old-mage-dwarf' | 'villager-man-dwarf' | 'villager-woman-dwarf' | 'child-dwarf' |
'king-dwarf' | 'knight-dwarf' | 'thief-dwarf' | 'blacksmith-dwarf' |

// Fixed
'thought-bubble' | 'wooden-sign'

SwordTier

'wood' | 'bronze' | 'iron'

LogicGateType

'not' | 'and' | 'or' | 'nand' | 'nor'

ChestItemType

'key' | 'life-potion' | 'xp-scroll' |
'sword' | 'sword-bronze' | 'sword-wood' |
'armor' | 'boots'

VariableRef

type VariableRef = {
  readonly id: string;    // encoded id, e.g. 'var-1'
  readonly index: number; // 1-based slot index (1..16)
  readonly name?: string; // optional authoring label (not encoded)
};

SdkSharePayload

type SdkSharePayload = {
  title?: string;
  author?: string;
  hideHud?: boolean;
  disableSkills?: boolean;
  disablePixelFont?: boolean;
  backgroundMusicVideoId?: string;
  backgroundMusicVolume?: number;
  skillOrder?: string[];
  online?: { enabled: boolean; spawnPoints?: Array<{ x: number; y: number; roomIndex: number }> };
  start?: { x: number; y: number; roomIndex: number };
  sprites?: SdkSprite[];
  enemies?: SdkEnemy[];
  objects?: SdkObject[];
  variables?: { id: string; value: boolean; name?: string }[];
  customSprites?: SdkCustomSprite[];
  tileset?: { maps: Array<{ ground?: number[][]; overlay?: (number | null)[][] }> };
  customPalette?: string[];
};

Links