Skip to main content

konjure_lang/catalog/
prelude.rs

1//! Rust-owned source and reference metadata for declarations imported by every program.
2//!
3//! These schemas describe nominal interpreter [`crate::RecordValue`] values. They are
4//! not aliases for Rust SDK structs: adapters decide which component schemas they
5//! consume. Keeping each declaration beside its documentation makes the parser input,
6//! rustdoc, and website reference one source of truth.
7
8/// Declares prelude source constants and builds their website definitions from the
9/// same literals. `catalog.rs` owns the shared output structs.
10macro_rules! prelude_definitions {
11    ($(
12        $(#[doc = $doc:literal])*
13        pub const $constant:ident: $name:literal => {
14            category: $category:literal,
15            kind: $kind:literal,
16            declaration: $declaration:literal,
17            status: $status:literal,
18            representation: $representation:literal,
19            members: [$(
20                $(#[doc = $member_doc:literal])*
21                $member:literal
22            ),* $(,)?],
23            examples: [$(
24                {
25                    title: $title:literal,
26                    description: $description:literal,
27                    source: $source:literal,
28                    output: [$($output:literal),* $(,)?],
29                    ticks: $ticks:literal,
30                    presentation: $presentation:literal
31                }
32            ),* $(,)?]
33        };
34    )*) => {
35        $(
36            $(#[doc = $doc])*
37            #[doc = concat!("\n\n# Declaration\n\n```text\n", $declaration, "\n```\n")]
38            #[doc = concat!("\n# Fields and methods\n", $("\n- `", $member, "`: ", $($member_doc, " ",)* "\n",)*)]
39            $(#[doc = concat!("\n# ", $title, "\n\n", $description, "\n\n```text\n", $source, "\n```\n")])*
40            pub const $constant: &str = $declaration;
41        )*
42
43        /// Returns documentation records for the parser-imported type and trait schemas.
44        pub(crate) fn definitions() -> Vec<super::BuiltinDefinition> {
45            vec![$(
46                super::BuiltinDefinition {
47                    name: $name,
48                    category: $category,
49                    kind: $kind,
50                    declaration: $declaration,
51                    docs: concat!($($doc, "\n"),*),
52                    status: $status,
53                    members: &[$(super::MemberDoc {
54                        name: $member,
55                        docs: concat!($($member_doc, "\n"),*),
56                    }),*],
57                    examples: &[$(super::ExampleSpec {
58                        title: $title,
59                        description: $description,
60                        source: $source,
61                        output: &[$($output),*],
62                        ticks: $ticks,
63                        presentation: $presentation,
64                    }),*],
65                    rust_path: concat!("/sdk/rust/konjure_lang/catalog/prelude/constant.", stringify!($constant), ".html"),
66                    representation: $representation,
67                }
68            ),*]
69        }
70
71        /// Concatenated parser input for the documented prelude declarations.
72        pub const PRELUDE: &str = concat!($($declaration, "\n"),*);
73    };
74}
75
76prelude_definitions! {
77    /// A typed interaction contract with one `click` operation.
78    ///
79    /// Implement Click when a type should satisfy a nominal interaction contract
80    /// or appear in `query[Click]()`. Hosts may also invoke an ordinary checked
81    /// click method without this trait; the host owns event dispatch.
82    pub const CLICK: "Click" => {
83        category: "Interface", kind: "trait", declaration: "trait Click { func click() -> Unit; }", status: "runtime",
84        representation: "Trait declaration checked by the interpreter; it is not a Rust SDK trait.",
85        members: [
86            /// Required action with no arguments. A direct record method may mutate its receiver; a bound component callback is required when that mutation must persist to an entity.
87            "click"
88        ],
89        examples: [{ title: "Implement a click action", description: "A type satisfies the contract with a matching typed method.", source: "type Example {}\n\nimpl Click for Example {\n  func click() -> Unit { print(\"clicked\"); }\n}\n\nlet value = Example {};\nvalue.click();", output: ["clicked"], ticks: 0, presentation: "snippet" }]
90    };
91    /// A typed presentation contract with one `render` operation.
92    ///
93    /// Querying Render implementers is language behavior. Rendering remains an adapter
94    /// responsibility; declaring this trait never schedules an automatic render call.
95    pub const RENDER: "Render" => {
96        category: "Geometry", kind: "trait", declaration: "trait Render { func render() -> Unit; }", status: "runtime",
97        representation: "Trait declaration checked by the interpreter; graphics handles remain host-owned.",
98        members: [
99            /// Required presentation operation. A host or system chooses when to invoke it.
100            "render"
101        ],
102        examples: [{ title: "Implement a render operation", description: "The trait only checks the method contract.", source: "type Example {}\n\nimpl Render for Example {\n  func render() -> Unit { print(\"rendered\"); }\n}\n\nlet value = Example {};\nvalue.render();", output: ["rendered"], ticks: 0, presentation: "snippet" }]
103    };
104    /// A three-component numeric vector with zero defaults.
105    ///
106    /// Spatial consumers interpret components as meters, directions, or radians based
107    /// on their containing field; Vec3 itself carries no unit.
108    pub const VEC3: "Vec3" => {
109        category: "Math", kind: "type", declaration: "type Vec3 {\n  x: Number = 0;\n  y: Number = 0;\n  z: Number = 0;\n}", status: "runtime",
110        representation: "Interpreter RecordValue schema, copied by value at language boundaries.",
111        members: [
112            /// X component; defaults to 0.
113            "x", /// Y component; defaults to 0.
114            "y", /// Z component; defaults to 0.
115            "z"
116        ], examples: [{ title: "Construct a vector", description: "Unset components retain their zero default.", source: "let value = Vec3 { x: 2 };\nprint(value.x);", output: ["2"], ticks: 0, presentation: "snippet" }]
117    };
118    /// Local pose and scale for an entity.
119    ///
120    /// Position is meters, rotation is XYZ Euler radians, and scale defaults to one on
121    /// every axis. Physics owns the position and rotation of dynamic bodies.
122    pub const TRANSFORM: "Transform" => {
123        category: "Math", kind: "type", declaration: "type Transform {\n  position: Vec3 = Vec3 {};\n  rotation: Vec3 = Vec3 {};\n  scale: Vec3 = Vec3 { x: 1, y: 1, z: 1 };\n}", status: "rendered",
124        representation: "Interpreter RecordValue schema consumed by spatial adapters.",
125        members: [
126            /// Translation in meters; defaults to the local origin.
127            "position", /// XYZ Euler rotation in radians; defaults to zero rotation.
128            "rotation", /// Per-axis multiplier; defaults to (1, 1, 1). Physical spheres require uniform positive scale.
129            "scale"
130        ], examples: [
131            { title: "Set a pose", description: "Create a transform value in meters.", source: "let value = Transform { position: Vec3 { x: 2 } };\nprint(value.position.x);", output: ["2"], ticks: 0, presentation: "snippet" },
132            { title: "Attach a renderable pose", description: "A scene adapter reads Transform from an entity with geometry.", source: "let entity = spawn(Sphere {});\nadd(entity, Transform { position: Vec3 { y: 1 } });\nprint(get[Transform](entity).position.y);", output: ["1"], ticks: 0, presentation: "scene" }
133        ]
134    };
135    /// A sphere centered at its entity origin.
136    ///
137    /// The spatial adapter requires a positive radius before tessellation. A Sphere is
138    /// also one of the two collision shapes accepted by RigidBody.
139    pub const SPHERE: "Sphere" => {
140        category: "Geometry", kind: "type", declaration: "type Sphere { radius: Number = 0.2; }", status: "rendered",
141        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
142        members: [#[doc = "Radius in meters; defaults to 0.2 and must be positive for physics."] "radius"],
143        examples: [{ title: "Create a sphere", description: "Geometry becomes renderable when attached to an entity.", source: "let entity = spawn(Sphere { radius: 0.5 });\nprint(get[Sphere](entity).radius);", output: ["0.5"], ticks: 0, presentation: "scene" }]
144    };
145    /// An axis-aligned local box with full dimensions.
146    ///
147    /// The spatial adapter validates positive dimensions before rendering. Box is one
148    /// of the two collision shapes accepted by RigidBody; `size` uses full extents.
149    pub const BOX: "Box" => {
150        category: "Geometry", kind: "type", declaration: "type Box { size: Vec3 = Vec3 { x: 1, y: 1, z: 1 }; }", status: "rendered",
151        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
152        members: [#[doc = "Full width, height, and depth in meters; each physical dimension must be positive."] "size"],
153        examples: [{ title: "Create a box", description: "Size records full extents, not half extents.", source: "let entity = spawn(Box { size: Vec3 { x: 2, y: 1, z: 1 } });\nprint(get[Box](entity).size.x);", output: ["2"], ticks: 0, presentation: "scene" }]
154    };
155    /// A cylinder aligned with local Y.
156    ///
157    /// Radius and height must be positive when a spatial adapter tessellates this
158    /// geometry. Cylinders currently render but are not RigidBody collision shapes.
159    pub const CYLINDER: "Cylinder" => {
160        category: "Geometry", kind: "type", declaration: "type Cylinder { radius: Number = 0.2; height: Number = 1; }", status: "rendered",
161        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
162        members: [#[doc = "Radius in meters; defaults to 0.2."] "radius", #[doc = "Full height in meters along local Y; defaults to 1."] "height"],
163        examples: [{ title: "Create a cylinder", description: "The current spatial adapter renders it along local Y.", source: "let entity = spawn(Cylinder { height: 2 });\nprint(get[Cylinder](entity).height);", output: ["2"], ticks: 0, presentation: "scene" }]
164    };
165    /// A rectangular local XY surface facing local +Z.
166    ///
167    /// Width and height must be positive when rendered. The adapter expands Quad into
168    /// two triangles with +Z normals; it is not a RigidBody collision shape.
169    pub const QUAD: "Quad" => {
170        category: "Geometry", kind: "type", declaration: "type Quad { width: Number = 1; height: Number = 1; }", status: "rendered",
171        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
172        members: [#[doc = "Width in meters along local X; defaults to 1."] "width", #[doc = "Height in meters along local Y; defaults to 1."] "height"],
173        examples: [{ title: "Create a quad", description: "The adapter places the surface in local XY.", source: "let entity = spawn(Quad { width: 3 });\nprint(get[Quad](entity).width);", output: ["3"], ticks: 0, presentation: "scene" }]
174    };
175    /// A line segment between two local positions.
176    ///
177    /// Endpoints are passed through as meters. The adapter tessellates the segment for
178    /// rendering; no positive length or physics collision contract is declared here.
179    pub const LINE: "Line" => {
180        category: "Geometry", kind: "type", declaration: "type Line { from: Vec3 = Vec3 {}; to: Vec3 = Vec3 { x: 1 }; }", status: "rendered",
181        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
182        members: [#[doc = "Start point in local meters; defaults to the origin."] "from", #[doc = "End point in local meters; defaults to (1, 0, 0)."] "to"],
183        examples: [{ title: "Create a segment", description: "Line endpoints are expressed in the entity's local coordinates.", source: "let entity = spawn(Line { to: Vec3 { y: 2 } });\nprint(get[Line](entity).to.y);", output: ["2"], ticks: 0, presentation: "scene" }]
184    };
185    /// A visual ray with an explicit finite length.
186    ///
187    /// The adapter requires direction magnitude greater than 1e-12 and positive
188    /// length. It normalizes an accepted direction before building the rendered line.
189    pub const RAY: "Ray" => {
190        category: "Geometry", kind: "type", declaration: "type Ray {\n  origin: Vec3 = Vec3 {};\n  direction: Vec3 = Vec3 { z: -1 };\n  length: Number = 1;\n}", status: "rendered",
191        representation: "Interpreter RecordValue geometry schema consumed by spatial adapters.",
192        members: [#[doc = "Local origin in meters; defaults to zero."] "origin", #[doc = "Local direction; spatial conversion requires magnitude greater than 1e-12 and normalizes the vector."] "direction", #[doc = "Visible distance in meters; defaults to 1."] "length"],
193        examples: [{ title: "Create a ray", description: "The default direction is local negative Z.", source: "let entity = spawn(Ray {});\nprint(get[Ray](entity).direction.z);", output: ["-1"], ticks: 0, presentation: "scene" }]
194    };
195    /// Indexed triangle geometry.
196    ///
197    /// The spatial adapter requires 3..=16384 positions and 1..=32768 triangles,
198    /// validates indices, and computes normals when it builds a render mesh.
199    pub const MESH: "Mesh" => {
200        category: "Geometry", kind: "type", declaration: "type Mesh { positions: Tensor[f32] = tensor[f32]([], [0, 3])?; indices: Tensor[u32] = tensor[u32]([], [0, 3])?; }", status: "rendered",
201        representation: "Interpreter RecordValue geometry schema; adapter validation produces the render mesh.",
202        members: [#[doc = "An N by 3 Tensor[f32] of local XYZ coordinates in meters. The empty default is not renderable."] "positions", #[doc = "An M by 3 Tensor[u32]; each row is a triangle and every index must address a position."] "indices"],
203        examples: [
204            { title: "Define one triangle", description: "Indices address positions in triples.", source: "let entity = spawn(Mesh { positions: tensor[f32]([0, 0, 0, 1, 0, 0, 0, 1, 0], [3, 3])?, indices: tensor[u32]([0, 1, 2], [1, 3])? });\nprint(get[Mesh](entity).indices.len());", output: ["3"], ticks: 0, presentation: "scene" },
205            { title: "Inspect an unfilled schema", description: "Construction itself does not invoke the mesh adapter.", source: "let value = Mesh {};\nprint(value.positions.len());", output: ["0"], ticks: 0, presentation: "snippet" }
206        ]
207    };
208    /// A bounded set of points rendered with a shared radius.
209    ///
210    /// Rendering requires 1 through 16384 points and a positive radius. The adapter
211    /// expands each point into tessellated sphere geometry, so this is not a point GPU primitive contract.
212    pub const POINT_CLOUD: "PointCloud" => {
213        category: "Geometry", kind: "type", declaration: "type PointCloud { points: Tensor[f32] = tensor[f32]([], [0, 3])?; radius: Number = 0.02; }", status: "rendered",
214        representation: "Interpreter RecordValue geometry schema; the adapter expands points into render geometry.",
215        members: [#[doc = "An N by 3 Tensor[f32] of local XYZ positions in meters; the adapter requires 1..=16384 points."] "points", #[doc = "Point radius in meters; defaults to 0.02."] "radius"],
216        examples: [{ title: "Create points", description: "A spatial adapter consumes the points when the value is attached to an entity.", source: "let entity = spawn(PointCloud { points: tensor[f32]([0, 0, 0, 1, 0, 0], [2, 3])? });\nprint(get[PointCloud](entity).points.shape()[0]?);", output: ["2"], ticks: 0, presentation: "scene" }]
217    };
218    /// Surface appearance for geometry rendered by the spatial adapter.
219    ///
220    /// The adapter validates `color` as #RRGGBB or #RRGGBBAA. Roughness must be
221    /// in 0..=1 and emissive intensity in 0..=100. Renderable geometry receives
222    /// default Transform and Material values when omitted.
223    pub const MATERIAL: "Material" => {
224        category: "Geometry", kind: "type", declaration: "type Material {\n  color: Str = \"#6fe3ff\";\n  roughness: Number = 0.6;\n  emissive: Number = 0;\n}", status: "rendered",
225        representation: "Interpreter RecordValue appearance schema consumed by spatial adapters.",
226        members: [#[doc = "Color in #RRGGBB or #RRGGBBAA form; defaults to #6fe3ff."] "color", #[doc = "Surface roughness from 0 through 1; defaults to 0.6."] "roughness", #[doc = "Emissive intensity from 0 through 100; defaults to 0."] "emissive"],
227        examples: [{ title: "Attach material", description: "Geometry receives a default material if none is attached by the spatial adapter.", source: "let entity = spawn(Sphere {});\nadd(entity, Material { color: \"#ff0000\" });\nprint(get[Material](entity).color);", output: ["#ff0000"], ticks: 0, presentation: "scene" }]
228    };
229    /// Physical-body configuration for a Sphere or Box entity.
230    ///
231    /// `kind` must be dynamic, fixed, or kinematic. Only dynamic bodies accept Force
232    /// or Impulse; fixed bodies must have zero velocities.
233    pub const RIGID_BODY: "RigidBody" => {
234        category: "Physics", kind: "type", declaration: "type RigidBody {\n  kind: Str = \"dynamic\";\n  mass: Number = 1;\n  velocity: Vec3 = Vec3 {};\n  angular_velocity: Vec3 = Vec3 {};\n  restitution: Number = 0.3;\n  friction: Number = 0.5;\n}", status: "physics",
235        representation: "Interpreter RecordValue physics schema consumed by the Rapier-backed spatial adapter.",
236        members: [#[doc = "dynamic, fixed, or kinematic; defaults to dynamic."] "kind", #[doc = "Positive mass used by the collider; defaults to 1."] "mass", #[doc = "Linear velocity in meters per second; defaults to zero."] "velocity", #[doc = "Angular velocity in radians per second; defaults to zero."] "angular_velocity", #[doc = "Bounciness in 0..=1; defaults to 0.3."] "restitution", #[doc = "Contact friction in 0..=1; defaults to 0.5."] "friction"],
237        examples: [
238            { title: "Advance a dynamic sphere", description: "Systems run before physics in each fixed tick, so the second callback observes the position advanced by the first integration step.", source: "let entity = spawn(Transform {});\nadd(entity, Sphere { radius: 0.5 });\nadd(entity, RigidBody { velocity: Vec3 { x: 1 } });\nsystem Observe of Transform {\n  func frame(dt: Number) -> Unit {\n    if tick > 1 { print(self.position.x > 0); }\n  }\n}", output: ["true"], ticks: 2, presentation: "scene" },
239            { title: "Choose a fixed body", description: "Fixed bodies keep zero velocity.", source: "let value = RigidBody { kind: \"fixed\" };\nprint(value.kind);", output: ["fixed"], ticks: 0, presentation: "snippet" }
240        ]
241    };
242    /// A world-space force applied every fixed physics tick.
243    ///
244    /// The physics adapter applies it only to a dynamic RigidBody and reapplies the
245    /// current value on each fixed step. Attaching Force without such a body is rejected.
246    pub const FORCE: "Force" => {
247        category: "Physics", kind: "type", declaration: "type Force { value: Vec3 = Vec3 {}; }", status: "physics",
248        representation: "Interpreter RecordValue force schema consumed by the physics adapter.",
249        members: [#[doc = "Force vector in newtons; defaults to zero and requires a dynamic RigidBody."] "value"],
250        examples: [{ title: "Apply force on fixed ticks", description: "The second callback observes movement produced by the first fixed integration step; the force remains attached for later steps.", source: "let entity = spawn(Transform {});\nadd(entity, Sphere {});\nadd(entity, RigidBody {});\nadd(entity, Force { value: Vec3 { x: 4 } });\nsystem Observe of Transform {\n  func frame(dt: Number) -> Unit {\n    if tick > 1 { print(self.position.x > 0); }\n  }\n}", output: ["true"], ticks: 2, presentation: "scene" }]
251    };
252    /// A world-space impulse consumed once by physics reconciliation.
253    ///
254    /// The physics adapter accepts it only with a dynamic RigidBody, applies it once,
255    /// then resets `value` to zero. Attaching Impulse without such a body is rejected.
256    pub const IMPULSE: "Impulse" => {
257        category: "Physics", kind: "type", declaration: "type Impulse { value: Vec3 = Vec3 {}; }", status: "physics",
258        representation: "Interpreter RecordValue impulse schema consumed by the physics adapter.",
259        members: [#[doc = "Impulse vector in newton-seconds; defaults to zero and requires a dynamic RigidBody."] "value"],
260        examples: [{ title: "Apply one impulse", description: "The second callback observes movement from the first integration step, after which the adapter has consumed the impulse.", source: "let entity = spawn(Transform {});\nadd(entity, Sphere {});\nadd(entity, RigidBody {});\nadd(entity, Impulse { value: Vec3 { x: 3 } });\nsystem Observe of Transform {\n  func frame(dt: Number) -> Unit {\n    if tick > 1 { print(self.position.x > 0); }\n  }\n}", output: ["true"], ticks: 2, presentation: "scene" }]
261    };
262    /// Visible text content represented as a host UI schema.
263    ///
264    /// Text is a declarative value only: layout, fonts, glyph shaping, and drawing
265    /// remain host responsibilities. Constructing it never performs text rendering by itself.
266    pub const TEXT: "Text" => {
267        category: "Interface", kind: "type", declaration: "type Text { value: Str = \"\"; size: Number = 0.2; }", status: "host UI",
268        representation: "Interpreter RecordValue schema; text layout and drawing are host responsibilities.",
269        members: [#[doc = "UTF-8 text content; defaults to empty."] "value", #[doc = "Requested text size in host scene units; defaults to 0.2."] "size"],
270        examples: [{ title: "Create text", description: "Construction records content but does not itself draw it.", source: "let value = Text { value: \"hello\" };\nprint(value.value);", output: ["hello"], ticks: 0, presentation: "snippet" }]
271    };
272    /// An image resource request with display dimensions.
273    ///
274    /// This schema declares desired resource data only. A host resolves `source`, owns
275    /// I/O and permissions, and reports any loading failure; construction performs no I/O.
276    pub const IMAGE: "Image" => {
277        category: "Media", kind: "type", declaration: "type Image {\n  source: Str = \"\";\n  width: Number = 1;\n  height: Number = 1;\n}", status: "resource contract",
278        representation: "Interpreter RecordValue resource schema, not an image decoder or Rust SDK image handle.",
279        members: [#[doc = "Host-defined image locator; defaults to empty."] "source", #[doc = "Requested display width in scene units; defaults to 1."] "width", #[doc = "Requested display height in scene units; defaults to 1."] "height"],
280        examples: [{ title: "Describe an image", description: "No file is read until a host chooses to resolve the source.", source: "let value = Image { source: \"poster.png\", width: 2 };\nprint(value.source);", output: ["poster.png"], ticks: 0, presentation: "snippet" }]
281    };
282    /// A video resource request with display dimensions.
283    ///
284    /// This is a schema, not playback: the host owns decoding, timing, I/O, and any
285    /// playback controls. Constructing it never starts a video.
286    pub const VIDEO: "Video" => {
287        category: "Media", kind: "type", declaration: "type Video {\n  source: Str = \"\";\n  width: Number = 1;\n  height: Number = 1;\n}", status: "resource contract",
288        representation: "Interpreter RecordValue resource schema, not a video decoder or playback handle.",
289        members: [#[doc = "Host-defined video locator; defaults to empty."] "source", #[doc = "Requested display width in scene units; defaults to 1."] "width", #[doc = "Requested display height in scene units; defaults to 1."] "height"],
290        examples: [{ title: "Describe a video", description: "The host decides whether and how the named resource plays.", source: "let value = Video { source: \"clip.mp4\" };\nprint(value.source);", output: ["clip.mp4"], ticks: 0, presentation: "snippet" }]
291    };
292    /// A live video input request with display dimensions.
293    ///
294    /// The host owns permission, capture lifecycle, frame orientation, and resource
295    /// contention. The default `camera` string is only a requested source selector.
296    pub const VIDEO_STREAM: "VideoStream" => {
297        category: "Media", kind: "type", declaration: "type VideoStream {\n  source: Str = \"camera\";\n  width: Number = 1;\n  height: Number = 1;\n}", status: "resource contract",
298        representation: "Interpreter RecordValue stream schema, not a camera session or frame source.",
299        members: [#[doc = "Host-defined live-video selector; defaults to camera."] "source", #[doc = "Requested display width in scene units; defaults to 1."] "width", #[doc = "Requested display height in scene units; defaults to 1."] "height"],
300        examples: [{ title: "Request a stream", description: "A host must grant permission and create the actual capture session.", source: "let value = VideoStream {};\nprint(value.source);", output: ["camera"], ticks: 0, presentation: "snippet" }]
301    };
302    /// An audio resource request with a gain value.
303    ///
304    /// This schema does not decode or play audio. The host resolves `source`, owns
305    /// I/O and playback lifecycle, and interprets the requested linear gain.
306    pub const AUDIO: "Audio" => {
307        category: "Media", kind: "type", declaration: "type Audio { source: Str = \"\"; volume: Number = 1; }", status: "resource contract",
308        representation: "Interpreter RecordValue resource schema, not an audio decoder or playback handle.",
309        members: [#[doc = "Host-defined audio locator; defaults to empty."] "source", #[doc = "Requested linear gain; defaults to 1 and is interpreted by the host."] "volume"],
310        examples: [{ title: "Describe audio", description: "Construction does not resolve or play the source.", source: "let value = Audio { source: \"tone.wav\", volume: 0.5 };\nprint(value.volume);", output: ["0.5"], ticks: 0, presentation: "snippet" }]
311    };
312    /// A live audio input request with a gain value.
313    ///
314    /// The host owns microphone permission, capture lifecycle, and stream routing;
315    /// this declaration does not open a microphone.
316    pub const AUDIO_STREAM: "AudioStream" => {
317        category: "Media", kind: "type", declaration: "type AudioStream { source: Str = \"microphone\"; volume: Number = 1; }", status: "resource contract",
318        representation: "Interpreter RecordValue stream schema, not a microphone session or audio buffer.",
319        members: [#[doc = "Host-defined live-audio selector; defaults to microphone."] "source", #[doc = "Requested linear gain; defaults to 1 and is interpreted by the host."] "volume"],
320        examples: [{ title: "Request audio input", description: "A host must grant permission and create any actual stream.", source: "let value = AudioStream {};\nprint(value.source);", output: ["microphone"], ticks: 0, presentation: "snippet" }]
321    };
322    /// A host-rendered control with a typed no-argument action.
323    ///
324    /// The host invokes `action` through Machine::invoke_component. The default `noop`
325    /// is intentional; a Button schema never dispatches an action by itself.
326    pub const BUTTON: "Button" => {
327        category: "Interface", kind: "type", declaration: "type Button { label: Str = \"Button\"; action: func() -> Res[Unit, DataError] = noop; }", status: "host UI",
328        representation: "Interpreter RecordValue UI schema; host input dispatch owns actual clicks.",
329        members: [#[doc = "Visible label; defaults to Button."] "label", #[doc = "Typed zero-argument callback; defaults to noop. Bind a live component method to persist mutations."] "action"],
330        examples: [
331            { title: "Use the default action", description: "The default callback is callable and produces no log output.", source: "let button = Button {};\nbutton.action()?;\nprint(button.label);", output: ["Button"], ticks: 0, presentation: "snippet" },
332            { title: "Expose a clickable control", description: "The spawned control retains a typed callback for host click dispatch; initialization makes the example's ready state observable.", source: "func activate() -> Res[Unit, DataError] { print(\"activated\"); ret Ok(()); }\nlet control = spawn(Button { label: \"Start\", action: activate });\nprint(\"button ready\");", output: ["button ready"], ticks: 0, presentation: "console" }
333        ]
334    };
335    /// A host-rendered numeric control with a typed value action.
336    ///
337    /// The host supplies a Number to `action`. A callback accepting input owns any
338    /// update to Slider.value; schema construction and host input do not mutate it automatically.
339    pub const SLIDER: "Slider" => {
340        category: "Interface", kind: "type", declaration: "type Slider {\n  label: Str = \"Slider\";\n  action: func(Number) -> Res[Unit, DataError] = ignore_number;\n  min: Number = 0;\n  max: Number = 1;\n  value: Number = 0;\n}", status: "host UI",
341        representation: "Interpreter RecordValue UI schema; host input dispatch owns actual slider interaction.",
342        members: [#[doc = "Visible label; defaults to Slider."] "label", #[doc = "Typed callback accepting the requested numeric value; defaults to ignore_number."] "action", #[doc = "Lower requested bound; defaults to 0. Hosts should present min no greater than max."] "min", #[doc = "Upper requested bound; defaults to 1. Hosts should present max no less than min."] "max", #[doc = "Current requested numeric value; defaults to 0 and changes only through explicit checked state updates."] "value"],
343        examples: [
344            { title: "Inspect defaults", description: "The default range is 0 through 1.", source: "let slider = Slider {};\nprint(slider.max);", output: ["1"], ticks: 0, presentation: "snippet" },
345            { title: "Expose a changeable control", description: "Change Gain: set_gain clamps the input, updates the stored Slider value, and logs the accepted value.", source: "func set_gain(value: Number) -> Res[Unit, DataError] {\n  let mut slider = get[Slider](control);\n  let accepted = value.clamp(slider.min, slider.max)?;\n  slider.value = accepted;\n  set(control, slider);\n  print(accepted);\n  ret Ok(());\n}\nlet control = spawn(Slider { label: \"Gain\", action: set_gain, min: 0, max: 2, value: 1 });\nprint(\"slider ready\");", output: ["slider ready"], ticks: 0, presentation: "console" }
346        ]
347    };
348    /// Decoded byte pixels with an explicit channel axis.
349    ///
350    /// Pixels have shape [height, width, channels], with 1, 3 or 4 channels for Gray, RGB or RGBA. Construction uses the SDK Image validator. Channel order follows the last axis; this value contains no encoded file or device handle.
351    pub const IMAGE_FRAME: "ImageFrame" => {
352        category: "Media", kind: "type", declaration: "type ImageFrame { pixels: Tensor[u8]; }", status: "runtime",
353        representation: "A checked language record delegating decoded media validation to konjure_sdk::data.",
354        members: [#[doc = "Packed u8 pixels; height and width are positive and channels is 1, 3 or 4."] "pixels"],
355        examples: [{ title: "Construct ImageFrame", description: "Inspect the typed payload and metadata.", source: "let image = ImageFrame { pixels: tensor[u8]([255, 0, 0, 255], [1, 1, 4])? };\nprint(image.pixels.shape());", output: ["[1, 1, 4]"], ticks: 0, presentation: "snippet" }]
356    };
357    /// Decoded audio samples with a checked sample rate.
358    ///
359    /// Samples have shape [sample_frames, channels] and finite f32 values. The SDK validates channel count and sample rate. This is a decoded block; playback, capture and scheduling belong to the host.
360    pub const AUDIO_BLOCK: "AudioBlock" => {
361        category: "Media", kind: "type", declaration: "type AudioBlock { samples: Tensor[f32]; sample_rate: u32; }", status: "runtime",
362        representation: "A checked language record delegating decoded media validation to konjure_sdk::data.",
363        members: [#[doc = "Sample-major f32 data with channels on the trailing axis."] "samples", #[doc = "Samples per second, from 1 through 384000."] "sample_rate"],
364        examples: [{ title: "Construct AudioBlock", description: "Inspect the typed payload and metadata.", source: "let audio = AudioBlock { samples: tensor[f32]([0, 0.5, 0, -0.5], [4, 1])?, sample_rate: 48000 };\nprint(audio.samples.shape());\nprint(audio.sample_rate);", output: ["[4, 1]", "48000"], ticks: 0, presentation: "snippet" }]
365    };
366    /// A decoded image associated with a presentation timestamp.
367    ///
368    /// Nanoseconds are exact u64 values, independent of wall-clock time. Place frames in a VideoClip to validate timestamp order and consistent image layout. A frame can be exchanged without starting a player or camera.
369    pub const VIDEO_FRAME: "VideoFrame" => {
370        category: "Media", kind: "type", declaration: "type VideoFrame { image: ImageFrame; timestamp_ns: u64; }", status: "runtime",
371        representation: "A checked language record delegating decoded media validation to konjure_sdk::data.",
372        members: [#[doc = "A validated decoded image."] "image", #[doc = "Presentation timestamp in nanoseconds; no wall-clock origin is implied."] "timestamp_ns"],
373        examples: [{ title: "Construct VideoFrame", description: "Inspect the typed payload and metadata.", source: "let frame = VideoFrame { image: ImageFrame { pixels: tensor[u8]([255], [1, 1, 1])? }, timestamp_ns: 16666667 };\nprint(frame.timestamp_ns);", output: ["16666667"], ticks: 0, presentation: "snippet" }]
374    };
375    /// An immutable-value sequence of validated decoded video frames.
376    ///
377    /// The SDK requires a nonempty sequence, strictly increasing timestamps and consistent image dimensions, dtype and channel format. Tensor buffers retain shared ownership. A live stream additionally needs host backpressure and lifetime handling.
378    pub const VIDEO_CLIP: "VideoClip" => {
379        category: "Media", kind: "type", declaration: "type VideoClip { frames: List[VideoFrame]; }", status: "runtime",
380        representation: "A checked language record delegating decoded media validation to konjure_sdk::data.",
381        members: [#[doc = "A nonempty ordered list of decoded frames with matching layouts."] "frames"],
382        examples: [{ title: "Construct VideoClip", description: "Inspect the typed payload and metadata.", source: "let image = ImageFrame { pixels: tensor[u8]([255, 0, 0], [1, 1, 3])? };\nlet clip = VideoClip { frames: [VideoFrame { image: image, timestamp_ns: 0 }, VideoFrame { image: image, timestamp_ns: 16666667 }] };\nprint(clip.frames.len());", output: ["2"], ticks: 0, presentation: "snippet" }]
383    };
384
385}