# Luma Language Reference ## Scalar Types | Type | Description | |------|-------------| | `bool` | Boolean (true/false) | | `int` | Signed 32-bit integer | | `uint` | Unsigned 32-bit integer | | `float` | 32-bit floating point | | `half` | 16-bit floating point | ## Vector Types Vectors of 2-4 components: `vec2`, `vec3`, `vec4` (float), `ivec2`-`ivec4` (int), `uvec2`-`uvec4` (uint), `bvec2`-`bvec4` (bool). Constructors: ```lua let v = vec3(1.0, 2.0, 3.0) let v2 = vec4(v, 1.0) -- expand vec3 to vec4 ``` Swizzling (xyzw, rgba, stpq): ```lua let xy = v.xy -- vec2 let zzz = v.zzz -- vec3 let r = color.r -- float ``` ## Matrix Types Square: `mat2`, `mat3`, `mat4`. Non-square: `mat2x3`, `mat3x4`, etc. Matrix-vector multiplication uses `*`: ```lua let clip = view_proj * model * vec4(pos, 1.0) ``` ## Array Types Fixed-size arrays: `[N]T`. ```lua @group(0) @binding(0) buffer lights: [16]Light -- Access by index let first = lights[0] ``` ## Sampler Types `sampler2D` represents a combined texture/sampler. During compilation, it is automatically split into separate texture and sampler bindings for backends that require it. ```lua @group(1) @binding(0) uniform tex: sampler2D -- In shader body: let color = sample(tex, uv) let mipped = sample_level(tex, uv, 2.0) ``` ## Structs ```lua struct MyStruct field1: vec3 field2: float end ``` ### Attributes on Fields ```lua struct VertexInput @location(0) position: vec3 @location(1) normal: vec3 @builtin(vertex_index) vid: uint end ``` ### Varying Structs `@varying` structs are shared between vertex output and fragment input. Fragment inputs automatically skip `@builtin` fields. ```lua @varying struct Interpolated @builtin(position) position: vec4 @location(0) uv: vec2 end ``` ## Functions ```lua function helper(a: vec3, b: vec3) -> float return dot(a, b) end ``` Functions cannot be recursive. All functions are inlined or statically dispatched. ## Entry Points ### Workflow stages ```lua vertex main in position: vec3 @location(0) in uv: vec2 @location(1) out clip: vec4 @builtin(position) out uv: vec2 do clip = vec4(position, 1.0) out.uv = uv end fragment shade in uv: vec2 out color: vec4 do return vec4(uv, 0.0, 1.0) end compute simulate @workgroup_size(64, 1, 1) do let i = work.global_id.x -- write storage buffers/resources end ``` `return expr` is only fragment single-output top-level sugar. Vertex stages use explicit `out` assignments. Compute stages do not return and cannot declare `out` slots. Workflow output assignments can appear in control flow if every non-discard path definitely assigns every output before stage exit. Overwrites are allowed. ### Compatibility entry syntax The older annotation syntax remains supported: ```lua @entry(vertex) function main(input: VertexInput) -> VertexOutput -- ... end @entry(fragment) function main(@location(0) uv: vec2) -> (color: vec4) return vec4(uv, 0.0, 1.0) end ``` ## Variables ```lua let x = 1.0 -- immutable, type inferred let y: float = 2.0 -- explicit type ``` Assignment requires mutable variables (loop variables, shared memory, buffer elements): ```lua for i = 0, 10 do shared_data[i] = float(i) end ``` ## Constants ```lua const PI = 3.14159 const MAX_LIGHTS: int = 16 ``` ### Specialization Constants ```lua @spec(0) const TILE_SIZE: int = 8 @spec(1) const USE_NORMAL_MAP: bool = true ``` ## Bindings ### Uniform Buffers ```lua group frame = 0 @binding(0) uniform camera: CameraData end ``` ### Storage Buffers ```lua group sim = 0 @binding(1) buffer particles: ParticleBuffer end ``` ### Textures ```lua group material = 1 @binding(0) texture diffuse: sampler2D end ``` ### Auto-numbering `@group` defaults to 0. `@binding` auto-increments within each group: ```lua uniform a: TypeA -- group=0, binding=0 uniform b: TypeB -- group=0, binding=1 @group(1) uniform c: sampler2D -- group=1, binding=0 (texture), binding=1 (sampler) group material = 1 texture c: sampler2D end ``` ## Shared Memory Workgroup-shared memory for compute shaders: ```lua shared tile: [64]float compute main @workgroup_size(64, 1, 1) do let idx = work.local_index tile[idx] = float(idx) barrier() -- all threads can now read tile end ``` ## Control Flow ### If/Elseif/Else ```lua if x > 0.0 then -- ... elseif x < 0.0 then -- ... else -- ... end ``` ### For Loop ```lua for i = 0, 10 do -- i goes from 0 to 9 -- ... end for i = 0, 100, 2 do -- step of 2 -- ... end ``` ### While Loop ```lua while dist > 0.001 do -- ... end ``` ## Operators | Category | Operators | |----------|-----------| | Arithmetic | `+`, `-`, `*`, `/`, `%` | | Comparison | `==`, `~=`, `<`, `>`, `<=`, `>=` | | Logical | `and`, `or`, `not` | | Unary | `-` (negate), `not` | ## Preprocessor ```lua #include "common.luma" ``` Include paths are resolved relative to the source file and any `--include-dir` paths. ## Built-in Variables ### Vertex | Name | Type | Description | |------|------|-------------| | `position` | `vec4` | Clip-space position (output) | | `vertex_index` | `uint` | Vertex index (input) | | `instance_index` | `uint` | Instance index (input) | ### Fragment | Name | Type | Description | |------|------|-------------| | `position` | `vec4` | Fragment coord (input) | | `front_facing` | `bool` | Front-facing (input) | | `frag_depth` | `float` | Depth override (output) | ### Compute | Name | Type | Description | |------|------|-------------| | `global_invocation_id` | `uvec3` | Global thread ID | | `local_invocation_id` | `uvec3` | Local thread ID | | `workgroup_id` | `uvec3` | Workgroup ID | | `num_workgroups` | `uvec3` | Total workgroups | | `local_invocation_index` | `uint` | Flattened local index |