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

@dcversus/babylon-anyup

v0.1.0

Published

Babylon.js plugin for Z-up coordinate system compatibility with automatic transforms

Readme

babylon-anyup

npm version License: AGPL-3.0 Build Status Coverage Bundle Size

A Babylon.js plugin for seamless Z-up to Y-up coordinate system conversion with automatic transforms.

Why This Exists

babylon-anyup was born from real-world pain while building Edge Craft - a WebGL-based RTS game engine. Our goal is to let modmakers port their Warcraft 3 and StarCraft 2 maps and mods to the web. But there's a problem:

Blizzard games use Z-up coordinates. Babylon.js uses Y-up coordinates.

This means every terrain vertex, every model, every camera position needs manual transformation. Without babylon-anyup, our codebase was littered with hundreds of lines of error-prone coordinate conversion math. Rotating models by -90°, swapping Y and Z axes, inverting signs - it was a nightmare to maintain.

We built this library to solve that problem once and for all. Now you can load Blizzard-format maps directly into Babylon.js without thinking about coordinate systems.

Who This Is For

This library is perfect for developers working with:

  • Game Development: Porting Warcraft 3, StarCraft 2, or other Z-up games to Babylon.js
  • CAD Import: Bringing CAD models (typically Z-up) into web-based Babylon.js viewers
  • Blender Integration: Loading Blender exports (Z-up) without manual rotation
  • 3D Content Pipelines: Building tools that need to support multiple coordinate systems
  • RTS Engines: Building real-time strategy games with terrain and unit systems

Overview

babylon-anyup provides a type-safe, zero-dependency solution for working with different coordinate systems in Babylon.js. It automatically handles the mathematical transformations needed to convert between:

  • Z-up (Warcraft 3, StarCraft 2, Blizzard games, many 3D modeling tools)
  • Y-up (Babylon.js default, many game engines)

Status

Current Phase: Initial Development Version: 0.1.0 Stability: Alpha Release Date: TBD

Live Demo

Coming soon! Check back after v0.1.0 release for interactive examples on GitHub Pages.

Features

  • Automatic coordinate system conversion (Z-up ↔ Y-up)
  • Position, rotation, and scaling transformations
  • Preserves original transforms (optional)
  • Type-safe with full TypeScript support
  • Zero dependencies (peer dependency: @babylonjs/core)
  • Lightweight (<10KB minified)

Installation

npm install @dcversus/babylon-anyup

Quick Start

import { Engine, Scene, MeshBuilder } from '@babylonjs/core';
import { AnyUpPlugin } from '@dcversus/babylon-anyup';

const scene = new Scene(engine);

// Initialize the plugin
const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: true,
  preserveOriginal: true,
});

plugin.initialize(scene);

// All meshes in the scene are automatically converted
const mesh = MeshBuilder.CreateBox('box', { size: 2 }, scene);

API Reference

AnyUpPlugin

Main plugin class for coordinate system conversion.

Constructor

new AnyUpPlugin(options: AnyUpPluginOptions)

Options:

interface AnyUpPluginOptions {
  sourceSystem: 'y-up' | 'z-up';  // Source coordinate system
  targetSystem: 'y-up' | 'z-up';  // Target coordinate system
  autoConvert: boolean;           // Auto-convert all meshes on initialize()
  preserveOriginal: boolean;      // Store original transforms in metadata
}
  • sourceSystem - Input coordinate system ('z-up' for Warcraft 3, Blender; 'y-up' for Babylon.js)
  • targetSystem - Output coordinate system (must differ from source)
  • autoConvert - If true, automatically converts all existing meshes when initialize() is called
  • preserveOriginal - If true, stores original transforms in mesh.metadata before conversion

Properties

  • name: string - Plugin identifier (readonly, always "AnyUpPlugin")
  • options: AnyUpPluginOptions - Configuration options (readonly)

Methods

initialize(scene: Scene): void

Initialize the plugin with a Babylon.js scene.

