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
Errors that can occur when working with the asset cache.
pub type AssetError {
AssetLoadError(url: String, reason: String)
AssetNotFound(url: String)
InvalidAssetType(url: String)
}
Constructors
-
AssetLoadError(url: String, reason: String)Failed to load an asset with a specific reason
-
AssetNotFound(url: String)The requested asset was not found in the cache
-
InvalidAssetType(url: String)The cached asset exists but is the wrong type (e.g., requesting a texture when a model is cached)
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().
pub type BufferGeometry
Asset cache configuration.
Controls the maximum number of assets that can be cached before the least recently used asset is evicted.
pub type CacheConfig {
CacheConfig(max_size: Int, current_time: Int)
}
Constructors
-
CacheConfig(max_size: Int, current_time: Int)Maximum number of assets before LRU eviction occurs
Data loaded from an FBX file.
Contains both the 3D scene and any embedded animations.
pub type FBXData {
FBXData(
scene: Object3D,
animations: List(animation.AnimationClip),
)
}
Constructors
-
FBXData( scene: Object3D, animations: List(animation.AnimationClip), )Arguments
- scene
-
The root scene object containing all meshes and materials
- animations
-
List of animation clips found in the FBX file
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
Data loaded from a GLTF/GLB file.
Contains both the 3D scene and any embedded animations.
pub type GLTFData {
GLTFData(
scene: Object3D,
animations: List(animation.AnimationClip),
)
}
Constructors
-
GLTFData( scene: Object3D, animations: List(animation.AnimationClip), )Arguments
- scene
-
The root scene object containing all meshes and materials
- animations
-
List of animation clips found in the GLTF file
Errors that can occur when loading individual assets.
pub type LoadError {
LoadError(String)
InvalidUrl(String)
ParseError(String)
}
Constructors
-
LoadError(String)General loading error with a message
-
InvalidUrl(String)The provided URL was invalid or empty
-
ParseError(String)The asset file could not be parsed
Progress information for batch loading.
Provided to the progress callback during load_batch().
pub type LoadProgress {
LoadProgress(loaded: Int, total: Int, current_url: String)
}
Constructors
-
LoadProgress(loaded: Int, total: Int, current_url: String)Arguments
- loaded
-
Number of assets successfully loaded so far
- total
-
Total number of assets to load
- current_url
-
URL of the asset currently being loaded
A loaded asset (opaque to enforce type safety)
pub opaque type LoadedAsset
Opaque type for Three.js Object3D.
Represents a 3D object loaded from GLTF, FBX, or OBJ files. Can be used in scene nodes or cloned for multiple instances.
pub type Object3D
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,
texture: Texture,
filter: TextureFilter,
) -> Nil
Apply a texture to all materials in a loaded 3D model
pub fn cache_size(cache: AssetCache) -> Int
Get the number of assets currently in the cache.
Example
let cache = asset.new_cache()
// ... load some assets
let count = asset.cache_size(cache) // => 5
pub fn clear_cache(cache: AssetCache) -> AssetCache
Clear all cached assets.
This removes all assets from the cache but preserves the cache configuration. Useful for level transitions or when you need to free memory.
Example
// When transitioning to a new level
fn load_new_level(model: Model) {
let cleared_cache = asset.clear_cache(model.assets)
Model(..model, assets: cleared_cache)
}
pub fn clone_object3d(object: 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 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, 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, AssetError)
Get the scene object from a cached GLTF model
pub fn get_obj(
cache: AssetCache,
url: String,
) -> Result(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 is_cached(cache: AssetCache, url: String) -> Bool
Check if a specific asset is cached.
Example
case asset.is_cached(cache, "textures/player.png") {
True -> {
// Asset is cached, get it immediately
let assert Ok(texture) = asset.get_texture(cache, "textures/player.png")
use_texture(texture)
}
False -> {
// Need to load the asset first
load_and_cache_texture("textures/player.png")
}
}
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, 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.
The default maximum size is 100 assets. When this limit is exceeded, the least recently used asset is automatically evicted.
Example
import tiramisu/asset
let cache = asset.new_cache()
// Load and cache assets...
pub fn new_cache_with_size(max_size: Int) -> AssetCache
Create a new empty asset cache with a custom maximum size.
The max_size is the number of assets to cache before LRU eviction occurs.
Example
// Create a larger cache for games with many assets
let cache = asset.new_cache_with_size(500)
// Or a smaller cache for memory-constrained environments
let cache = asset.new_cache_with_size(20)
pub fn set_texture_filter(
texture: Texture,
filter: TextureFilter,
) -> Nil
Set the filtering mode for a texture