tiramisu/geometry

3D geometry primitives and custom geometry loading.

This module provides validated constructors for common 3D shapes used in game development. All constructors return Result types to ensure valid geometry parameters at compile time.

Primitive Shapes

// Box with Vec3 size (width, height, depth)
let assert Ok(cube) = geometry.box(size: vec3.Vec3(1.0, 1.0, 1.0))

// Sphere with radius and segment counts
let assert Ok(ball) = geometry.sphere(radius: 1.0, segments: vec2.Vec2(32, 16))

// Plane with Vec2 size (width, height)
let assert Ok(floor) = geometry.plane(size: vec2.Vec2(10.0, 10.0))

Loading External Geometry

Load STL files for custom 3D models:

let load_model = geometry.load_stl(
  from: "models/part.stl",
  on_success: ModelLoaded,
  on_error: ModelFailed,
)

3D Text

Create extruded 3D text with loaded fonts:

// First load a font
let load_font = geometry.load_font(
  from: "fonts/helvetica.json",
  on_success: FontLoaded,
  on_error: FontFailed,
)

// Then create text geometry
let assert Ok(text) = geometry.text(
  text: "Hello!",
  font: my_font,
  size: 1.0,
  depth: 0.2,
  // ...
)

Types

pub type CustomGeometry =
  savoiardi.Geometry

3D geometry types supported by the engine.

Each variant represents a different primitive shape or custom geometry. Use the validated constructor functions like box(), sphere(), etc.

pub opaque type Geometry
pub type GeometryError {
  NonPositiveWidth(width: Float)
  NonPositiveHeight(height: Float)
  NonPositiveDepth(depth: Float)
  NonPositiveRadius(radius: Float)
  InvalidGeometryTube(tube: Float)
  LessThanThreeSegmentCountWidth(count: Int)
  LessThanTwoSegmentCountHeight(count: Int)
  NegativeSegmentCount(count: Int)
  EmptyText
  NonPositiveSize(size: Float)
  NegativeBevelThickness(thickness: Float)
  NegativeBevelSize(size: Float)
}

Constructors

  • NonPositiveWidth(width: Float)
  • NonPositiveHeight(height: Float)
  • NonPositiveDepth(depth: Float)
  • NonPositiveRadius(radius: Float)
  • InvalidGeometryTube(tube: Float)
  • LessThanThreeSegmentCountWidth(count: Int)
  • LessThanTwoSegmentCountHeight(count: Int)
  • NegativeSegmentCount(count: Int)
  • EmptyText
  • NonPositiveSize(size: Float)
  • NegativeBevelThickness(thickness: Float)
  • NegativeBevelSize(size: Float)

Values

pub fn box(
  size size: vec3.Vec3(Float),
) -> Result(Geometry, GeometryError)

Create a validated box geometry.

All dimensions must be positive (> 0).

Example

let assert Ok(cube) = geometry.box(size: vec3.Vec3(1.0, 1.0, 1.0))
let assert Ok(wall) = geometry.box(size: vec3.Vec3(10.0, 3.0, 0.1))
pub fn center(
  geometry geometry: savoiardi.Geometry,
) -> savoiardi.Geometry

Centers a geometry around its bounding box center.

This is useful for STL or OBJ models that need to rotate around their geometric center rather than their original origin point.

Many CAD-exported models have their origin at an arbitrary location. Call this function after loading to ensure the model rotates around its visual center.

Example

use result <- promise.await(geometry.load_stl("/models/part.stl"))
case result {
  Ok(geom) -> {
    // Center the geometry so it rotates around its middle
    let centered = geometry.center(geom)
    // Use centered geometry in your mesh...
  }
  Error(Nil) -> // handle error
}
pub fn circle(
  radius radius: Float,
  segments segments: Int,
) -> Result(Geometry, GeometryError)
pub fn cone(
  radius radius: Float,
  height height: Float,
  segments segments: Int,
) -> Result(Geometry, GeometryError)
pub fn custom_geometry(
  geometry geometry: savoiardi.Geometry,
) -> Geometry
pub fn cylinder(
  radius_top radius_top: Float,
  radius_bottom radius_bottom: Float,
  height height: Float,
  radial_segments radial_segments: Int,
) -> Result(Geometry, GeometryError)

