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

@reldens/tileset-to-tilemap

v0.5.0

Published

Reldens - Tileset to Tile Map

Downloads

278

Readme

Reldens - GitHub - Release

Reldens - Tileset to Tile Map

A Node.js library that takes game tileset PNG images, detects individual game objects via pixel analysis, sends each cluster to AI providers for naming and layer assignment, and generates Tiled-compatible JSON files for use with the Reldens game platform.

Need some specific feature?

Request a feature here: https://www.reldens.com/features-request


Features

  • Pixel-Level Cluster Detection: Analyzes tileset PNGs tile by tile using connected component labeling to group related tiles into clusters
  • AI-Powered Naming: Sends each detected cluster to Claude, Gemini, or Ollama for automatic naming and layer assignment
  • Multi-Provider Fallback: Tries AI providers sequentially (Ollama → Claude → Gemini), using the first valid result
  • Layer Assignment: AI assigns each element's tiles to the correct Tiled layer types (below-player, collisions, over-player, collisions-over-player)
  • Tiled JSON Output: Generates per-element Tiled-compatible JSON maps and a composite map with all elements
  • Session Management: Saves and loads analysis sessions, supports renaming and incremental saves
  • Tileset Merging: Combines multiple source tilesets into a single merged tileset with remapped elements
  • Annotated Preview: Generates annotated PNG with colored overlays per element for visual review
  • Express Integration: TilesetAnalyzerServer mounts all API routes onto any Express app with optional auth middleware
  • Zero env-var coupling: All configuration passed via constructor options with sensible defaults

Documentation

https://www.reldens.com/documentation/tileset-to-tilemap/

Installation

npm install @reldens/tileset-to-tilemap

Quick Start

Embed in an Express app

const express = require('express');
const { Requirements, TilesetAnalyzerServer } = require('@reldens/tileset-to-tilemap');

async function start() {
    let requirements = new Requirements({
        ollamaHost: 'http://localhost:11434',
        anthropicApiKey: process.env.ANTHROPIC_API_KEY,
        geminiApiKey: process.env.GEMINI_API_KEY
    });
    let aiProviders = await requirements.resolveAiProviders();

    let app = express();
    let rootDir = '/path/to/generated-tile-map-elements';

    // Serve uploaded input images and generated output files
    app.use('/tileset-image', express.static(rootDir + '/input'));
    app.use('/output', express.static(rootDir + '/output'));

    let server = new TilesetAnalyzerServer(rootDir, {
        publicDir: '/path/to/public',
        aiProviders,
        showAiControls: true,
        claudeModel: 'claude-sonnet-4-6',
        ollamaHost: 'http://localhost:11434'
    });

    server.registerRoutes(app);
    app.listen(3000);
}

start();

With auth middleware (e.g. admin integration)

server.registerRoutes(app, isAuthenticatedMiddleware);

All routes automatically receive the middleware. Pass skipIndex: true in options to skip the GET / page route when embedding inside an existing app.

Detect clusters and generate files programmatically

const { AiAnalyzer, TilesetFilesBuilder, Helpers } = require('@reldens/tileset-to-tilemap');
const sharp = require('sharp');

let imageBuffer = await sharp('/path/to/tileset.png').png().toBuffer();
let meta = await sharp('/path/to/tileset.png').metadata();
let tileWidth = 32, tileHeight = 32, margin = 0, spacing = 0;

let analyzer = new AiAnalyzer({ ollamaHost: 'http://localhost:11434', skipAi: false });
let result = await analyzer.analyzeImage(
    imageBuffer,
    Helpers.calcTileColumns(meta.width, margin, spacing, tileWidth),
    Helpers.calcTileRows(meta.height, margin, spacing, tileHeight),
    tileWidth, tileHeight, margin, spacing,
    providers, '#ffffff', null, null, null
);
// result = { elements: [{ name, type, approved, layers }], filteredTiles: [[row, col], ...] }

let builder = new TilesetFilesBuilder();
let files = await builder.build(rootDir, sessionId, outputDir, tilesets, tilesets, 'my-map', 'My Map');
// files = [{ name, downloadUrl, type: 'output'|'input' }]

Configuration Options

