DatumHuePlatform v0.0.24datumhue.com
Contents

handle18 methods, 11 fields

DrawPrimitive

A single drawable on a DrawCanvas, returned by the primitive constructors and canvas:body. Methods update geometry, color, rotation/scale, visibility, or attach physics.

Obtained from
datumhue.physics.raycast, datumhue.physics.raycast_all, datumhue.physics.point_query, datumhue.physics.shapecast, datumhue.draw.text_span, DrawCanvas:rect, DrawCanvas:circle, DrawCanvas:ellipse and 19 more
Accepted by
datumhue.physics.add_joint, datumhue.physics.raycast, datumhue.physics.raycast_all, datumhue.physics.point_query, datumhue.physics.shapecast, SpriteClips:bind, DrawCanvas:text, DrawCanvas:group and 5 more

The examples on this page start from:

lua
local vec2 = datumhue.math.vec2
local color = datumhue.color
local canvas = datumhue.draw.new({ width = 320, height = 240 })
canvas:mount({ width = 320, height = 240 })
local prim = canvas:circle({ radius = 20, color = color("#a7c080") })

Fields 11

FieldTypeAccessDescription
visiblebooleanread/writeWhether the primitive is shown (propagates to children).
opacitynumberread/writeAlpha 0.0-1.0 (propagates to children).
velocityVec3?read/writeLinear velocity (assign a vec2/vec3), or nil if the handle has no physics body.
angular_velocitynumber?read/writeAngular velocity in radians/sec about Z, or nil if the handle has no physics body. Assign a number.
posVec3?read/writePosition relative to the parent (assign a vec2/vec3); a physics body follows at the next physics step. nil once removed.
rotationnumber?read/writeRotation in radians about Z, relative to the parent, or nil once the primitive is removed. Assign a number; a physics body follows at the next physics step.
restitutionnumber?read/writeBounciness, 0 or more (0 absorbs an impact, 1 keeps all its energy); nil if the handle has no physics body. Assign a number to change it at runtime.
frictionnumber?read/writeSurface friction coefficient; nil if the handle has no physics body. Assign a number to change it at runtime.
ccdbooleanread/writeWhether this body, when moving fast, also sweeps moving (kinematic and dynamic) bodies so it never tunnels through them; fast bodies always sweep static geometry. Assign a boolean to toggle.
parentDrawPrimitive?read/writeThe group this primitive belongs to (its transform composes with the group's), or nil if it is ungrouped. Assign a primitive to reparent (the local transform is kept, and a physics body moves with the primitive), or nil to detach; reparenting across canvases, or under the primitive itself or one of its descendants, raises.
cellinteger?read/writeThe atlas cell index (0-based) for a sprite drawn from an Atlas; assign to animate. Nil for primitives that are not atlas sprites; assigning to those is ignored.

Methods 18

DrawPrimitive:update

method
DrawPrimitive:update(opts: draw.UpdateOptions)

Update a primitive's properties in place.

Example
prim:update({
    pos = vec2(80, 40),
    color = color("#e67e80"),
    scale_x = 2,
})

opts draw.UpdateOptions options 13 keys Omitted keys keep their current value.

KeyTypeDescription
posVec2 | Vec3New position: a shape's center, a text's top-left corner, or a group's offset; a vec2 keeps the current depth.
colorColorNew color.
materialShaderShader handle to apply.
rotationnumberRotation in radians CCW.
scale_xnumberHorizontal scale factor.
scale_ynumberVertical scale factor.
textstringNew text content.
font_sizenumber | stringNew font size: a number (pixels) or a unit string like "1.5rem"/"50vw"/"4vmin".
max_widthnumberMaximum line width in pixels; enables wrapping.
align"left" | "center" | "right" | "justified"Horizontal alignment.
font_weightnumber | "thin" | "extralight" | "light" | "regular" | "normal" | "medium" | "semibold" | "bold"New font weight: a number on the variable weight axis, or a weight name (bold is the heaviest).
font_style"normal" | "italic" | "oblique"New font face: upright, the calligraphic cursive, or a mechanical slant.
spans(draw.TextSpan | DrawPrimitive)[]Rich-text spans to set: each entry is a span table or a detached span handle.

DrawPrimitive:remove

method
DrawPrimitive:remove()

Remove a primitive from its canvas.

DrawPrimitive:animate

method
DrawPrimitive:animate(opts: draw.AnimateOptions)

Tween the primitive's position, rotation, scale, color, and opacity over duration seconds with the given easing curve.

Example
prim:animate({
    pos = vec2(100, 0),
    scale = vec2(2, 2),
    duration = 0.5,
    easing = "cubic_out",
})

opts draw.AnimateOptions options 8 keys

KeyTypeDefaultDescription
posVec2the position is not tweenedTarget position; the primitive's current z (layer) is kept.
rotationnumberthe rotation is not tweenedTarget rotation in radians (about Z).
scaleVec2the scale is not tweenedTarget scale (x, y).
colorColorthe color is not tweenedTarget color, blended perceptually (Oklab, like Color:lerp). Writes the same color slot update{color=} writes.
opacitynumberthe opacity is not tweenedTarget alpha 0.0-1.0 — the opacity property's value, so it propagates to children.
durationnumber1Tween duration in seconds.
easingEasing"linear"Easing curve.
loopingbooleanfalsePing-pong loop the tween.

DrawPrimitive:contains

method
DrawPrimitive:contains(point: Vec2) -> boolean

Whether this primitive's drawn shape covers point (canvas-local world space). Geometry only — a named primitive is tested regardless of its visibility. Always false for text and groups, which have no single shape.

Example
-- A new shape can be tested from the next frame on.
datumhue.time.wait_frames(1)
print(prim:contains(vec2(10, 10))) --> true
print(prim:contains(vec2(30, 0))) --> false

DrawPrimitive:bounds

method
DrawPrimitive:bounds() -> draw.Bounds?

The primitive's axis-aligned bounding box in canvas-local world space, or nil for primitives without a single drawn shape (text, groups, canvas:body bodies).

returns draw.Bounds record 4 keys

KeyTypeDescription
minVec2Minimum corner.
maxVec2Maximum corner.
sizeVec2Extent along each axis (max - min).
centerVec2Center of the box.

DrawPrimitive:add_body

method
DrawPrimitive:add_body(options?: physics.BodyOptions)

Attach a physics body. A DrawPrimitive's body simulates in the app's 2D world, a SceneNode's in its 3D world. See physics.BodyOptions for the shape + material fields. With no shape, the collider fits what the handle draws, measured when add_body runs: a draw primitive's drawing (a circle for a round one, a text's laid-out block, a group's children combined), or a scene node's mesh (a plane is a thin slab under it, a torus the disc it spans, a billboard sprite an upright cylinder standing on its pivot, anything else a unit box). A draw primitive's named shape also takes omitted sizes from its drawing; a scene node's takes width, height, and depth 1 and radius 0.5. The collider, unless built from points, is centered on the drawing; refit_body measures again. Sizes and points are in the handle's own units: the collider scales and mirrors with the handle and every group or node above it, except that a sprite sized in pixels keeps its unscaled collider. A size or point, or a collider reaching, past 1000000 units raises. The body follows whatever moves, turns, or scales the handle or anything above it at the next physics step: a static or kinematic body goes where its handle goes; a dynamic body simulates on its own and jumps, keeping its velocity, when your code moves it or something above it. Replacing a body keeps its joints. Raises, keeping any previous body, for a text span or a voxel volume, a negative or non-finite size, a non-finite point, a triangle naming a point that does not exist, or a world other than the jointed body's own.

Example
local floor = canvas:rect({
    pos = vec2(-160, -120),
    width = 320,
    height = 20,
    color = color("#7fbbb3"),
})
-- Without a shape, the collider fits what is drawn.
floor:add_body({ type = "static" })
prim:add_body({ restitution = 0.8 })

options physics.BodyOptions options 18 keys

KeyTypeDefaultDescription
type"dynamic" | "static" | "kinematic""dynamic"Body dynamics.
shapephysics.Shapethe collider fits what the handle drawsCollider shape.
widthnumbertaken from what the handle draws, or 1Box width, in the handle's own units.
heightnumbertaken from what the handle draws, or 1Box, cylinder, or cone height, or a capsule's straight length between its caps, in the handle's own units.
depthnumbertaken from what the handle draws, or 1Box depth in the handle's own units, 3D only.
radiusnumbertaken from what the handle draws, or 0.5Circle, sphere, capsule, cylinder, or cone radius, in the handle's own units.
restitutionnumber0.3Bounciness, 0 or more: 0 absorbs an impact, 1 keeps all its energy.
frictionnumber0.5Surface friction, 0 or more.
massnumberderived from the collider's sizeMass override, more than 0.
sensorbooleanfalseMake the body a non-colliding trigger volume that reports the bodies overlapping it: dynamic and kinematic ones, and static ones unless the sensor is static itself.
pointsVec3[]a convex_hull, polyline or trimesh shape is a boxVertices for convex_hull / polyline / trimesh in the handle's own frame and units (vec3; vec2 accepted, z = 0).
indicesinteger[][]a trimesh shape is a boxTriangles for the trimesh shape: each three 1-based positions in points.
layersinteger[]every layerCollision membership: layer bit indices 0..=31 the body belongs to.
collides_withinteger[]every layerCollision filter: layer bit indices 0..=31 the body collides with; an empty list collides with nothing.
lock_translation"x" | "y" | "z"[]no axis beyond those constraintsAxes to lock translation on, on top of a 2D body's in-plane constraints.
lock_rotation"x" | "y" | "z"[]no axis beyond those constraintsAxes to lock rotation on, on top of a 2D body's in-plane constraints.
ccdbooleanfalseSweep this body against moving (kinematic and dynamic) bodies too when it moves fast; fast bodies always sweep static geometry so they never tunnel through it.
worldPhysicsWorldthe app's default worldSimulate in this world, made by datumhue.physics.world(), instead of the app's default one.

DrawPrimitive:character_controller

method
DrawPrimitive:character_controller(options?: physics.CharacterControllerOptions) -> CharacterController

Attach a kinematic character controller to this body and return its CharacterController handle. The body must be kinematic. The controller solves walking/sliding/stair-stepping geometry only — gravity, jump, input, and camera stay in your code. Lengths, absolute or relative, are 0 to 1000000. Raises if the body is missing, not kinematic, or already has a controller (remove() to rebind).

Example
prim:add_body({ type = "kinematic" })
local walker = prim:character_controller({
    max_slope_climb_angle = math.pi / 3,
    snap_to_ground = { relative = 0.5 },
})

options physics.CharacterControllerOptions options 8 keys

KeyTypeDefaultDescription
upVec2 | Vec3datumhue.math.vec3(0, 1, 0)Floor-defining up direction; selects which contacts count as ground. 2D uses the XY components.
offsetnumber | physics.RelativeLength{relative = 0.01}Small gap kept between the character and surroundings for stability; must be > 0.
slidebooleantrueSlide along blocking walls instead of stopping dead.
max_slope_climb_anglenumbermath.pi / 4Steepest slope, in radians, the character will climb; steeper surfaces act as walls.
min_slope_slide_anglenumbermath.pi / 4Slope angle, in radians, at/above which the character auto-slides down.
snap_to_groundnumber | physics.RelativeLength | boolean{relative = 0.2}Distance to snap down onto ground after a move, keeping the character glued over dips; false disables.
autostepphysics.AutostepConfig | booleanfalseStep-climbing config, or false to disable; stepping is expensive. Needs a flat-bottomed body (cube or cylinder); a capsule's rounded bottom slides back off the ledge. The body also needs head room of its own height plus max_height above where it stands, so a low ceiling stops it stepping.
normal_nudge_factornumber0.0001Tiny anti-stick push along contact normals while sliding, 0 to 1.

DrawPrimitive:apply_impulse

method
DrawPrimitive:apply_impulse(vec: Vec2 | Vec3)

Apply an instantaneous, mass-correct velocity change of impulse / mass. Accepts vec2 or vec3.

Example
prim:add_body({ mass = 2 })
prim:apply_impulse(vec2(100, 0))
-- The velocity changes by impulse / mass, in canvas units a second.
print(prim.velocity.x) --> 50.0

DrawPrimitive:apply_angular_impulse

method
DrawPrimitive:apply_angular_impulse(impulse: number | Vec3)

Apply an instantaneous, inertia-correct spin change. A number for 2D bodies (about Z), a vec3 for 3D.

DrawPrimitive:apply_force

method
DrawPrimitive:apply_force(vec: Vec2 | Vec3)

Set the continuous force applied every step until changed. Pass a zero vector to stop. Accepts vec2 or vec3.

DrawPrimitive:apply_torque

method
DrawPrimitive:apply_torque(torque: number | Vec3)

Set the continuous torque applied every step until changed. Pass zero to stop. A number for 2D bodies (about Z), a vec3 for 3D.

DrawPrimitive:lock_rotation

method
DrawPrimitive:lock_rotation(locked: boolean)

Lock or unlock rotation.

DrawPrimitive:set_collision_layers

method
DrawPrimitive:set_collision_layers(options: physics.CollisionLayerOptions)

Replace this body's collision filtering at runtime.

Example
prim:add_body()
prim:set_collision_layers({ layers = { 1 }, collides_with = { 0, 2 } })

options physics.CollisionLayerOptions options 2 keys

KeyTypeDefaultDescription
layersinteger[]every layerMembership layer bit indices 0..=31.
collides_withinteger[]every layerFilter layer bit indices 0..=31; an empty list collides with nothing.

DrawPrimitive:set_locked_axes

method
DrawPrimitive:set_locked_axes(options: physics.LockedAxesOptions)

Lock or unlock individual translation/rotation axes at runtime. The 2D in-plane constraints are always preserved.

Example
prim:add_body()
-- Move along y only.
prim:set_locked_axes({ lock_translation = { "x" } })

options physics.LockedAxesOptions options 2 keys

KeyTypeDefaultDescription
lock_translation"x" | "y" | "z"[]translation is unlockedAxes to lock translation on; the 2D in-plane locks always remain.
lock_rotation"x" | "y" | "z"[]rotation is unlockedAxes to lock rotation on; the 2D in-plane locks always remain.

DrawPrimitive:on_collision_start

method
DrawPrimitive:on_collision_start(callback?: fun(other: DrawPrimitive, contact?: physics.Contact))

Set, replace, or clear (pass nil) the handler fired when this body starts colliding. contact is nil when either body is a sensor. Not fired once this body's own handle has been removed, even by an earlier collision handler in the same step; other may have been removed that way, and its handle still compares equal to one you hold.

DrawPrimitive:on_collision_end

method
DrawPrimitive:on_collision_end(callback?: fun(other: DrawPrimitive))

Set, replace, or clear (pass nil) the handler fired when this body stops colliding. Removing either body of a touching pair (its handle, or only its body, as remove_body does) ends the contact on the next physics step; other may be the removed body, and its handle still compares equal to one you hold. Not fired once this body's own handle has been removed, even by an earlier collision handler in the same step.

DrawPrimitive:remove_body

method
DrawPrimitive:remove_body()

Remove all physics from this handle.

DrawPrimitive:refit_body

method
DrawPrimitive:refit_body()

Measure what the handle draws again and resize its collider to fit, in place: velocity, joints, and contacts carry on. Sizes given to add_body stay; the ones it took from the drawing, and the collider's center, follow the drawing as it is now (a text laid out again, a group whose children moved). Raises, keeping the collider, for a handle with no body, a voxel volume (its body follows its cells), or a collider that would reach more than 1000000 units from the body.

Types 1

Easing

enum
ValueDescription
"linear"
"quadratic_in"
"quadratic_out"
"quadratic_in_out"
"cubic_in"
"cubic_out"
"cubic_in_out"
"quartic_in"
"quartic_out"
"quartic_in_out"
"quintic_in"
"quintic_out"
"quintic_in_out"
"sine_in"
"sine_out"
"sine_in_out"
"circular_in"
"circular_out"
"circular_in_out"
"exponential_in"
"exponential_out"
"exponential_in_out"
"elastic_in"
"elastic_out"
"elastic_in_out"
"back_in"
"back_out"
"back_in_out"
"bounce_in"
"bounce_out"
"bounce_in_out"
"smooth_step_in"
"smooth_step_out"
"smooth_step"
"smoother_step_in"
"smoother_step_out"
"smoother_step"

Nested in: chart.AnimateOptions, draw.AnimateOptions, scene.AnimateOptions, scene.CameraAnimateOptions, time.TweenOptions

datumhue.com

(c) 2026 Shuusei AB. Quote excerpts of this manual, with attribution to DatumHue, in your own documentation, tutorials, course materials, reviews, and other writing or video. Republishing it in whole or in substantial part needs written permission: support@datumhue.com.

Victor Mono is licensed under the SIL Open Font License 1.1
Copyright (c) 2024, Rune Bjørnerås (https://github.com/rubjo)

This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL


-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------

PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.

The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.

DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.

"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).

"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).

"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.

"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.

PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:

1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.

2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.

3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.

4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.

5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.

TERMINATION
This license becomes null and void if any of the above conditions are
not met.

DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Try

    ↑↓ selectEnter openTab filter

    Settings

    Theme
    Text
    Print

    Keyboard shortcuts

    / or Ctrl KSearch
    ↑ ↓ EnterPick a result
    TabNext result filter
    j kNext or previous entry
    [ ]Previous or next page
    yCopy a link to the current entry
    ?These shortcuts
    EscClose

    On this page