const scene = new Scene(engine);
plugin.initialize(scene);

Behavior:

  • If autoConvert: true, converts all existing meshes and transform nodes
  • Stores plugin reference in scene.metadata for later access
convertMesh(mesh: AbstractMesh): void

Convert a single mesh's transform to the target coordinate system.

const box = MeshBuilder.CreateBox('box', { size: 2 }, scene);
plugin.convertMesh(box);

Behavior:

  • Transforms position, rotationQuaternion, and scaling
  • If preserveOriginal: true, stores original values in mesh.metadata
  • Handles null rotationQuaternion gracefully

Metadata (when preserveOriginal: true):

mesh.metadata = {
  originalPosition: Vector3,
  originalRotation: Quaternion | null,
  originalScaling: Vector3,
};
convertTransformNode(node: TransformNode): void

Convert a transform node (same as convertMesh() but for nodes without geometry).

const parent = new TransformNode('parent', scene);
plugin.convertTransformNode(parent);
dispose(): void

Clean up plugin resources. Call when the plugin is no longer needed.

plugin.dispose();

Transform Strategies

Low-level transformation strategies (used internally by AnyUpPlugin).

ZUpToYUpStrategy

Converts Z-up coordinates to Y-up (Blizzard games → Babylon.js).

import { ZUpToYUpStrategy } from '@dcversus/babylon-anyup';

const strategy = new ZUpToYUpStrategy();
const converted = strategy.convertPosition(new Vector3(1, 2, 3));
// Result: Vector3(1, 3, -2)

Transformation:

  • Position: (x, y, z)(x, z, -y)
  • Rotation: Applies -90° X-axis correction
  • Scaling: (x, y, z)(x, z, y)

YUpToZUpStrategy

Converts Y-up coordinates to Z-up (Babylon.js → Blizzard games).

import { YUpToZUpStrategy } from '@dcversus/babylon-anyup';

const strategy = new YUpToZUpStrategy();
const converted = strategy.convertPosition(new Vector3(1, 2, 3));
// Result: Vector3(1, -3, 2)

Transformation:

  • Position: (x, y, z)(x, -z, y)
  • Rotation: Applies +90° X-axis correction
  • Scaling: (x, y, z)(x, z, y)

TransformStrategyFactory

Factory for creating transformation strategies.

import { TransformStrategyFactory } from '@dcversus/babylon-anyup';

const strategy = TransformStrategyFactory.createStrategy('z-up', 'y-up');

Throws:

  • Error if source === target
  • Error if conversion not supported

Usage Examples

Warcraft 3 Terrain Import

import { Engine, Scene } from '@babylonjs/core';
import { AnyUpPlugin } from '@dcversus/babylon-anyup';

const engine = new Engine(canvas);
const scene = new Scene(engine);

// Initialize plugin for Z-up (Warcraft 3)
const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: true,
  preserveOriginal: false,
});

plugin.initialize(scene);

// Load Warcraft 3 terrain (automatically converted)
const terrain = await loadW3Terrain('map.w3e');
scene.addMesh(terrain); // Already in Y-up coordinates!

Selective Conversion (Manual Mode)

const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: false, // Disable auto-conversion
  preserveOriginal: false,
});

plugin.initialize(scene);

// Only convert specific meshes
const terrain = loadWarcraft3Terrain();
plugin.convertMesh(terrain);

const units = loadWarcraft3Units();
// Don't convert units (keep original orientation)

Preserve Original Transforms

const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: true,
  preserveOriginal: true, // Store originals
});

plugin.initialize(scene);

// Access original transforms later
scene.meshes.forEach(mesh => {
  console.log('Original:', mesh.metadata.originalPosition);
  console.log('Converted:', mesh.position);

  // Revert if needed
  if (someCondition) {
    mesh.position = mesh.metadata.originalPosition.clone();
  }
});

Blender Model Import

import { SceneLoader } from '@babylonjs/core';
import { AnyUpPlugin } from '@dcversus/babylon-anyup';