Create a validated cylinder geometry.

Both radii must be non-negative, height positive, radial segments >= 3. Set one radius to 0 to create a cone shape.

Example

let assert Ok(cylinder) = scene.cylinder(radius_top: 1.0, radius_bottom: 1.0, height: 2.0, radial_segments: 32)
let assert Ok(cone) = scene.cylinder(radius_top: 0.0, radius_bottom: 1.0, height: 2.0, radial_segments: 32)
pub fn icosahedron(
  radius radius: Float,
  detail detail: Int,
) -> Result(Geometry, GeometryError)

Create a validated icosahedron (20-sided polyhedron) geometry.

Detail level controls subdivision. Good for creating spheres with flat faces.

Example

let assert Ok(shape) = scene.icosahedron(radius: 1.0, detail: 2)
pub fn load_font(
  from url: String,
  on_success on_success: fn(savoiardi.Font) -> msg,
  on_error on_error: msg,
) -> effect.Effect(msg)
pub fn load_stl(
  from url: String,
  on_success on_success: fn(savoiardi.Geometry) -> msg,
  on_error on_error: msg,
) -> effect.Effect(msg)
pub fn plane(
  size size: vec2.Vec2(Float),
) -> Result(Geometry, GeometryError)
pub fn sheet(
  size size: vec2.Vec2(Float),
  segments segments: vec2.Vec2(Int),
) -> Result(Geometry, GeometryError)
pub fn sphere(
  radius radius: Float,
  segments segments: vec2.Vec2(Int),
) -> Result(Geometry, GeometryError)

Create a validated sphere geometry.

Radius must be positive. Width segments >= 3, height segments >= 2. More segments = smoother sphere but more triangles.

Example

let assert Ok(ball) = geometry.sphere(radius: 1.0, segments: vec2.Vec2(32, 16))
let assert Ok(low_poly) = geometry.sphere(radius: 1.0, segments: vec2.Vec2(8, 6))
pub fn tetrahedron(
  radius radius: Float,
  detail detail: Int,
) -> Result(Geometry, GeometryError)

Create a validated tetrahedron (4-sided polyhedron) geometry.

Detail level controls subdivision (0 = no subdivision, higher = more triangles).

Example

let assert Ok(shape) = scene.tetrahedron(radius: 1.0, detail: 0)
pub fn text(
  text text: String,
  font font: savoiardi.Font,
  size size: Float,
  depth depth: Float,
  curve_segments curve_segments: Int,
  bevel_enabled bevel_enabled: Bool,
  bevel_thickness bevel_thickness: Float,
  bevel_size bevel_size: Float,
  bevel_offset bevel_offset: Float,
  bevel_segments bevel_segments: Int,
) -> Result(Geometry, GeometryError)

Create validated 3D text geometry from a loaded font.

Renders text as 3D geometry with optional beveling (rounded edges). Requires a font loaded via geometry.load_font().

Example

import tiramisu/geometry

// After loading font with geometry.load_font()...
let assert Ok(text) = geometry.text(
  text: "Hello!",
  font: my_font,
  size: 1.0,
  depth: 0.2,
  curve_segments: 12,
  bevel_enabled: True,
  bevel_thickness: 0.05,
  bevel_size: 0.02,
  bevel_offset: 0.0,
  bevel_segments: 5,
)
pub fn torus(
  radius radius: Float,
  tube tube: Float,
  radial_segments radial_segments: Int,
  tubular_segments tubular_segments: Int,
) -> Result(Geometry, GeometryError)

Create a validated torus (donut) geometry.

Example

let assert Ok(donut) = scene.torus(radius: 2.0, tube: 0.5, radial_segments: 16, tubular_segments: 100)
Search Document