Values & shapes
One value type, every datum
A Value is the atom of a Prism document: a dtype plus a shape over a flat buffer. The dtype is one of bool, the signed and unsigned integer widths (int8 through uint64), the floats (float32, float64), or str. The shape is a scalar, a 1-D run, or a multi-dimensional array. That is the entire type system, and it is deliberately enough to express everything the higher content kinds need.
def object "ball" {
bool visible = true
float radius = 1.5
float3 albedo = (0.9, 0.2, 0.2) # a float32 of shape (3)
float[] weights = [0.1, 0.2, 0.4, 0.3] # a 1-D float32 array
str name = "ball"
}
Shapes, not classes
The familiar aggregates are sugar over fixed shapes, not separate types. float3 is a float32 of shape (3); a 4×4 matrix is a float32 of shape (4, 4); a colour is a small float vector; an image is a float32 (or uint8) array of shape (height, width, channels). One Value plus a shape covers a vector, a matrix, and a colour alike.
Value r = Float(1.5); // f32 scalar
Value rgb = Float3(0.9, 0.2, 0.2); // f32 shape (3)
Value pts = Value::array<float>({3, 2}, {0,0, 1,0, 1,1}); // f32 shape (3,2)
bool vis = r.isScalar(); // shape/dtype are introspectable
Why one type matters
A single Value is simultaneously a transform component in a scene, a channel of pixels in an image, a control point in a vector path, and the text of a paragraph in a document. Because of that, the codecs can share canonical models instead of inventing a schema per format: an OpenEXR channel, a mesh's vertex buffer, an SVG point list, and a heading's text are all typed arrays distinguished only by dtype and shape. The argument that "almost all data is typed values at named addresses" is implemented here, in Value.
Strict, typed access
A consumer always knows the type it holds. Kinogaki Core offers permissive getters that return an optional, and strict getters that demand a type and report a clear error if the document disagrees:
auto ball = doc.edit(Path("/world/ball"));
float r = ball.getFloat("radius", 1.0f); // permissive, with a default
Vec3 rgb = ball.requireFloat3("albedo"); // throws a located error if absent or mistypedball = doc.edit("/world/ball")
r = ball.get_float("radius", 1.0) # permissive, with a default
rgb = ball.require_float3("albedo") # raises a located error if absent or mistypedTyped values mean a reader always knows what it is holding, and a program (or an agent) can demand the shape it expects rather than guessing. From here, two axes build on the value: properties add a name and time, and connections let one value flow from another.