// Initialize plugin
const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: false,
  preserveOriginal: false,
});

plugin.initialize(scene);

// Load Blender export (typically Z-up)
SceneLoader.ImportMesh('', '/models/', 'blender_export.glb', scene, (meshes) => {
  // Convert imported meshes
  meshes.forEach(mesh => plugin.convertMesh(mesh));
});

Direct Strategy Usage (Advanced)

import { ZUpToYUpStrategy } from '@dcversus/babylon-anyup';
import { Vector3, Quaternion } from '@babylonjs/core';

const strategy = new ZUpToYUpStrategy();

// Convert individual components
const zUpPos = new Vector3(10, 20, 30);
const yUpPos = strategy.convertPosition(zUpPos);
console.log(yUpPos); // Vector3(10, 30, -20)

// Convert rotation
const zUpRot = Quaternion.FromEulerAngles(0, Math.PI / 4, 0);
const yUpRot = strategy.convertRotation(zUpRot);

// Convert scaling
const zUpScale = new Vector3(1, 2, 3);
const yUpScale = strategy.convertScaling(zUpScale);
console.log(yUpScale); // Vector3(1, 3, 2)

Migration Guide

From Manual Transforms

Before (manual transformation):

// ❌ Old way: Manual coordinate conversion everywhere
function loadW3Terrain(w3e: W3E) {
  for (let i = 0; i < w3e.vertices.length; i++) {
    // Manual Y↔Z swap and negation
    vertices[i * 3] = w3e.vertices[i].x;
    vertices[i * 3 + 1] = w3e.vertices[i].z;  // Y becomes Z
    vertices[i * 3 + 2] = -w3e.vertices[i].y; // Z becomes -Y
  }

  // Hardcoded -90° rotation for models
  mesh.rotation.x = -Math.PI / 2;
}

After (with babylon-anyup):

// ✅ New way: Automatic transformation
import { AnyUpPlugin } from '@dcversus/babylon-anyup';

const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',
  targetSystem: 'y-up',
  autoConvert: true,
  preserveOriginal: false,
});

plugin.initialize(scene);

// Load terrain normally - plugin handles conversion
function loadW3Terrain(w3e: W3E) {
  // Just use data as-is, plugin converts automatically
  const terrain = createTerrainMesh(w3e);
  // Done! No manual transformation needed
}

Migration Steps

  1. Install babylon-anyup:
npm install @dcversus/babylon-anyup
  1. Remove manual transforms:

    • Delete all Y↔Z swapping code
    • Remove hardcoded rotations (e.g., mesh.rotation.x = -Math.PI / 2)
    • Remove position/scale coordinate conversions
  2. Add plugin initialization:

import { AnyUpPlugin } from '@dcversus/babylon-anyup';

const plugin = new AnyUpPlugin({
  sourceSystem: 'z-up',  // Your source data format
  targetSystem: 'y-up',  // Babylon.js format
  autoConvert: true,     // Convert everything automatically
  preserveOriginal: false,
});

plugin.initialize(scene);
  1. Test thoroughly:

    • Verify meshes are positioned correctly
    • Check rotations are correct
    • Validate scaling matches expectations
    • Test camera controls feel natural
  2. Clean up (optional):

    • Remove helper functions for coordinate conversion
    • Simplify data loading code
    • Update comments/documentation

Common Issues During Migration

Issue: Meshes are upside down or rotated incorrectly

  • Solution: Ensure you're using correct sourceSystem and targetSystem
  • Tip: Try swapping them if objects appear inverted

Issue: Some meshes convert, others don't

  • Solution: Use autoConvert: true or manually call plugin.convertMesh() for each mesh
  • Tip: Check if meshes were added before plugin.initialize()

Issue: Transformations are applied twice

  • Solution: Remove manual coordinate conversions from your code
  • Tip: Search codebase for Y/Z swaps, hardcoded rotations

Contributing

Want to contribute? See CONTRIBUTING.md for development workflow, quality standards, and PR guidelines

