# PR-003 Runtime First Builtins: Color, Vec2, Pixel ## Goal Implement the first concrete builtin types, constants, and intrinsic behaviors so the frontend can target a stable MVP builtin line. This PR should be the first runtime feature slice that a PBS frontend can map to directly. ## Why After PR-001 and PR-002, the runtime has the machinery but not the domain set. This PR makes the model real by installing the first builtin registry entries and execution implementations. The initial scope should match the current agenda and spec direction: - scalar builtin `color` - aggregate builtin `vec2` - aggregate builtin `pixel` - intrinsic methods for `vec2` - builtin constant for `vec2.zero` ## Scope Add runtime registry entries and implementations for: - builtin type `color` - builtin type `vec2` - builtin type `pixel` - builtin constant `("vec2", "zero", 1)` - intrinsic `("vec2", "dot", 1)` - intrinsic `("vec2", "length", 1)` `("vec2", "distance", 1)` may be included if the numeric contract is already clear enough for portable behavior. If not, leave it for a follow-up PR. ## Builtin Type Contracts ### 1. `color` Canonical identity: ```text ("color", 1) ``` Expected properties: - scalar builtin - flat slot width `1` - runtime semantic distinctness from plain `int` Suggested field model: - `raw` carrier field if the runtime benefits from explicit internal naming ### 2. `vec2` Canonical identity: ```text ("vec2", 1) ``` Expected properties: - aggregate builtin - flattened layout `[float, float]` - field `x` at slot `0` - field `y` at slot `1` - flat slot width `2` ### 3. `pixel` Canonical identity: ```text ("pixel", 1) ``` Expected properties: - aggregate builtin - semantic layout `[int, int, color]` - flattened width `3` - field `x` at slot `0` - field `y` at slot `1` - field `color` at slot `2` ## Builtin Constant Contract ### `vec2.zero` Canonical identity: ```text ("vec2", "zero", 1) ``` Expected materialized value: ```text [0.0, 0.0] ``` This constant must be runtime-owned and materialized without touching the host. ## Intrinsic Contracts ### 1. `vec2.dot` Canonical identity: ```text ("vec2", "dot", 1) ``` Stack contract: ```text args: [float, float, float, float] ret: [float] ``` Semantic behavior: ```text (x1 * x2) + (y1 * y2) ``` ### 2. `vec2.length` Canonical identity: ```text ("vec2", "length", 1) ``` Stack contract: ```text args: [float, float] ret: [float] ``` Semantic behavior: ```text sqrt((x * x) + (y * y)) ``` ### 3. Optional: `vec2.distance` Canonical identity: ```text ("vec2", "distance", 1) ``` Stack contract: ```text args: [float, float, float, float] ret: [float] ``` Semantic behavior: ```text sqrt(((x1 - x2)^2) + ((y1 - y2)^2)) ``` Only include this if the runtime already has a clear portable numeric contract for `sqrt`. ## Representation Guidance ### `color` Choose one of: 1. dedicated scalar runtime variant with builtin nominal tag 2. 1-slot scalar carrier plus explicit builtin registry identity The critical rule is: - `color` must remain semantically a builtin color type, - even if its carrier width matches `int`. ### `vec2` and `pixel` Do not allocate heap objects for these in the MVP. Represent them as: - canonical stack-shaped flattened values, - with runtime metadata describing field offsets and nominal builtin identity. ## Numeric Contract Note `vec2.dot` is straightforward and should land in this PR. `vec2.length` and `vec2.distance` depend on the runtime's floating-point portability story. If that story is not already stable, implement: 1. `vec2.dot` 2. `vec2.zero` 3. builtin type descriptors for `color`, `vec2`, `pixel` and either: - gate `length`/`distance` behind the current platform float rules, - or defer them into a follow-up PR. ## Acceptance Criteria 1. Runtime registry contains builtin entries for `color`, `vec2`, and `pixel`. 2. Runtime registry contains builtin constant entry for `("vec2", "zero", 1)`. 3. Runtime registry contains intrinsic entries for at least `vec2.dot` and `vec2.length`. 4. `vec2` layout is width `2` and `pixel` layout is width `3`. 5. `pixel` composes `color` through builtin layout metadata rather than by special-case host code. 6. Executing `vec2.dot` and `vec2.length` through `INTRINSIC ` produces correct runtime results. 7. No part of the implementation routes through `SYSC`, `HOSTCALL`, or `SYSCALL`. ## Test Cases ### Builtin metadata - `color` width is `1` - `vec2` width is `2` - `pixel` width is `3` ### Constant materialization - materializing `("vec2", "zero", 1)` yields `[0.0, 0.0]` ### Intrinsic execution - `dot([1, 2], [3, 4]) == 11` - `length([3, 4]) == 5` ### Composition - `pixel(x=1, y=2, color=)` uses builtin metadata width `3` - `pixel.color` points at slot `2` ## Frontend Alignment This PR should be implemented so the following frontend surfaces map naturally: ```pbs [BuiltinType(name="vec2", version=1)] declare builtin type Vec2( [Slot(0)] pub x: float, [Slot(1)] pub y: float, ) { [IntrinsicCall(name="dot")] fn dot(other: Vec2) -> float; [IntrinsicCall(name="length")] fn length() -> float; } [BuiltinConst(target="vec2", name="zero", version=1)] declare const ZERO: Vec2; ``` The runtime should not care whether the source-visible type name is `Vec2`, `vec2`, or something else. It should care only about canonical identities and flattened layout.