Animation
10 source file(s), 178 public symbol(s), 41 of them carrying KDoc. Everything below is the documentation that lives beside the code — the same text the completion documentation panel shows in the editor. A blank summary means the declaration has no KDoc yet, not that this page dropped it.
Motion.kt
src/jvmMain/kotlin/afield/animation/mocap/Motion.kt — read the source
Top-level functions
| Declaration | Summary |
|---|---|
fun MotionPose.bones(skeleton: MotionSkeleton): FLine |
Parent-child segments in 3D; pass these to the existing Field line renderer and camera. |
fun FLine.motionRoute(startTime: Double, duration: Double, count: Int = 41, headings: Boolean = false, distanceFraction: (Double) -> Double = { it }): List<TimedRootPoint> |
Existing FLine arc-length cursor; distanceFraction supplies timing separately from geometry. |
MotionCoordinates
Motion uses metres, seconds, right handed Y-up coordinates and xyzw quaternions. This matches Field's glTF scene coordinates. Cameras and projection remain the caller's. sourceToField is a row-major orthogonal basis, also used for forces; moments are axial vectors.
| Declaration | Summary |
|---|---|
val sourceUnits: String |
|
val sourceHandedness: String |
|
val sourceUp: String |
|
val sourceForward: String |
|
val metresPerUnit: Double |
|
val sourceToField |
|
val determinant: Float |
|
fun position(p: Vec3): Vec3 |
|
fun direction(p: Vec3): Vec3 |
|
fun moment(p: Vec3): Vec3 |
|
fun rotation(q: Quat): Quat |
|
fun json(): JSONObject |
MotionBody
data class MotionBody(val name: String, val joint: String, val massKg: Double? = null)
A rigid body is explicitly named and mapped; a joint index is never a force-application body.
| Declaration | Summary |
|---|---|
fun json() |
MotionSkeleton
Runtime joint order and rest transforms. Reuses Field's scene hierarchy rather than a new FK engine.
| Declaration | Summary |
|---|---|
val id: String |
|
val version: String |
|
val coordinates: MotionCoordinates |
|
val names |
|
val parents |
|
val restTranslations |
|
val restRotations |
|
val bodies |
|
val hash: String |
|
fun joint(name: String): Int |
|
fun body(name: String): MotionBody |
|
fun sceneSkeleton(): GltfSkinning.Skeleton |
|
fun json() |
MotionPose
class MotionPose(root: List<Double>, localRotations: List<Double>, worldPositions: List<Double>)
Lists are copied on construction. Display code may create mutable Field vectors without sharing worker state.
| Declaration | Summary |
|---|---|
val root |
|
val localRotations |
|
val worldPositions |
|
val size: Int |
|
val hasRotations: Boolean |
|
fun position(index: Int): Vec3 |
|
fun rotation(index: Int): Quat |
|
fun json() |
MotionFrame
| Declaration | Summary |
|---|---|
val time: Double, val index: Long, val episode: Long, val revision: Long |
|
val executed: MotionPose, val intended: MotionPose? |
|
val contacts |
|
val diagnostics |
|
fun json() |
TimedRootPoint
| Declaration | Summary |
|---|---|
fun json() |
MotionAuthoring.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionAuthoring.kt — read the source
Used in: Generative Mocap — ARDY and CLoSD
Top-level functions
| Declaration | Summary |
|---|---|
suspend fun <T> CompletableFuture<T>.awaitMotion(): T |
Await an optional worker without blocking Field's frame thread. Cancellation cancels opening too. |
fun MotionSession.prompt(text: String, at: Double = editableTime) |
Change intention at the next editable time, or explicitly schedule at in session seconds. |
fun MotionSession.route(path: FLine, duration: Duration, at: Double = editableTime, headings: Boolean = true, distanceFraction: (Double) -> Double = { it }): CompletableFuture<MotionApplied?> |
Sample Field's arc-length cursor, with geometry, duration, heading and speed envelope independent. |
fun MotionSession.body(name: String): MotionBodyHandle |
A runtime physical body; resolving it checks the explicit body mapping, never a display-joint index. |
fun MotionSession.joint(name: String) |
An animation joint. Holding it is kinematic conditioning, distinct from a physical tether. |
suspend fun afield.runtime.lifecycle.Frames.playMotion(session: MotionSession, duration: Duration, draw: (MotionSnapshot) -> Unit) |
Present a bounded, wall-paced stretch of motion from a Frames coroutine. Inference stays on the session worker; draw sees interpolated snapshots and explicit lag. Duration rounds up to the backend's next complete token/control step. Late output holds; it never extrapolates a body. |
Top-level values
| Declaration | Summary |
|---|---|
val MotionSession.editableTime: Double |
First uncommitted session time. A currently running advance may move it further before an edit applies. |
TetherSettings
class TetherSettings internal constructor(previous: MotionAttachment? = null)
Mutable only while authoring a command; vectors are copied into the immutable wire payload. SI units.
| Declaration | Summary |
|---|---|
var point |
|
var anchor: Vec3? |
|
var velocity |
|
var stiffness |
|
var damping |
|
var maxForce |
|
var ramp: Duration |
|
var breakForce |
|
var breakDistance |
|
var breakDuration: Duration |
|
fun breakAbove(force: Double, forAtLeast: Duration = 100.milliseconds) |
Break on sustained pre-cap demand, not merely because the spring hits its force cap. |
fun unbreakable() |
Keep the connection when its applied force saturates. |
MotionBodyHandle
| Declaration | Summary |
|---|---|
fun position(localPoint: Vec3 = Vec3()): Vec3 |
Current executed body-local point in world metres; localPoint is not a joint offset. |
fun tether(id: String = "tether-${tetherIds.incrementAndGet()}", at: Double = session.editableTime, block: TetherSettings.() -> Unit = {}): MotionTether |
Capture the current point as anchor unless the block supplies TetherSettings.anchor. |
fun impulse(impulse: Vec3, point: Vec3 = Vec3(), at: Double = session.editableTime) |
World impulse in N s, applied once at a body-local point. |
MotionTether
A named connection. accepted acknowledges scheduling; observation reports actual physics/reset events.
MotionJointHandle
class MotionJointHandle internal constructor(private val session: MotionSession, val index: Int)
| Declaration | Summary |
|---|---|
fun position(): Vec3 |
|
fun hold(duration: Duration, orientation: Boolean = false, at: Double = session.editableTime): CompletableFuture<MotionApplied?> |
Repeated future targets; ARDY requires an explicit root plan covering the same interval. |
fun release(at: Double = session.editableTime) |
TetherObservation
Actual submitted point force and raw anchor residual, not inferred muscular effort.
| Declaration | Summary |
|---|---|
val time: Double, val forceN: Double |
|
val powerWatts: Double |
|
val point: List<Double> |
MotionTelemetry
class MotionTelemetry internal constructor()
Bounded observations of actual backend events. Reset and break invalidate every affected connection.
| Declaration | Summary |
|---|---|
var lastEvent |
|
fun tether(id: String) |
|
fun tethers(): List<TetherObservation> |
MotionCommands.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionCommands.kt — read the source
Top-level functions
| Declaration | Summary |
|---|---|
fun pointTether(point: Vec3, centreOfMass: Vec3, comVelocity: Vec3, angularVelocity: Vec3, anchor: Vec3, anchorVelocity: Vec3 = Vec3(), stiffness: Double, damping: Double, maximumForce: Double, engagement: Double = 1.0): PointWrench |
Inspectable point-force math, independent of a simulator. Inputs are in one world frame, SI. point is measured from the actual COM, not the display joint or rigid-body origin. The simulator adapter must add this wrench to other forces and apply it for the documented step. |
MotionOperation
Constants: PROMPT, ROOT_PLAN, JOINT_TARGETS, ATTACH, UPDATE_ATTACHMENT, DETACH, IMPULSE, ADVANCE, RESET.
MotionCapabilities
| Declaration | Summary |
|---|---|
fun require(operation: MotionOperation) |
JointTarget
Kinematic conditioning, in world coordinates; orientation is optional and separately recorded.
| Declaration | Summary |
|---|---|
fun json() |
MotionAttachment
Force capped spring/damper. A break requires a sustained criterion; saturation alone never detaches.
| Declaration | Summary |
|---|---|
val id: String, val body: String, val localPoint: List<Double>, val anchor: List<Double> |
|
val stiffness: Double |
|
val engagementSeconds: Double |
|
val breakDuration: Double |
|
val anchorVelocity: List<Double> |
|
fun json() |
PointWrench
MotionExamples.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionExamples.kt — read the source
MotionExamples
A diagnostic two-joint clip, explicitly unrelated to learned motion or simulated humanoids.
| Declaration | Summary |
|---|---|
fun contractClip(): MotionClip |
|
fun recordContractClip(directory: Path) |
MotionPlayback.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionPlayback.kt — read the source
MotionSnapshot
data class MotionSnapshot(val frame: MotionFrame, val lagSeconds: Double, val held: Boolean)
MotionBuffer
class MotionBuffer(val capacity: Int = 8, val maxSpanSeconds: Double = .4)
Bounded live display buffer. Missing data holds the last pose and reports lag; no extrapolation. Reset/episode edges hold the earlier pose until the new frame's time. Reader and producer may differ.
| Declaration | Summary |
|---|---|
var dropped: Long |
|
fun clear() |
|
fun add(frame: MotionFrame) |
|
fun sample(time: Double): MotionSnapshot? |
|
fun size(): Int |
MotionClip
class MotionClip(val skeleton: MotionSkeleton, frames: List<MotionFrame>)
Immutable recorded poses, independent of model installations and seeds.
| Declaration | Summary |
|---|---|
val frames |
|
fun sample(time: Double): MotionSnapshot |
MotionProcess.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionProcess.kt — read the source
Used in: Generative Mocap — ARDY and CLoSD
MotionProcessConfig
CLoSD
Starts a process, authenticates its capability/skeleton reply, and owns it through box stop/re-run.
| Declaration | Summary |
|---|---|
fun openAsync(config: MotionProcessConfig = MotionProcessConfig()): CompletableFuture<MotionSession> |
ARDY
| Declaration | Summary |
|---|---|
fun openAsync(config: MotionProcessConfig = MotionProcessConfig(backend = "ardy")): CompletableFuture<MotionSession> |
MotionRecording.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionRecording.kt — read the source
MotionRecorder
Portable .f4motion directory: JSON metadata/events and chunked little-endian float32 poses. No native Python objects or pickle. The manifest appears only after a clean close. Requested/applied/superseded commands and reset/termination diagnostics belong in event.
| Declaration | Summary |
|---|---|
val chunkFrames: Int |
|
fun event(event: JSONObject) |
|
fun append(frame: MotionFrame) |
|
override fun close() |
MotionRecording
class MotionRecording(val directory: Path)
Streaming read keeps long recordings off the live buffer; clip is an explicit in-memory load.
| Declaration | Summary |
|---|---|
val metadata: JSONObject |
|
val skeleton: MotionSkeleton |
|
fun frames(): Sequence<MotionFrame> |
|
fun clip() |
|
fun events(): Sequence<JSONObject> |
MotionScoreSmoke.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionScoreSmoke.kt — read the source
MotionScoreSmoke
Real physical-body authoring, moving anchor, observation, reset and reused-handle ordering.
| Declaration | Summary |
|---|---|
fun main(args: Array<String>) |
MotionSession.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionSession.kt — read the source
MotionCommand
MotionApplied
Null time/index means accepted for scheduling; a later update carries the actual applied event.
MotionUpdate
data class MotionUpdate(val frames: List<MotionFrame>, val events: List<JSONObject> = emptyList())
MotionBackend
interface MotionBackend : AutoCloseable
Blocking backend boundary, invoked only by MotionSession's owned daemon thread. Implementations must return bounded batches, honor explicit session times, and close promptly. An installed Python package alone must never advertise a working capability.
| Declaration | Summary |
|---|---|
val skeleton: MotionSkeleton |
|
val capabilities: MotionCapabilities |
|
fun command(command: MotionCommand): MotionApplied |
|
fun advance(seconds: Double): MotionUpdate |
MotionSession
One small optional motion facade. No inference or simulator work runs on Field's frame thread. Commands are bounded; path/target replacements coalesce only before the next ordered event. Subscriptions run on the worker thread and must be short; rendering reads buffer snapshots. Construction in a box registers with its existing RunScope (stop/re-run/document close). Live ARDY/CLoSD drivers require separately validated model environments; replay needs neither.
MotionView.kt
src/jvmMain/kotlin/afield/animation/mocap/MotionView.kt — read the source
Used in: Generative Mocap — ARDY and CLoSD
Top-level functions
| Declaration | Summary |
|---|---|
fun Box.showMotion(frame: MotionFrame, skeleton: MotionSkeleton, channel: String = "motion", reference: Boolean = true, contacts: Boolean = true, overlays: List<FLine> = emptyList(), height: Int = 420, follow: Boolean = false, followHalfLife: Double = .4, followVertical: Boolean = false, followEpoch: String = frame.episode.toString()) |
Existing Field 3D viewer/camera, streamed FLine geometry; repeated draws preserve the user's orbit. |
fun TetherObservation.overlays(forceScale: Double = .00015): List<FLine> |
Red spring/anchor and an amber submitted-force vector, scaled in metres per Newton for drawing. |