Performance Benchmarks

Benchmarks run on MacBook, version 0.1.0 (2025-10-27):

| Operation | Target (PRP) | Actual | Status | |-----------|--------------|--------|--------| | Vector3 Transform | >100,000 ops/sec | ~22,000,000 ops/sec | ✅ 220x faster | | Quaternion Transform | >66,000 ops/sec | ~19,000,000 ops/sec | ✅ 287x faster | | Bulk Transform (1K vectors) | N/A | 183,549 ops/sec | ✅ | | Bulk Transform (1K quaternions) | N/A | 35,493 ops/sec | ✅ | | Bundle Size | <10KB minified | 8.2KB | ✅ |

Real-world impact: Transforming 10,000 meshes takes ~0.5ms - negligible overhead in production scenes.

Run Benchmarks Yourself

npm run bench

Detailed Results

Vector3 Transform:

  • ZUpToYUpStrategy: 22,299,067 ops/sec (fastest)
  • YUpToZUpStrategy: 19,933,199 ops/sec

Quaternion Transform:

  • ZUpToYUpStrategy: 18,273,103 ops/sec
  • YUpToZUpStrategy: 19,600,341 ops/sec (fastest)

Scaling Transform:

  • ZUpToYUpStrategy: 20,312,662 ops/sec
  • YUpToZUpStrategy: 20,744,284 ops/sec (fastest)

The library achieves exceptional performance due to minimal overhead, optimized Babylon.js math operations, and zero dynamic dispatch.

Browser Support

Supports all modern browsers that support WebGL 2:

  • Chrome 56+
  • Firefox 51+
  • Safari 15+
  • Edge 79+

Requires Babylon.js 7.0.0 or higher.

Troubleshooting

My meshes are still rotated incorrectly

Ensure you're using autoConvert: true or manually calling plugin.convertMesh(mesh) after loading. If the mesh was already in the scene before plugin initialization, convert it manually:

const plugin = new AnyUpPlugin({ sourceSystem: 'z-up', targetSystem: 'y-up' });
plugin.initialize(scene);

// For existing meshes
scene.meshes.forEach(mesh => plugin.convertMesh(mesh));

Performance is slower than expected

  1. Check if you're converting the same mesh multiple times (use mesh.metadata.coordinateSystemConverted to track)
  2. Use autoConvert: false and batch convert meshes during load
  3. Profile with browser DevTools to identify bottlenecks

Transformations are not reversible

Ensure you're using preserveOriginal: true to store original transforms in metadata. Note that floating-point precision may cause small errors in round-trip conversions.

Plugin not working with imported models

Some model loaders apply their own transformations. Initialize the plugin before loading models, or manually convert after import completes.

License

GNU Affero General Public License v3.0 (AGPL-3.0) - see LICENSE for details.

Author: Vasilisa Versus (@dcversus) Contact:

Related Projects

  • Edge Craft - WebGL RTS game engine (the project that inspired babylon-anyup)
  • Babylon.js - Powerful 3D engine for the web
  • mdx-m3-viewer - Warcraft 3 and StarCraft 2 model viewer

Roadmap

v0.1.0 (Current)

  • [x] Core Z-up to Y-up transformation
  • [x] Plugin system with auto-convert
  • [ ] Comprehensive test suite
  • [ ] Performance benchmarks
  • [ ] Documentation and examples

v0.2.0 (Planned)

  • [ ] X-up coordinate system support
  • [ ] Custom coordinate system definitions
  • [ ] Animation retargeting
  • [ ] Vertex-level transformations
  • [ ] glTF/OBJ loader integration

v1.0.0 (Future)

  • [ ] Handedness conversion (left ↔ right)
  • [ ] UV coordinate adjustments
  • [ ] Performance optimizations (SIMD, workers)
  • [ ] Visual debugging tools

Sponsors

This project is currently maintained by @dcversus. If you find this library useful, consider sponsoring development:

Support