All options are passed to constructors. The package reads no process.env directly. Claude and Gemini API keys are picked up from ANTHROPIC_API_KEY / GEMINI_API_KEY env vars by their respective SDKs.

TilesetAnalyzerServer(rootDir, options)

| Option | Default | Description | |---|---|---| | publicDir | 'public' | Path to static files directory | | showAiControls | false | Show manual AI buttons in the web UI | | aiProviders | [] | Array of active provider strings | | skipAi | false | Disable AI analysis entirely | | skipIndex | false | Skip GET / page route (for admin embed) |

All AI and detection options below are also accepted and passed through to route handlers.

AI Options (AiAnalyzer, AiProviderCaller, MultiAiAnalyzer)

| Option | Default | Description | |---|---|---| | claudeModel | 'claude-sonnet-4-6' | Claude model ID | | claudeMaxTokens | 512 | Token budget for naming/verify | | claudeMaxTokensDetection | 4096 | Token budget for detection | | geminiModel | 'gemini-2.0-flash-preview-image-generation' | Gemini model ID | | geminiMaxTokens | 512 | Token budget for naming/verify | | geminiMaxTokensDetection | 4096 | Token budget for detection | | ollamaHost | 'http://localhost:11434' | Ollama server URL | | ollamaModel | 'qwen2.5vl:7b' | Default Ollama model | | ollamaAvailableModels | '' | Comma-separated list of additional Ollama models | | ollamaNumCtx | 8192 | Ollama context size | | ollamaNumPredict | 2000 | Ollama max tokens | | validatePass | false | Run a verify step after naming | | skipAi | false | Skip all AI calls |

Detection Options (ClusterDetector, ClusterCropper)

| Option | Default | Description | |---|---|---| | minClusterTiles | 1 | Discard clusters smaller than this | | clusterEmptyAlphaThreshold | 10 | Alpha below this = transparent | | clusterColorDistance | 30 | RGB distance from bgColor = background | | clusterVarianceThreshold | 600 | Exclude low-variance tiles | | clusterMinTileFillPct | 10 | Min % of tile pixels that must be non-background | | clusterSplitByGap | 1 | Split clusters at internal empty tile rows/cols | | elementBorderColorDistance | 20 | Max color distance between adjacent tile edges for single-element classification |

How It Works

  1. Upload: Tileset PNG uploaded; Sharp reads pixel buffer
  2. Tile Scan: Each tile scanned for non-background pixel fill percentage and variance
  3. Connected Components: image-js runs connected component labeling on a binary pixel mask
  4. Cluster Classification: Groups with uniform inter-tile border colors become elements; others stay as clusters
  5. AI Sub-Detection: Each cluster sent to AI to split into named sub-elements
  6. AI Naming + Layers: Each element cropped and sent to AI for a kebab-case name and layer assignments
  7. Multi-Provider Fallback: Providers tried in order (Ollama → Claude → Gemini); first valid result wins
  8. Output Generation: Per-element Tiled JSON, annotated PNG, composite map, and map-generator config written to output/{sessionId}/

Output Files

All saved to generated-tile-map-elements/output/{sessionId}/:

  • session-editor-state.json — full tileset+element state (used by Load session)
  • elements-config.json — same state formatted for readability
  • {tileset-name}.png — copy of original tileset PNG
  • {tileset-name}-{element-name}.json — per-element Tiled-format map
  • {tileset-name}-annotated.png — tileset with colored element overlays and grid
  • composite.json — all elements combined on one Tiled map
  • map-generator-config.json — Reldens map generator config

Input files stored in generated-tile-map-elements/input/{sessionId}/.

Dependencies

  • sharp: Pixel-level image processing and cropping
  • image-js: Connected component labeling for cluster detection
  • archiver: ZIP download of session output files
  • multer: Multipart file upload handling
  • @anthropic-ai/sdk: Claude AI provider
  • @google/genai: Gemini AI provider
  • @reldens/utils: Logger, Shortcuts (sc)
  • @reldens/server-utils: FileHandler

Related Packages

  • @reldens/tile-map-optimizer: Optimize Tiled JSON maps by removing unused tiles and merging tilesets
  • @reldens/tile-map-generator: Generate random tile maps for Reldens
  • Reldens: MMORPG platform that uses these generated maps

Reldens

By DwDeveloper