Classes
A class is a struct with functions around it. Dispatch is static, so inheritance, a mixin and a generic are settled while the file is compiled.
-
Derived value in a base position
The compiler builds the base representation once when it proves read-only access and equivalent method dispatch. Overrides, receiver writes and observable alias mutation remain outside that proof.
TypeScript class Material {color: f32 = 0.5;response(): f32 { return this.color; }}class LeafMaterial extends Material {thickness: f32 = 1.;}function response(material: Material): f32 {return material.response();}export function leafResponse(): f32 {const material = new LeafMaterial();return response(material);}Emitted WGSL struct Material {color: f32,}struct LeafMaterial {color: f32,thickness: f32,}fn response(material: Material) -> f32 {return Material_response(material);}fn leafResponse() -> f32 {let material = LeafMaterial_new();return response(LeafMaterial_as_Material(material));} -
Class without fields
Construction and method calls work with no instance fields. The host value is
{}; the GPU receives an internal storage member that is absent from the source value.TypeScript class Counter {next(value: f32): f32 { return value + 1.; }}export function next(value: f32): f32 {return new Counter().next(value);}Emitted WGSL struct Counter {_empty: u32,}fn Counter_new() -> Counter {var self_: Counter = Counter(0u);return self_;}fn Counter_next(self_: Counter, value: f32) -> f32 {return (value + 1.0);}fn next(value: f32) -> f32 {return Counter_next(Counter_new(), value);} -
constructorandnewnewis a call ofRay_new, which builds the struct and hands it back.TypeScript class Ray {origin: vec3dir: vec3constructor(origin: vec3, dir: vec3) {this.origin = originthis.dir = dir}}Emitted WGSL fn Ray_new(origin: vec3<f32>, dir: vec3<f32>) -> Ray {let _cse0 = vec3<f32>(0.0, 0.0, 0.0);var self_: Ray = Ray(_cse0, _cse0);self_.origin = origin;self_.dir = dir;return self_;} -
Method
A function whose first parameter is the struct, and
thisreads as that parameter.TypeScript class Ray {origin: vec3dir: vec3at(t: f32): vec3 {return this.origin + this.dir * t}}Emitted WGSL fn Ray_at(self_: Ray, t: f32) -> vec3<f32> {return (self_.origin + (self_.dir * t));}fn hit(r: Ray) -> vec3<f32> {return Ray_at(r, 1.0);} -
staticmethodA function with no receiver, under the class name.
TypeScript class Ray {origin: vec3dir: vec3static up(): vec3 {return vec3(0., 1., 0.)}}Emitted WGSL fn Ray_up() -> vec3<f32> {return vec3<f32>(0.0, 1.0, 0.0);} -
Method that writes
thisA method that writes its object takes it by pointer on WGSL, and by
inouton GLSL ES 3.00. orbit-inoutTypeScript class Body {pos: vec3vel: vec3step(dt: f32): void {this.pos = this.pos + this.vel * dt}}Emitted WGSL fn Body_step(self_: ptr<function, Body>, dt: f32) {(*self_).pos = ((*self_).pos + ((*self_).vel * dt));} -
extendsandsuperThe base's fields come first, an inherited method is lowered again, and
superis a function of its own. shape-inheritanceTypeScript class Ring extends Circle {width: f32sdf(p: vec2): f32 {return abs(super.sdf(p)) - this.width}}Emitted WGSL struct Ring {center: vec2<f32>,radius: f32,width: f32,}fn Ring_sdf(self_: Ring, p: vec2<f32>) -> f32 {return (abs(Ring_super_Circle_sdf(self_, p)) - self_.width);} -
abstractclassNo struct for the abstract class. Each subclass carries the fields and its own copy of the method.
TypeScript abstract class Shape {center: vec2abstract sdf(p: vec2): f32offset(p: vec2): vec2 {return p - this.center}}Emitted WGSL struct Disc {center: vec2<f32>,radius: f32,}fn Disc_offset(self_: Disc, p: vec2<f32>) -> vec2<f32> {return (p - self_.center);} -
implementsChecked by TypeScript alone. The struct is the class's own fields.
TypeScript class Disc implements Placed {center: vec2radius: f32}Emitted WGSL struct Disc {center: vec2<f32>,radius: f32,} -
Access modifiers
Accepted, and they mean nothing to the shader. TypeScript is what enforces them.
TypeScript class Sphere {private center: vec3readonly radius: f32public hit(p: vec3): f32 {return length(p - this.center) - this.radius}}Emitted WGSL struct Sphere {center: vec3<f32>,radius: f32,}fn Sphere_hit(self_: Sphere, p: vec3<f32>) -> f32 {return (length((p - self_.center)) - self_.radius);} -
Getter and setter
Each half is a function of the module,
Disc_get_areaandDisc_set_area, and a read or a write calls it. class-syntaxTypeScript class Disc {radius: f32get area(): f32 {return this.radius * this.radius}}Emitted WGSL struct Disc {radius: f32,}fn Disc_get_area(self_: Disc) -> f32 {return (self_.radius * self_.radius);} -
Mixin function
The function runs while the file is compiled. Its members are spliced in, and
Tintedis emitted nowhere. mixin-surfaceTypeScript function Tinted<T extends AnyClass>(Base: T) {return class extends Base {tint: vec3lit(cover: f32): vec3 {return this.tint * cover}}}class TintedDisc extends Tinted(Disc) {}Emitted WGSL struct TintedDisc {center: vec2<f32>,radius: f32,tint: vec3<f32>,}fn TintedDisc_lit(self_: TintedDisc, cover: f32) -> vec3<f32> {return (self_.tint * cover);} -
Generic function
One function per set of type arguments the program uses, and nothing called
pick. generic-helpersTypeScript function pick<T>(a: T, b: T, c: bool): T {return c ? a : b}Emitted WGSL fn pick_f32(a: f32, b: f32, c: bool) -> f32 {return select(b, a, c);}fn pick_vec3(a: vec3<f32>, b: vec3<f32>, c: bool) -> vec3<f32> {return select(b, a, c);} -
Generic class
One struct per set of type arguments, each with its own copy of every method. generic-class
TypeScript class Slot<T> {a: Tb: Tfirst(): T {return this.a}}Emitted WGSL struct Slot_f32 {a: f32,b: f32,}struct Slot_vec3 {a: vec3<f32>,b: vec3<f32>,}