The .rayzr package
The Rayzr package format (.rayzr; before the rename: .ore, magic ORE1 - still read) is a high-performance, single-file container and serialization standard designed for data-driven game development. It decouples game design from compiled Odin source code, allowing complete games, scenes, physics configurations, node graphs, assets, and Lua scripts to be declared in portable files and manipulated via visual GUI editors.
1. Architectural Overview
Section titled “1. Architectural Overview”Development Mode (Loose Files) Export / Distribution Mode (.rayzr)┌─────────────────────────────────┐ ┌─────────────────────────────────┐│ my_game/ │ │ release_game.rayzr ││ ├── project.json │ ───► │ ├── [RYZ1 Header: 32 bytes] ││ ├── scenes/ │ Pack │ ├── [Contiguous Compressed ││ │ ├── main.scene.json │ │ │ Payloads: Textures, Audio,││ │ └── level2.scene.json │ │ │ JSON, Lua Scripts] ││ └── assets/ │ │ └── [Table of Contents (TOC) ││ ├── textures/hero.png │ │ Offsets, Sizes, CRC32] ││ ├── audio/bgm.ogg │ └─────────────────────────────────┘│ └── scripts/player.lua │└─────────────────────────────────┘The engine provides seamless dual-mode resolution:
- Loose Directory Mode (Git-Friendly Development): The engine reads loose files directly from disk (
project.json,scenes/*.scene.json, loose PNG/WAV/Lua files). Fast iteration without re-packaging. - Packaged Container Mode (
.rayzrRelease): All assets, scenes, and project configurations are compressed into a single binary archive. Can be embedded directly into release game binaries with#loador loaded from disk as a standalone portable package.
2. Binary Container Specification (RYZ1)
Section titled “2. Binary Container Specification (RYZ1)”The .rayzr file format uses an append-friendly layout where data payloads precede the Table of Contents (TOC), allowing high-throughput streaming and memory mapping:
+-------------------------------------------------------------+| Header (32 bytes) || magic: [4]u8 ('R', 'Y', 'Z', '1') || version: u32 (1) || fileCount: u32 || tocOffset: u64 || tocSize: u64 || flags: u32 (reserved) |+-------------------------------------------------------------+| Data Payloads (Variable length, contiguous) || File 0: [Raw / Zlib-compressed byte slice] || File 1: [Raw / Zlib-compressed byte slice] || ... |+-------------------------------------------------------------+| Table of Contents (TOC at tocOffset) || For each entry: || pathLen: u16 || path: [pathLen]u8 (UTF-8, normalized relative path) || dataOffset: u64 || compressedSize: u64 || uncompressedSize: u64 || compression: u8 (0 = Store, 1 = Deflate) || crc32: u32 (IEEE 802.3 CRC32 checksum) |+-------------------------------------------------------------+Compression Strategy
Section titled “Compression Strategy”- Individual files with uncompressed length $\le 64$ bytes or where compressed length $\ge$ uncompressed length are stored uncompressed (
Store). - Large files (scripts, scenes, JSON, raw textures, waveforms) are compressed using standard
zlib.deflate(Deflate). - Compressed payloads are decompressed on-demand with
zlib.uncompressdirectly into target buffers.
3. Project Configuration Schema (project.json)
Section titled “3. Project Configuration Schema (project.json)”The root configuration defines window settings, physics parameters, and registered scenes:
{ "name": "My Galactic Game", "version": "1.0.0", "initial_scene": "scenes/main.scene.json", "window": { "title": "My Galactic Adventure", "width": 1280, "height": 720, "virtual_width": 1280.0, "virtual_height": 720.0, "target_fps": 60 }, "physics": { "gravity": [0.0, 980.0] }, "scenes": [ "scenes/main.scene.json", "scenes/credits.scene.json" ]}4. Scene Graph Schema (*.scene.json)
Section titled “4. Scene Graph Schema (*.scene.json)”Scenes define the active camera, debug boundaries, and hierarchical node graphs. Node types and properties map directly to engine structures:
{ "name": "MainScene", "draw_bounds": false, "camera": { "target_position": [640.0, 360.0], "zoom": 1.0 }, "root": { "type": "Node", "name": "RootNode", "children": [ { "type": "StaticBodyNode", "name": "GroundPlatform", "position": [640.0, 680.0], "scale": [1.0, 1.0], "rotation": 0.0, "enabled": true, "visible": true, "layer": 0, "physics": { "shape": { "type": "box", "size": [1280.0, 40.0], "density": 0.0, "friction": 0.8, "restitution": 0.0 } } }, { "type": "DynamicBodyNode", "name": "PlayerCrate", "position": [640.0, 150.0], "scale": [1.0, 1.0], "rotation": 0.0, "enabled": true, "visible": true, "layer": 1, "physics": { "gravity_scale": 1.0, "fixed_rotation": false, "linear_damping": 0.05, "angular_damping": 0.1, "shape": { "type": "box", "size": [48.0, 48.0], "density": 1.5, "friction": 0.5, "restitution": 0.2 } }, "script": { "path": "assets/scripts/crate_physics.lua", "properties": { "bounciness": 1.2, "can_shatter": true } } }, { "type": "TextureNode", "name": "HeroSprite", "position": [400.0, 300.0], "texture_path": "assets/textures/hero.png", "pivot": [0.5, 1.0] } ] }}5. Supported Node Types in JSON
Section titled “5. Supported Node Types in JSON”| Node Type | Key Properties | Physics Support |
|---|---|---|
Node |
Basic transform (position, scale, rotation, enabled, visible, layer) |
Hierarchy transform |
TextureNode |
texture_path, pivot (the origin: a fraction of the image, [0.5, 0.5] = centre; also on animations, AnimationPlayers, nine-slices, text). An older pixel origin is still read. |
Sprite rendering |
DynamicBodyNode |
physics.gravity_scale, physics.fixed_rotation, physics.shape |
Box2D dynamic body |
StaticBodyNode |
physics.shape |
Box2D static geometry |
CharacterMoverNode |
character.speed, character.jump_speed, character.radius, character.height |
Kinematic character controller |
AreaNode |
area.shape |
Overlap & trigger sensor |
RaycastNode |
raycast.direction, raycast.length |
Geometric raycaster |
ParticleEmitterNode |
particles.amount, particles.lifetime, particles.emitting |
Particle simulation |
TimerNode |
timer.duration, timer.auto_start, timer.loop |
Frame-independent timer |
CameraNode |
camera.zoom, camera.target_position |
2D camera controls |
6. Engine API Usage in Odin
Section titled “6. Engine API Usage in Odin”// 1. Load project directly from loose folder during developmentgame->loadProject("my_project_folder")
// 2. Export folder into standalone .rayzr container packagegame.exportRayzr("my_project_folder", "exports/game.rayzr")
// 3. Load project directly from .rayzr container packagegame->loadProject("exports/game.rayzr")
// 4. Serialize active scene to JSON string (for editor save operations)jsonString := e.Scene_SerializeToJSON(activeScene)7. Engine API Usage in Lua
Section titled “7. Engine API Usage in Lua”-- Load a complete project (.rayzr or directory)Project.load("assets/demo_project.rayzr")
-- Read arbitrary asset file from mounted .rayzr archive or disklocal scriptSource = Project.read_file("assets/scripts/orbiting_drone.lua")
-- Check file existenceif Project.has_file("scenes/bonus.scene.json") then -- File existsend
-- Serialize current scene to JSONlocal jsonStr = Project.serialize_scene()
-- Pack loose project directory into .rayzr packageProject.export_rayzr("assets/demo_project", "assets/demo_project.rayzr")