{"id":51236875,"url":"https://github.com/dcversus/babylon-anyup","last_synced_at":"2026-06-28T21:02:26.835Z","repository":{"id":321136612,"uuid":"1084553426","full_name":"dcversus/babylon-anyup","owner":"dcversus","description":"Babylon.js Z-up coordinate system compatibility layer - making Babylon.js work seamlessly with RTS game formats","archived":false,"fork":false,"pushed_at":"2025-10-28T17:56:23.000Z","size":581,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-31T12:39:33.540Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dcversus.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-10-27T20:49:12.000Z","updated_at":"2025-10-28T17:56:27.000Z","dependencies_parsed_at":"2025-10-28T02:25:33.169Z","dependency_job_id":"c6c4535e-4909-4f63-808c-856ccf20925b","html_url":"https://github.com/dcversus/babylon-anyup","commit_stats":null,"previous_names":["dcversus/babylon-anyup"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/dcversus/babylon-anyup","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcversus%2Fbabylon-anyup","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcversus%2Fbabylon-anyup/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcversus%2Fbabylon-anyup/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcversus%2Fbabylon-anyup/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dcversus","download_url":"https://codeload.github.com/dcversus/babylon-anyup/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dcversus%2Fbabylon-anyup/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34903523,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-28T02:00:05.809Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-28T21:02:24.570Z","updated_at":"2026-06-28T21:02:26.816Z","avatar_url":"https://github.com/dcversus.png","language":"TypeScript","funding_links":["https://github.com/sponsors/dcversus"],"categories":[],"sub_categories":[],"readme":"# babylon-anyup\n\n[![npm version](https://img.shields.io/npm/v/@dcversus/babylon-anyup.svg)](https://www.npmjs.com/package/@dcversus/babylon-anyup)\n[![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)\n[![Build Status](https://img.shields.io/github/actions/workflow/status/dcversus/babylon-anyup/ci.yml?branch=main)](https://github.com/dcversus/babylon-anyup/actions)\n[![Coverage](https://img.shields.io/codecov/c/github/dcversus/babylon-anyup)](https://codecov.io/gh/dcversus/babylon-anyup)\n[![Bundle Size](https://img.shields.io/bundlephobia/minzip/@dcversus/babylon-anyup)](https://bundlephobia.com/package/@dcversus/babylon-anyup)\n\nA Babylon.js plugin for seamless Z-up to Y-up coordinate system conversion with automatic transforms.\n\n## Why This Exists\n\n**babylon-anyup** was born from real-world pain while building [Edge Craft](https://github.com/dcversus/edgecraft) - 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:\n\n**Blizzard games use Z-up coordinates. Babylon.js uses Y-up coordinates.**\n\nThis 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.\n\nWe 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.\n\n## Who This Is For\n\nThis library is perfect for developers working with:\n- **Game Development**: Porting Warcraft 3, StarCraft 2, or other Z-up games to Babylon.js\n- **CAD Import**: Bringing CAD models (typically Z-up) into web-based Babylon.js viewers\n- **Blender Integration**: Loading Blender exports (Z-up) without manual rotation\n- **3D Content Pipelines**: Building tools that need to support multiple coordinate systems\n- **RTS Engines**: Building real-time strategy games with terrain and unit systems\n\n## Overview\n\n**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:\n- **Z-up** (Warcraft 3, StarCraft 2, Blizzard games, many 3D modeling tools)\n- **Y-up** (Babylon.js default, many game engines)\n\n## Status\n\n**Current Phase**: Initial Development\n**Version**: 0.1.0\n**Stability**: Alpha\n**Release Date**: TBD\n\n## Live Demo\n\nComing soon! Check back after v0.1.0 release for interactive examples on GitHub Pages.\n\n## Features\n\n- Automatic coordinate system conversion (Z-up ↔ Y-up)\n- Position, rotation, and scaling transformations\n- Preserves original transforms (optional)\n- Type-safe with full TypeScript support\n- Zero dependencies (peer dependency: @babylonjs/core)\n- Lightweight (\u003c10KB minified)\n\n## Installation\n\n```bash\nnpm install @dcversus/babylon-anyup\n```\n\n## Quick Start\n\n```typescript\nimport { Engine, Scene, MeshBuilder } from '@babylonjs/core';\nimport { AnyUpPlugin } from '@dcversus/babylon-anyup';\n\nconst scene = new Scene(engine);\n\n// Initialize the plugin\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: true,\n  preserveOriginal: true,\n});\n\nplugin.initialize(scene);\n\n// All meshes in the scene are automatically converted\nconst mesh = MeshBuilder.CreateBox('box', { size: 2 }, scene);\n```\n\n## API Reference\n\n### `AnyUpPlugin`\n\nMain plugin class for coordinate system conversion.\n\n#### Constructor\n\n```typescript\nnew AnyUpPlugin(options: AnyUpPluginOptions)\n```\n\n**Options:**\n\n```typescript\ninterface AnyUpPluginOptions {\n  sourceSystem: 'y-up' | 'z-up';  // Source coordinate system\n  targetSystem: 'y-up' | 'z-up';  // Target coordinate system\n  autoConvert: boolean;           // Auto-convert all meshes on initialize()\n  preserveOriginal: boolean;      // Store original transforms in metadata\n}\n```\n\n- `sourceSystem` - Input coordinate system (`'z-up'` for Warcraft 3, Blender; `'y-up'` for Babylon.js)\n- `targetSystem` - Output coordinate system (must differ from source)\n- `autoConvert` - If `true`, automatically converts all existing meshes when `initialize()` is called\n- `preserveOriginal` - If `true`, stores original transforms in `mesh.metadata` before conversion\n\n#### Properties\n\n- `name: string` - Plugin identifier (readonly, always `\"AnyUpPlugin\"`)\n- `options: AnyUpPluginOptions` - Configuration options (readonly)\n\n#### Methods\n\n##### `initialize(scene: Scene): void`\n\nInitialize the plugin with a Babylon.js scene.\n\n```typescript\nconst scene = new Scene(engine);\nplugin.initialize(scene);\n```\n\n**Behavior:**\n- If `autoConvert: true`, converts all existing meshes and transform nodes\n- Stores plugin reference in `scene.metadata` for later access\n\n##### `convertMesh(mesh: AbstractMesh): void`\n\nConvert a single mesh's transform to the target coordinate system.\n\n```typescript\nconst box = MeshBuilder.CreateBox('box', { size: 2 }, scene);\nplugin.convertMesh(box);\n```\n\n**Behavior:**\n- Transforms `position`, `rotationQuaternion`, and `scaling`\n- If `preserveOriginal: true`, stores original values in `mesh.metadata`\n- Handles null `rotationQuaternion` gracefully\n\n**Metadata (when `preserveOriginal: true`):**\n```typescript\nmesh.metadata = {\n  originalPosition: Vector3,\n  originalRotation: Quaternion | null,\n  originalScaling: Vector3,\n};\n```\n\n##### `convertTransformNode(node: TransformNode): void`\n\nConvert a transform node (same as `convertMesh()` but for nodes without geometry).\n\n```typescript\nconst parent = new TransformNode('parent', scene);\nplugin.convertTransformNode(parent);\n```\n\n##### `dispose(): void`\n\nClean up plugin resources. Call when the plugin is no longer needed.\n\n```typescript\nplugin.dispose();\n```\n\n### Transform Strategies\n\nLow-level transformation strategies (used internally by `AnyUpPlugin`).\n\n#### `ZUpToYUpStrategy`\n\nConverts Z-up coordinates to Y-up (Blizzard games → Babylon.js).\n\n```typescript\nimport { ZUpToYUpStrategy } from '@dcversus/babylon-anyup';\n\nconst strategy = new ZUpToYUpStrategy();\nconst converted = strategy.convertPosition(new Vector3(1, 2, 3));\n// Result: Vector3(1, 3, -2)\n```\n\n**Transformation:**\n- Position: `(x, y, z)` → `(x, z, -y)`\n- Rotation: Applies -90° X-axis correction\n- Scaling: `(x, y, z)` → `(x, z, y)`\n\n#### `YUpToZUpStrategy`\n\nConverts Y-up coordinates to Z-up (Babylon.js → Blizzard games).\n\n```typescript\nimport { YUpToZUpStrategy } from '@dcversus/babylon-anyup';\n\nconst strategy = new YUpToZUpStrategy();\nconst converted = strategy.convertPosition(new Vector3(1, 2, 3));\n// Result: Vector3(1, -3, 2)\n```\n\n**Transformation:**\n- Position: `(x, y, z)` → `(x, -z, y)`\n- Rotation: Applies +90° X-axis correction\n- Scaling: `(x, y, z)` → `(x, z, y)`\n\n#### `TransformStrategyFactory`\n\nFactory for creating transformation strategies.\n\n```typescript\nimport { TransformStrategyFactory } from '@dcversus/babylon-anyup';\n\nconst strategy = TransformStrategyFactory.createStrategy('z-up', 'y-up');\n```\n\n**Throws:**\n- `Error` if `source === target`\n- `Error` if conversion not supported\n\n## Usage Examples\n\n### Warcraft 3 Terrain Import\n\n```typescript\nimport { Engine, Scene } from '@babylonjs/core';\nimport { AnyUpPlugin } from '@dcversus/babylon-anyup';\n\nconst engine = new Engine(canvas);\nconst scene = new Scene(engine);\n\n// Initialize plugin for Z-up (Warcraft 3)\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: true,\n  preserveOriginal: false,\n});\n\nplugin.initialize(scene);\n\n// Load Warcraft 3 terrain (automatically converted)\nconst terrain = await loadW3Terrain('map.w3e');\nscene.addMesh(terrain); // Already in Y-up coordinates!\n```\n\n### Selective Conversion (Manual Mode)\n\n```typescript\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: false, // Disable auto-conversion\n  preserveOriginal: false,\n});\n\nplugin.initialize(scene);\n\n// Only convert specific meshes\nconst terrain = loadWarcraft3Terrain();\nplugin.convertMesh(terrain);\n\nconst units = loadWarcraft3Units();\n// Don't convert units (keep original orientation)\n```\n\n### Preserve Original Transforms\n\n```typescript\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: true,\n  preserveOriginal: true, // Store originals\n});\n\nplugin.initialize(scene);\n\n// Access original transforms later\nscene.meshes.forEach(mesh =\u003e {\n  console.log('Original:', mesh.metadata.originalPosition);\n  console.log('Converted:', mesh.position);\n\n  // Revert if needed\n  if (someCondition) {\n    mesh.position = mesh.metadata.originalPosition.clone();\n  }\n});\n```\n\n### Blender Model Import\n\n```typescript\nimport { SceneLoader } from '@babylonjs/core';\nimport { AnyUpPlugin } from '@dcversus/babylon-anyup';\n\n// Initialize plugin\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: false,\n  preserveOriginal: false,\n});\n\nplugin.initialize(scene);\n\n// Load Blender export (typically Z-up)\nSceneLoader.ImportMesh('', '/models/', 'blender_export.glb', scene, (meshes) =\u003e {\n  // Convert imported meshes\n  meshes.forEach(mesh =\u003e plugin.convertMesh(mesh));\n});\n```\n\n### Direct Strategy Usage (Advanced)\n\n```typescript\nimport { ZUpToYUpStrategy } from '@dcversus/babylon-anyup';\nimport { Vector3, Quaternion } from '@babylonjs/core';\n\nconst strategy = new ZUpToYUpStrategy();\n\n// Convert individual components\nconst zUpPos = new Vector3(10, 20, 30);\nconst yUpPos = strategy.convertPosition(zUpPos);\nconsole.log(yUpPos); // Vector3(10, 30, -20)\n\n// Convert rotation\nconst zUpRot = Quaternion.FromEulerAngles(0, Math.PI / 4, 0);\nconst yUpRot = strategy.convertRotation(zUpRot);\n\n// Convert scaling\nconst zUpScale = new Vector3(1, 2, 3);\nconst yUpScale = strategy.convertScaling(zUpScale);\nconsole.log(yUpScale); // Vector3(1, 3, 2)\n```\n\n## Migration Guide\n\n### From Manual Transforms\n\n**Before (manual transformation):**\n\n```typescript\n// ❌ Old way: Manual coordinate conversion everywhere\nfunction loadW3Terrain(w3e: W3E) {\n  for (let i = 0; i \u003c w3e.vertices.length; i++) {\n    // Manual Y↔Z swap and negation\n    vertices[i * 3] = w3e.vertices[i].x;\n    vertices[i * 3 + 1] = w3e.vertices[i].z;  // Y becomes Z\n    vertices[i * 3 + 2] = -w3e.vertices[i].y; // Z becomes -Y\n  }\n\n  // Hardcoded -90° rotation for models\n  mesh.rotation.x = -Math.PI / 2;\n}\n```\n\n**After (with babylon-anyup):**\n\n```typescript\n// ✅ New way: Automatic transformation\nimport { AnyUpPlugin } from '@dcversus/babylon-anyup';\n\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',\n  targetSystem: 'y-up',\n  autoConvert: true,\n  preserveOriginal: false,\n});\n\nplugin.initialize(scene);\n\n// Load terrain normally - plugin handles conversion\nfunction loadW3Terrain(w3e: W3E) {\n  // Just use data as-is, plugin converts automatically\n  const terrain = createTerrainMesh(w3e);\n  // Done! No manual transformation needed\n}\n```\n\n### Migration Steps\n\n1. **Install babylon-anyup:**\n```bash\nnpm install @dcversus/babylon-anyup\n```\n\n2. **Remove manual transforms:**\n   - Delete all Y↔Z swapping code\n   - Remove hardcoded rotations (e.g., `mesh.rotation.x = -Math.PI / 2`)\n   - Remove position/scale coordinate conversions\n\n3. **Add plugin initialization:**\n```typescript\nimport { AnyUpPlugin } from '@dcversus/babylon-anyup';\n\nconst plugin = new AnyUpPlugin({\n  sourceSystem: 'z-up',  // Your source data format\n  targetSystem: 'y-up',  // Babylon.js format\n  autoConvert: true,     // Convert everything automatically\n  preserveOriginal: false,\n});\n\nplugin.initialize(scene);\n```\n\n4. **Test thoroughly:**\n   - Verify meshes are positioned correctly\n   - Check rotations are correct\n   - Validate scaling matches expectations\n   - Test camera controls feel natural\n\n5. **Clean up (optional):**\n   - Remove helper functions for coordinate conversion\n   - Simplify data loading code\n   - Update comments/documentation\n\n### Common Issues During Migration\n\n**Issue:** Meshes are upside down or rotated incorrectly\n- **Solution:** Ensure you're using correct `sourceSystem` and `targetSystem`\n- **Tip:** Try swapping them if objects appear inverted\n\n**Issue:** Some meshes convert, others don't\n- **Solution:** Use `autoConvert: true` or manually call `plugin.convertMesh()` for each mesh\n- **Tip:** Check if meshes were added before `plugin.initialize()`\n\n**Issue:** Transformations are applied twice\n- **Solution:** Remove manual coordinate conversions from your code\n- **Tip:** Search codebase for Y/Z swaps, hardcoded rotations\n\n## Contributing\n\nWant to contribute? See [CONTRIBUTING.md](./CONTRIBUTING.md) for development workflow, quality standards, and PR guidelines\n\n## Performance Benchmarks\n\nBenchmarks run on MacBook, version 0.1.0 (2025-10-27):\n\n| Operation | Target (PRP) | Actual | Status |\n|-----------|--------------|--------|--------|\n| Vector3 Transform | \u003e100,000 ops/sec | ~22,000,000 ops/sec | ✅ **220x faster** |\n| Quaternion Transform | \u003e66,000 ops/sec | ~19,000,000 ops/sec | ✅ **287x faster** |\n| Bulk Transform (1K vectors) | N/A | 183,549 ops/sec | ✅ |\n| Bulk Transform (1K quaternions) | N/A | 35,493 ops/sec | ✅ |\n| Bundle Size | \u003c10KB minified | 8.2KB | ✅ |\n\n**Real-world impact**: Transforming 10,000 meshes takes ~0.5ms - negligible overhead in production scenes.\n\n### Run Benchmarks Yourself\n\n```bash\nnpm run bench\n```\n\n### Detailed Results\n\n**Vector3 Transform:**\n- ZUpToYUpStrategy: 22,299,067 ops/sec (fastest)\n- YUpToZUpStrategy: 19,933,199 ops/sec\n\n**Quaternion Transform:**\n- ZUpToYUpStrategy: 18,273,103 ops/sec\n- YUpToZUpStrategy: 19,600,341 ops/sec (fastest)\n\n**Scaling Transform:**\n- ZUpToYUpStrategy: 20,312,662 ops/sec\n- YUpToZUpStrategy: 20,744,284 ops/sec (fastest)\n\nThe library achieves exceptional performance due to minimal overhead, optimized Babylon.js math operations, and zero dynamic dispatch.\n\n## Browser Support\n\nSupports all modern browsers that support WebGL 2:\n- Chrome 56+\n- Firefox 51+\n- Safari 15+\n- Edge 79+\n\nRequires Babylon.js 7.0.0 or higher.\n\n## Troubleshooting\n\n### My meshes are still rotated incorrectly\n\nEnsure 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:\n\n```typescript\nconst plugin = new AnyUpPlugin({ sourceSystem: 'z-up', targetSystem: 'y-up' });\nplugin.initialize(scene);\n\n// For existing meshes\nscene.meshes.forEach(mesh =\u003e plugin.convertMesh(mesh));\n```\n\n### Performance is slower than expected\n\n1. Check if you're converting the same mesh multiple times (use `mesh.metadata.coordinateSystemConverted` to track)\n2. Use `autoConvert: false` and batch convert meshes during load\n3. Profile with browser DevTools to identify bottlenecks\n\n### Transformations are not reversible\n\nEnsure you're using `preserveOriginal: true` to store original transforms in metadata. Note that floating-point precision may cause small errors in round-trip conversions.\n\n### Plugin not working with imported models\n\nSome model loaders apply their own transformations. Initialize the plugin before loading models, or manually convert after import completes.\n\n## License\n\nGNU Affero General Public License v3.0 (AGPL-3.0) - see [LICENSE](./LICENSE) for details.\n\n**Author**: Vasilisa Versus ([@dcversus](https://github.com/dcversus))\n**Contact**:\n- Email: dcversus@gmail.com\n- Telegram: [t.me/dcversus](https://t.me/dcversus)\n- Social: @dcversus\n\n## Related Projects\n\n- **[Edge Craft](https://github.com/dcversus/edgecraft)** - WebGL RTS game engine (the project that inspired babylon-anyup)\n- **[Babylon.js](https://www.babylonjs.com/)** - Powerful 3D engine for the web\n- **[mdx-m3-viewer](https://github.com/flowtsohg/mdx-m3-viewer)** - Warcraft 3 and StarCraft 2 model viewer\n\n## Roadmap\n\n### v0.1.0 (Current)\n- [x] Core Z-up to Y-up transformation\n- [x] Plugin system with auto-convert\n- [ ] Comprehensive test suite\n- [ ] Performance benchmarks\n- [ ] Documentation and examples\n\n### v0.2.0 (Planned)\n- [ ] X-up coordinate system support\n- [ ] Custom coordinate system definitions\n- [ ] Animation retargeting\n- [ ] Vertex-level transformations\n- [ ] glTF/OBJ loader integration\n\n### v1.0.0 (Future)\n- [ ] Handedness conversion (left ↔ right)\n- [ ] UV coordinate adjustments\n- [ ] Performance optimizations (SIMD, workers)\n- [ ] Visual debugging tools\n\n## Sponsors\n\nThis project is currently maintained by [@dcversus](https://github.com/dcversus). If you find this library useful, consider sponsoring development:\n\n- [GitHub Sponsors](https://github.com/sponsors/dcversus) (coming soon)\n\n## Support\n\n- **Issues**: [GitHub Issues](https://github.com/dcversus/babylon-anyup/issues)\n- **Discussions**: [GitHub Discussions](https://github.com/dcversus/babylon-anyup/discussions)\n- **Security**: See [SECURITY.md](./SECURITY.md) for vulnerability reporting\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcversus%2Fbabylon-anyup","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdcversus%2Fbabylon-anyup","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdcversus%2Fbabylon-anyup/lists"}