Skip to content
hikari
RenderingEditorAIToolchainDocumentation
GitHub
hikari

© 2026 Flying Rat Studio.
All rights reserved.

Explore the engineDocumentationContributorsLicenseBack to top
Documentation / Systems
Browse docs
Overview
Tutorials16
OverviewFirst game projectFirst entityAuthored user_data and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesPlay, Edit, and scenesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides16
OverviewDevelopment guideGameplay APIChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / UnrealActor and component lifecycle
Systems28
OverviewArchitectureApplication lifecycleFrontends and driversPlatforms and supportSession services and cross-scene stateScenes and gameplayActor communication (hi.actors)Game-facing refsSave / replication wire versionCoordinate space and camera conventionsRenderingRenderer architecture mapFrame governorGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)UI and editorEditor asset hot reloadEditor Project Selector
Language reference2
OverviewAkari language referenceKawa language reference
Engine overview
Start exploring
  • No matching sections. Try fewer words or another topic.
NavigateEnter Openesc Close
Overview
Tutorials16
OverviewFirst game projectFirst entityAuthored user_data and the inspectorFirst mesh and materialFirst physics body and triggerFirst character controllerFirst session servicesFirst UIFirst input actionFirst messagesPlay, Edit, and scenesFirst runtime spawnFirst motionFirst skeletal animationAssets in Play (soft refs and hot reload)Dynamic editor recompile
Guides16
OverviewDevelopment guideGameplay APIChoosing component storageBuild and packagingProject filePluginsHikari Plugin APIData-driven content, JSON, and pathsScripting with KawaShader authoringTime of dayUser interfaceUI layoutUI widgetsMigration from Unity / UnrealActor and component lifecycle
Systems28
OverviewArchitectureApplication lifecycleFrontends and driversPlatforms and supportSession services and cross-scene stateScenes and gameplayActor communication (hi.actors)Game-facing refsSave / replication wire versionCoordinate space and camera conventionsRenderingRenderer architecture mapFrame governorGPU particlesVisual ZonesVolumetric mediaInputAudioPhysicsMotion KitTemporal KitAssets and ShinraPrefabsAsset residencyAsset formats (Shinra pipeline)UI and editorEditor asset hot reloadEditor Project Selector
Language reference2
OverviewAkari language referenceKawa language reference
Engine overview
Systems4 min read

Coordinate space and camera conventions

On this page
On this pageWhy this setWorld axesCamera and gameplayEuler angles (degrees)QuaternionsUnitsProjection and clip spacevs other engines Back to top

Engine standard (unreleased; no +Z-forward or non-reverse-Z path):

PropertyChoice
HandednessRight-handed (+X × +Y = +Z)
Up+Y
Forward−Z (identity camera looks down −Z)
Matrix storageColumn-major
Clip / depthReverse-Z (NDC: near → 1, far → 0; infinite-far perspective preferred)

This matches glTF / classic GL math (right-handed, Y-up, −Z forward), plus reverse-Z depth as used in contemporary high-end renderers. It is not left-handed +Z-forward, and it is not Z-up.

Source of truth: src/hikari/src/math/, scene/camera.zig, sdk/src/camera_rig.zig, projection consumers, depth/Hi-Z paths.

Why this set

  1. RH Y-up −Z forward — Object +X, view-right, and lookAt’s X axis coincide at identity. No separate “view-right = −local X” story.
  2. glTF / DCC alignment — Assets and tools already speak RH Y-up; camera space matches OpenGL-style −Z view.
  3. Reverse-Z — Best depth precision for large far / outdoor scales with 24–32-bit depth; pairs naturally with an infinite-far projection.
  4. Rejected alternatives — left-handed +Z-forward keeps glTF awkward; Z-up forces constant axis remaps; RH +Z forward would force view-right ≠ local +X.

World axes

AxisDirection
+XRight (math_vector.right) — also view/screen right for an identity camera
+YUp
−ZForward (identity camera look direction)
+ZBackward

Right-handed: +X × +Y = +Z (so forward −Z is “into the screen” in the usual GL view diagram).

