Spatial is licensed under the PolyForm Shield License 1.0.0.
You may embed Spatial in your own applications โ including commercial apps โ free of charge, modify it for that purpose, and redistribute it with your application, as long as you keep the required copyright and license notices.
You may not copy, fork, or rebrand this codebase to publish a competing 3D library, SDK, or practical substitute for Spatial, and you may not remove or obscure authorship.
Copyright ยฉ 2024โ2026 Daniel Imbert (danielitoCode). See LICENSE and NOTICE for the full terms.
Spatial is a modern declarative 3D rendering library for Android inspired by Jetpack Compose.
Its goal is to make 3D scene creation feel as natural and expressive as Compose, while completely hiding the complexity of OpenGL and GPU pipelines from the developer.
For a more detailed explanation: https://deepwiki.com/danielitoCode/Spatial
Spatial is not intended to become a full game engine.
Instead, it focuses on:
- Declarative scene composition
- Smooth cinematic motion
- State-driven rendering
- Compose-first APIs
- Natural gestures
- Modular rendering architecture
- Clean GPU abstraction
Core #1 exposes its public Compose API from the root com.elitec.spatial_compose package.
For Pilar 1, application and playground consumers should depend on :spatial-compose as the public facade for scene authoring. Load GLB assets with Element.Model(model = ModelResource.fromRawResource(R.raw.my_model), ...); spatial-compose delegates parsing internally, so consumers should not depend directly on :spatial-geometry unless they are building a dedicated diagnostic parser screen.
Material changes for rendered primitives or GLB models should be expressed through Modifier3D.color(...) for simple flat colors or Modifier3D.material(...) when a caller needs to pass the public material data object. The :spatial-material module is reserved for the material implementation and future texture/shader metadata APIs; apps should add implementation(project(":spatial-material")) only after a deliberate public material API is exposed from that module.
Core #1 remains In Development. This status must only change when the Core #1 contracts and tests are closed and passing against the real public API. Until then, README badges, phase notes, and release messaging must not describe Core #1 as complete or stable.
- Essential 3D primitives
- Orbit camera
- Smooth zoom
- Inertia and damping
- Declarative scene API
- Basic camera/transform motion system
- Gesture system
- Flat-color material rendering (no active lighting/shading in Core #1)
- Material abstraction
- Units system
- GPU abstraction layer
- Compose integration
- Physics
- ECS
- PBR
- Shadows
- Real lighting and shaded light evaluation
- Vulkan
- Skeletal animation
- Post-processing
- Advanced animation timelines and clip sequencing
- Multiplayer systems
- Editor tooling
These items are explicitly outside the Core #1 scope and must not be pulled into Core #1 API, renderer, or test commitments:
- PBR
- Shadows
- Active lights in shaders
- Object animation
- External model loading
- Advanced picking
Core #1 keeps lighting as contracts only. LightData exists so scene, light, and future renderer modules can agree on shape, direction, color, and intensity metadata, but Core #1 does not transport lights through the render frame and does not evaluate real lighting in shaders.
The active Core #1 renderer supports flat-color materials: the material color is passed directly to the shader without directional, ambient, point, or physically based light contribution.
Spatial follows a strict design philosophy:
Scenes describe state.
State changes update rendering automatically.
Inspired by Compose mental models and APIs.
Motion quality matters more than feature quantity.
Good defaults and minimal boilerplate.
Core #1 exposes its stable public Compose API from the root com.elitec.spatial_compose package. Implementation packages remain split internally, but application code should prefer these root imports.
import com.elitec.spatial_compose.CameraState
import com.elitec.spatial_compose.Element
import com.elitec.spatial_compose.GestureSensitivity
import com.elitec.spatial_compose.Gestures
import com.elitec.spatial_compose.Modifier3D
import com.elitec.spatial_compose.MotionSpec
import com.elitec.spatial_compose.Scene
import com.elitec.spatial_compose.SceneGestures
import com.elitec.spatial_compose.rememberCameraStateA real Android render host is supplied by the runtime adapter:
import com.elitec.spatial_compose_runtime_adapter.DefaultSceneRenderHostFactoryimport androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.elitec.spatial_compose.Element
import com.elitec.spatial_compose.Gestures
import com.elitec.spatial_compose.Modifier3D
import com.elitec.spatial_compose.Scene
import com.elitec.spatial_compose_runtime_adapter.DefaultSceneRenderHostFactory
import com.elitec.spatial_units.deg
import com.elitec.spatial_compose.rememberCameraState
import com.elitec.spatial_units.meters
@Composable
fun CoreOneScene() {
val cameraState = rememberCameraState(
yaw = 20f.deg,
pitch = (-12f).deg,
zoom = 1.25f,
)
Scene(
modifier = Modifier.fillMaxSize(),
renderHostFactory = DefaultSceneRenderHostFactory,
cameraState = cameraState,
gestures = Gestures.orbitAndZoom(),
) {
Element.Cube(
modifier = Modifier3D.Default
.size(2f.meters)
.position(0f.meters, 0f.meters, (-5f).meters),
)
Element.Sphere(
modifier = Modifier3D.Default
.size(1f.meters)
.position(3f.meters, 0f.meters, (-8f).meters),
)
}
}Spatial uses a hybrid architecture:
The architecture prioritizes:
- Ownership boundaries
- Module independence
- Rendering performance
- Scalability
- Low coupling
- Maintainability
Spatial avoids unnecessary enterprise abstractions such as:
- Excessive repositories
- DTO overengineering
- Artificial use cases
- Massive inheritance hierarchies
The old monolithic Scene3D responsibility is now documented as a thin public facade plus internal feature slices:
components/Scene.ktowns the ComposeScenecomposable, Android view hosting, render-host lifecycle, gesture modifier wiring, scene graph collection, and frame submission.scene/*owns scene graph construction and conversion:SceneBuilder,SceneContentScope,SceneNode, gesture configuration, render host contracts, graph remembering, and renderable-node adapters.modifier/*ownsModifier3D, gesture input modifiers, and conversion from declarative transforms to model matrices.state/*ownsCameraStateandrememberCameraState.core/Element.ktowns the primitive element facade (Element.Cube,Element.Sphere, andElement.Plane).Scene3D.ktremains the root-package public API facade that re-exports the stable Core #1 symbols fromcom.elitec.spatial_compose.
spatial/
โ
โโโ app/
โ
โโโ spatial-renderer/
โโโ spatial-scene/
โโโ spatial-camera/
โโโ spatial-motion/
โโโ spatial-gesture/
โโโ spatial-material/
โโโ spatial-geometry/
โโโ spatial-light/
โโโ spatial-math/
โโโ spatial-units/
โโโ spatial-compose/
โโโ spatial-core/
Android Application
Playground and showcase application.
Used for:
- Rendering validation
- Gesture testing
- Motion tuning
- FPS monitoring
- Demo scenes
- Visual experimentation
Android Library
Shared Core #1 motion primitives for basic camera and transform animation.
- Basic camera/transform interpolation
- Shared easing curves
- Shared camera animation duration planning
- Runtime/Compose motion parity helpers
- Skeletal animation
- Advanced keyframe timelines
- Clip blending and sequencer-style orchestration
renderer/
โโโ shader/
โโโ pipeline/
โโโ buffer/
โโโ texture/
โโโ framebuffer/
โโโ renderloop/
โโโ context/
Kotlin Library
Scene graph and hierarchical structure.
- Node hierarchy
- Transform propagation
- Traversal
- Visibility management
- Dirty flags
- Parent-child relationships
Kotlin Library
Camera behavior and cinematic motion.
- Orbit camera
- Pan
- Zoom
- Damping
- Inertia
- Smooth transitions
- Projection systems
camera/
โโโ orbit/
โโโ zoom/
โโโ inertia/
โโโ interpolation/
โโโ projection/
Kotlin Library
Animation and motion engine.
- Animation timelines
- Interpolation
- Spring systems
- Easing
- Transitions
- Motion orchestration
Android Library
Touch and gesture input system.
- Multi-touch
- Pinch zoom
- Orbit gestures
- Velocity tracking
- Gesture smoothing
- MotionEvent handling
Kotlin Library
Material abstraction layer.
- Flat-color materials for Core #1
- Texture materials (future)
- Shader metadata (future)
- Material bindings
- Lighting properties as metadata only; active light evaluation is outside Core #1
Kotlin Library
Mesh and primitive generation.
- Cube generation
- Sphere generation
- Cylinder generation
- Plane generation
- Mesh data
- Normals
- UV coordinates
Kotlin Library
Lighting models.
- Light contracts and helper factories
- Directional light metadata
- Light intensity metadata
- Light direction metadata
- Active lighting in shaders
- Shaded material evaluation
- Shadows
Kotlin Library
Pure mathematical foundation.
- Vec2
- Vec3
- Vec4
- Quaternion
- Matrix4
- Projection math
This module must remain:
- Lightweight
- Pure Kotlin
- Allocation-friendly
- Dependency-free
Kotlin Library
Consistent spatial units system.
- Meters
- Centimeters
- Degrees
- Unit conversions
- Spatial consistency
1.meters
45.deg
50.cmAndroid Library
Declarative Compose integration layer.
- Scene composables
- Element composables
- Modifier3D
- remember states
- Compose adapters
This module does NOT render directly.
It orchestrates:
- state
- composition
- declarative APIs
Kotlin Library
Core orchestration and public contracts.
- Public APIs
- Module orchestration
- Shared contracts
- Engine coordination
Compose
โ
Core
โ
Scene
โ
Renderer
Rules:
- High-level modules never depend on UI.
- Renderer never knows Compose.
- Scene never knows Android.
- Math remains framework-independent.
Spatial is developed using a parallel playground application.
Modify renderer
โ
Run playground
โ
Validate motion
โ
Tune gestures
โ
Refactor APIs
โ
Repeat
The playground app acts as:
- Rendering sandbox
- Motion laboratory
- Camera tuning environment
- FPS validator
- Material previewer
- Demo showcase
- Kotlin
- OpenGL ES 3.0+
- Jetpack Compose
- Coroutines
- Gradle Kotlin DSL
Recommended:
- Koin (limited usage)
Use DI ONLY for:
- Renderer services
- Shader registries
- Texture caches
- Motion orchestrators
Avoid DI for:
- Vec3
- Matrix4
- Geometry
- Units
- Transforms
Spatial avoids arbitrary floats whenever possible.
Example:
Modifier3D
.size(2.meters)
.rotateY(45.deg)This improves:
- readability
- spatial consistency
- API ergonomics
Motion quality is one of Spatial's highest priorities.
Core #1 focuses heavily on:
- smooth orbit camera
- cinematic transitions
- natural zoom
- inertia
- damping
- interpolation
The renderer should feel premium even with simple cubes.
Rendering foundations:
- EGL
- OpenGL setup
- Triangle rendering
- Render loop
Math engine:
- Vec3
- Matrix4
- Quaternion
Camera system:
- Orbit
- Zoom
- Inertia
- Gestures
Scene graph:
- Nodes
- Hierarchy
- Traversal
Geometry:
- Cube
- Sphere
- Plane
- Cylinder
Materials:
- Solid materials
- Texture materials
- Basic lighting
Compose DSL:
- Scene
- Element
- Modifier3D
Basic motion system:
- animateTo for camera/transform changes
- interpolation
-
- shared easing/duration planning
Advanced timelines, skeletal animation, and clip sequencing are intentionally outside Core #1.
Polish:
- smooth gestures
- frame pacing
- shader caching
- lifecycle cleanup
Showcase playground.
Core #1 is complete when:
- Primitives render correctly
- Camera feels cinematic
- Zoom feels smooth
- Gestures feel natural
- Motion transitions work
- Compose integration works
- API feels elegant
- 60 FPS remain stable
- OpenGL complexity stays hidden
Potential future expansions:
- glTF loading
- PBR
- Real lighting and shaded light evaluation
- Shadows
- Vulkan backend
- Compose Multiplatform
- Spatial UI
- Physics integration
- WebGPU backend
Less GPU complexity. More declarative intent.
Built for modern Android graphics experimentation.
License: PolyForm Shield 1.0.0 ยท ยฉ 2024โ2026 Daniel Imbert (danielitoCode)
