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_path to 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

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

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

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

  • LinearFilter

    Linear filtering - smooth, blurred appearance (default in Three.js) Good for realistic graphics and smooth gradients

  • NearestFilter

    Nearest 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 cache_size(cache: AssetCache) -> Int

Get the number of cached asset

pub fn cached_urls(cache: AssetCache) -> List(String)

Get all cached URLs

pub fn clear_cache(cache: AssetCache) -> AssetCache

Clear all cached asset

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 is_cached(cache: AssetCache, url: String) -> Bool

Check if an asset is cached

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 file
  • texture_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 clips
  • Error(LoadError): File not found
  • Error(InvalidUrl): Invalid URL provided
  • Error(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 TextGeometry
  • Error(LoadError): File not found
  • Error(InvalidUrl): Invalid URL provided
  • Error(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 file
  • mtl_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 textures
  • Error(LoadError): File not found
  • Error(InvalidUrl): Invalid URL provided
  • Error(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

Search Document