Camera and gameplay

Important

An identity camera looks along local −Z. To look toward the origin with identity rotation, place it on +Z; a camera on −Z would look away from the origin.

  • Identity orientation: local +X right, +Y up, −Z forward.
  • Camera.getRight / Actor.get_right / FlyCamera.right = rotated local +X (same as cross(forward, up) when forward is the look direction).
  • getForward / look direction = rotated −Z (math_vector.forward).
  • Ground move basis: yaw about +Y; at yaw 0, forward is (0,0,−1), right is (1,0,0).
  • Camera frustum gizmos (editor overlay) place near/far on local −Z.
  • Look controllers store pitch/yaw degrees as source of truth (FlyCamera, CameraRig, play-mode camera_controller.kawa) and derive the quaternion. Do not round-trip toEuler every look frame — near the pitch clamp that is ill-conditioned in f32.

Euler angles (degrees)

Triples are (pitch, yaw, roll) in degrees, composition on column vectors:

text
R = Ry(yaw) · Rx(pitch) · Rz(roll)
q = qy · qx · qz
ComponentAxisPositive sense (RH, facing −Z)
pitch+XLook up
yaw+YTurn left (CCW from above)
roll+ZBank around the view axis

Yaw-first ordering is what makes this usable for cameras:

  • Yaw is full-range. toEuler reports yaw over (−180°, 180°]; only pitch is limited to [−90°, 90°].
  • Gimbal lock sits at the poles (pitch ±90°), which look controllers already clamp away from.
  • Roll does not steer. Because roll is innermost, it rotates about the local forward axis, so banking never changes where a camera or light points.

That last pair is load-bearing. FlyCamera.look and Actor.look both round-trip through toEuler, clamp pitch, force roll to 0, and rebuild — an order with yaw in the middle turns every |yaw| > 90° into roll = ±180°, and clearing that roll flips the view upside down.

fromEuler / toEuler must stay inverses. CameraRig.Look / mouse deltas use gameplay sense (turn right / look up) and convert into these euler values.

Quaternions

The runtime type is { w, x, y, z } — Hamilton, scalar-first (math/quaternion.zig).

This is the minority layout in the wider ecosystem: glTF and most DCC/engine formats serialise xyzw scalar-last, and so does the cooked model format (ImportNode.rotation in shinra/src/import/mod.rs, and skeletal animation keyframes). Anything crossing that boundary must swizzle. Scene assets are unaffected — they store rotation_euler degrees, not quaternions.

Rotating a vector uses local axes as columns of toMatrix, so rotateVector(q, forward) is the look direction.

Units

QuantityUnit
Distancemetres (1 world unit = 1 m, matching glTF)
Timeseconds
Masskilograms
Anglesradians everywhere except euler triples and authored/inspector fields, which are degrees

Physics assumes this: tenkai's default gravity is -9.81 on +Y. Authoring content at a different scale silently changes how everything falls, how character motors tune, and how attenuation ranges read.

Projection and clip space

  • CPU builds reverse-Z perspective (finite or infinite far) with NDC z already in [0, 1] (near → 1, far → 0). remap_clip_z is identity.
  • After projection, larger depth buffer values are closer. Depth tests use greater. Clear depth / empty shadow atlas to 0.
  • Metal and D3D12 share the same CPU matrices (no GL −1…+1 remap).
  • Linear G-buffer / Hi-Z depth (meters, −view.z) keeps min=nearer, max=farther. Hardware-depth consumers use reverse-Z ordering.

vs other engines

HikariUnityGodot 4Unreal
HandednessRightLeftRightLeft
Up+Y+Y+Y+Z
Forward−Z+Z−Z+X
DepthReverse-ZVariesTypically GL-styleReverse-Z (modern)
PreviousSave / replication wire versionNext Rendering

Documentation follows the current engine checkout.

Snapshot cc148c75Source docs/systems/coordinate-space.md
On this pageWhy this setWorld axesCamera and gameplayEuler angles (degrees)QuaternionsUnitsProjection and clip spacevs other engines Back to top