tiramisu/asset
Asset Management System - loading and caching for textures, models, and audio.
Provides declarative asset loading with progress tracking, caching, and batch loading capabilities with LRU eviction.
Quick Example
import tiramisu/asset
// Load a texture
let load_effect = asset.load_texture("player.png")
|> promise.map(fn(result) {
case result {
Ok(texture) -> TextureLoaded(texture)
Error(err) -> LoadFailed(err)
}
})
|> effect.from_promise
// Use with cache
let cache = asset.new_cache()
let cache = asset.insert_texture(cache, "player.png", texture)
let texture = asset.get_texture(cache, "player.png")
Types
Asset cache/registry with LRU eviction
pub opaque type AssetCache
Asset loading error
pub type AssetError {
AssetLoadError(url: String, reason: String)
AssetNotFound(url: String)
InvalidAssetType(url: String)
}
Constructors
-
AssetLoadError(url: String, reason: String) -
AssetNotFound(url: String) -
InvalidAssetType(url: String)
Types of asset that can be loaded
pub type AssetType {
ModelAsset(url: String)
TextureAsset(url: String)
AudioAsset(url: String)
STLAsset(url: String)
OBJAsset(obj_url: String, mtl_url: option.Option(String))
FBXAsset(url: String, texture_path: option.Option(String))
FontAsset(url: String)
}
Constructors
-
ModelAsset(url: String)GLTF/GLB 3D model
-
TextureAsset(url: String)Texture image (PNG, JPG, etc.)
-
AudioAsset(url: String)Audio file (MP3, WAV, OGG)
-
STLAsset(url: String)STL 3D model
-
OBJAsset(obj_url: String, mtl_url: option.Option(String))OBJ 3D model with optional MTL material file
Supports loading Wavefront OBJ models with their associated MTL material files. The loader automatically:
- Loads diffuse color maps (map_Kd)
- Loads normal maps (map_bump) for surface detail
- Loads ambient occlusion maps (map_Ka) for realistic shadows
- Centers the model at origin
- Computes vertex normals if missing
MTL files can include texture paths with options (e.g., “map_bump -bm 1 texture.jpg”), which are properly parsed. Textures are assumed to be in the same directory as the MTL file.
-
FBXAsset(url: String, texture_path: option.Option(String))FBX 3D model with animations
Supports loading Autodesk FBX models with embedded animations and materials. The FBX loader automatically:
- Loads embedded textures and materials
- Loads skeletal animations
- Loads morph target animations
- Computes vertex normals if missing
- Handles both ASCII and binary FBX formats
FBX files can contain multiple animations, which are returned as AnimationClips that can be used with the animation system.
Texture Path: If textures are in a different directory than the FBX file, provide the
texture_pathto tell the loader where to find them. For example:- FBX: “assets/PSX_Dungeon/Models/Door.fbx”
- Textures: “assets/PSX_Dungeon/Textures/”
- Use:
FBXAsset(url: "...", texture_path: Some("assets/PSX_Dungeon/Textures/"))
-
FontAsset(url: String)Font for TextGeometry (typeface.json format)
Fonts must be in Three.js typeface.json format. You can convert TTF/OTF fonts using the facetype.js converter or download pre-converted fonts from the Three.js repository (examples/fonts/).
Result of batch loading
pub type BatchLoadResult {
BatchLoadResult(cache: AssetCache, errors: List(AssetError))
}
Constructors
-
BatchLoadResult(cache: AssetCache, errors: List(AssetError))
Opaque type for Three.js BufferGeometry.
Created by loading 3D models with asset.load_stl() or asset.load_model().
pub type BufferGeometry
Asset cache configuration
pub type CacheConfig {
CacheConfig(max_size: Int, current_time: Int)
}
Constructors
-
CacheConfig(max_size: Int, current_time: Int)
pub type FBXData {
FBXData(
scene: object3d.Object3D,
animations: List(object3d.AnimationClip),
)
}
Constructors
-
FBXData( scene: object3d.Object3D, animations: List(object3d.AnimationClip), )
Opaque type for Three.js Font (for TextGeometry).
Created via asset.load_font() and used in text geometries.
Fonts must be in typeface.json format.
pub type Font
pub type GLTFData {
GLTFData(
scene: object3d.Object3D,
animations: List(object3d.AnimationClip),
)
}
Constructors
-
GLTFData( scene: object3d.Object3D, animations: List(object3d.AnimationClip), )
STL loading error
pub type LoadError {
LoadError(String)
InvalidUrl(String)
ParseError(String)
}
Constructors
-
LoadError(String) -
InvalidUrl(String) -
ParseError(String)
Progress information for batch loading
pub type LoadProgress {
LoadProgress(loaded: Int, total: Int, current_url: String)
}
Constructors
-
LoadProgress(loaded: Int, total: Int, current_url: String)
A loaded asset (opaque to enforce type safety)
pub opaque type LoadedAsset
Opaque type for Three.js textures.
Created via asset.load_texture() and used in materials.
pub type Texture
Texture filtering mode
Controls how textures are sampled when they’re displayed at different sizes.
pub type TextureFilter {
LinearFilter
NearestFilter
}
Constructors
-
LinearFilterLinear filtering - smooth, blurred appearance (default in Three.js) Good for realistic graphics and smooth gradients
-
NearestFilterNearest filtering - crisp, pixelated appearance Perfect for pixel art, low-poly aesthetics, and retro games
Values
pub fn apply_texture_to_object(
object: object3d.Object3D,
texture: Texture,
filter: TextureFilter,
) -> Nil
Apply a texture to all materials in a loaded 3D model
pub fn clone_object3d(
object: object3d.Object3D,
) -> object3d.Object3D
Clone an Object3D for reuse in multiple scene locations
When you need to place the same model in multiple locations, you must clone it. Three.js doesn’t allow the same Object3D to exist in multiple places in the scene graph.
Example
import tiramisu/asset
let assert Ok(fbx_data) = asset.get_fbx(cache, "models/tree.fbx")
// Create multiple instances of the tree
let tree1 = fbx_data.scene
let tree2 = asset.clone_object3d(fbx_data.scene)
let tree3 = asset.clone_object3d(fbx_data.scene)
pub fn dispose_geometry(geometry: BufferGeometry) -> Nil
Dispose of a geometry and free GPU memory
pub fn dispose_object3d(object: object3d.Object3D) -> Nil
Dispose of an Object3D and all its resources (geometry, materials, textures, children)
pub fn dispose_texture(texture: Texture) -> Nil
Dispose of a texture and free GPU memory
pub fn get(
cache: AssetCache,
url: String,
) -> Result(LoadedAsset, AssetError)
Try to get any asset
pub fn get_audio(
cache: AssetCache,
url: String,
) -> Result(audio.AudioBuffer, AssetError)
Get an audio buffer from the cache
pub fn get_fbx(
cache: AssetCache,
url: String,
) -> Result(FBXData, AssetError)
Get an FBX model from the cache
Returns the loaded FBX model data including the scene object and animations. FBX files can contain:
- Skeletal animations for character animation
- Morph target animations
- Embedded textures and materials
- Multiple mesh objects in a scene hierarchy
Example
let assert Ok(character_data) = asset.get_fbx(cache, "models/character.fbx")
scene.Model3D(
id: "character",
object: character_data.scene,
transform: transform.identity,
animation: option.Some(
animation.state_machine(character_data.animations)
),
physics: option.None,
)
pub fn get_fbx_scene(
cache: AssetCache,
url: String,
) -> Result(object3d.Object3D, AssetError)
Get the scene object from a cached FBX model
pub fn get_model(
cache: AssetCache,
url: String,
) -> Result(GLTFData, AssetError)
Get a GLTF model from the cache (updates LRU timestamp)
pub fn get_model_scene(
cache: AssetCache,
url: String,
) -> Result(object3d.Object3D, AssetError)
Get the scene object from a cached GLTF model
pub fn get_obj(
cache: AssetCache,
url: String,
) -> Result(object3d.Object3D, AssetError)
Get an OBJ model from the cache
Returns the loaded OBJ model as an Object3D. The model will have:
- Materials with textures applied (if MTL file was loaded)
- Vertex normals computed
- Center position at origin
Example
let assert Ok(bread_model) = asset.get_obj(cache, "models/bread.obj")
scene.Model3D(
id: "bread",
object: bread_model,
transform: transform.identity,
animation: option.None,
physics: option.None,
)
pub fn get_stl(
cache: AssetCache,
url: String,
) -> Result(BufferGeometry, AssetError)
Get an STL geometry from the cache
pub fn get_texture(
cache: AssetCache,
url: String,
) -> Result(Texture, AssetError)
Get a texture from the cache
pub fn insert_asset(
cache: AssetCache,
url: String,
asset: LoadedAsset,
) -> AssetCache
Insert a loaded asset into the cache manually If cache exceeds max_size, evicts least recently used asset
pub fn load_asset(
asset: AssetType,
) -> promise.Promise(Result(LoadedAsset, AssetError))
Load a single asset
pub fn load_audio(
url: String,
) -> promise.Promise(Result(audio.AudioBuffer, LoadError))
Load an audio file from a URL using Promises
Supports common audio formats including MP3, WAV, and OGG. Returns an AudioBuffer that can be used with the audio system.
Example
import tiramisu/asset
import gleam/javascript/promise
let load_effect = asset.load_audio("sounds/jump.mp3")
|> promise.map(fn(result) {
case result {
Ok(audio_buffer) -> AudioLoaded(audio_buffer)
Error(err) -> LoadFailed(err)
}
})
pub fn load_batch(
asset: List(AssetType),
on_progress: fn(LoadProgress) -> Nil,
) -> promise.Promise(BatchLoadResult)
Load multiple asset with progress tracking Returns a promise that resolves with the loaded asset and any errors
pub fn load_batch_simple(
asset: List(AssetType),
) -> promise.Promise(BatchLoadResult)
Load multiple asset without progress tracking
pub fn load_fbx(
url: String,
texture_path: String,
) -> promise.Promise(Result(FBXData, LoadError))
Load an FBX file with animations
Loads a 3D model in FBX format with full animation and material support. The loader handles:
- Skeletal Animations: Bone-based character animations
- Morph Target Animations: Vertex-based shape animations
- Embedded Textures: Textures embedded in the FBX file
- Materials: PBR and standard materials with properties
- Scene Hierarchy: Complex object hierarchies preserved
- Both Formats: ASCII and binary FBX files
Parameters
url: Path to the FBX filetexture_path: Optional path to texture directory (if textures are separate from FBX)
Returns
A Promise that resolves to:
Ok(FBXData): Loaded model with scene object and animation clipsError(LoadError): File not foundError(InvalidUrl): Invalid URL providedError(ParseError): Failed to parse FBX file
Example
import tiramisu/asset
import gleam/javascript/promise
import gleam/option
// FBX with textures in same directory
let load_effect = asset.load_fbx("models/character.fbx", "")
|> promise.map(fn(result) {
case result {
Ok(fbx_data) -> ModelLoaded(fbx_data)
Error(err) -> LoadFailed(err)
}
})
// FBX with textures in different directory
let load_effect = asset.load_fbx(
"assets/PSX_Dungeon/Models/Door.fbx",
"assets/PSX_Dungeon/Textures/"
)
pub fn load_font(
url: String,
) -> promise.Promise(Result(Font, LoadError))
Load a font file (typeface.json format) for use with TextGeometry.
Three.js fonts must be in typeface.json format. You can:
- Download pre-converted fonts from Three.js repository (examples/fonts/)
- Convert TTF/OTF fonts using facetype.js converter
Example
import gleam/javascript/promise
import tiramisu/asset
let load_effect = asset.load_font("fonts/helvetiker_regular.typeface.json")
|> promise.map(fn(result) {
case result {
Ok(font) -> FontLoaded(font)
Error(err) -> LoadFailed(err)
}
})
Returns
A Promise that resolves to:
Ok(Font): Loaded font ready for TextGeometryError(LoadError): File not foundError(InvalidUrl): Invalid URL providedError(ParseError): Failed to parse font file
pub fn load_gltf(
url: String,
) -> promise.Promise(Result(GLTFData, LoadError))
Load a GLTF/GLB file from a URL using Promises
pub fn load_obj(
obj_url obj_url: String,
mtl_url mtl_url: String,
) -> promise.Promise(Result(object3d.Object3D, LoadError))
Load a Wavefront OBJ file with optional MTL materials
Loads a 3D model in OBJ format with full material and texture support. The loader handles:
- Diffuse/Color Maps (map_Kd): Base color textures
- Normal Maps (map_bump): Surface detail and lighting
- Ambient Occlusion Maps (map_Ka): Contact shadows and depth
- Vertex Normals: Computed automatically if missing
- Model Centering: Centers the model at origin
Textures are loaded from the same directory as the MTL file. The loader
properly parses MTL texture paths with options like map_bump -bm 1 normal.jpg.
Parameters
obj_url: Path to the OBJ filemtl_url: Path to the MTL file, or empty string""for no materials
Returns
A Promise that resolves to:
Ok(Object3D): Loaded model with materials and texturesError(LoadError): File not foundError(InvalidUrl): Invalid URL providedError(ParseError): Failed to parse OBJ/MTL file
pub fn load_stl(
url: String,
) -> promise.Promise(Result(BufferGeometry, LoadError))
Load an STL file from a URL using Promises
pub fn load_texture(
url: String,
) -> promise.Promise(Result(Texture, LoadError))
Load a texture from a URL using Promises
pub fn new_cache() -> AssetCache
Create a new empty asset cache with default max size (100 asset)
pub fn new_cache_with_size(max_size: Int) -> AssetCache
Create a new empty asset cache with custom max size
pub fn set_texture_filter(
texture: Texture,
filter: TextureFilter,
) -> Nil
Set the filtering mode for a texture