KloradDocs

Physical correspondence

Digital Object, Digital Shadow, Digital Twin. Every Scene Object says how it relates to the physical world.

"Digital twin" is used loosely for anything in 3D. Klorad is strict about it, because the difference decides what code may do with an object. Every Scene Object has a correspondence, and there are three.

Digital Objectcorrespondence: "object"
Physical· · ·Digital
Modelled only: a building, a zone, a label.
Digital Shadowcorrespondence: "shadow"
Physical──▶Digital
Physical state flows in as timestamped readings.
Digital Twincorrespondence: "twin"
Physical◀──▶Digital
Readings flow in, authorised commands flow out.
KindcorrespondenceHas a bindingAccepts readingsAccepts commands
Digital Object"object" (the default)nonono
Digital Shadow"shadow"yesyesno
Digital Twin"twin"yesyesyes, through an actuator

A Digital Object is modelled only. Nothing physical updates it: a building footprint, a zone, a planned extension. It changes only when your code or a Behaviour changes it.

A Digital Shadow mirrors a physical thing one way. Its binding names a source and an entity in that source, and readings from there become its state. Your code cannot command it, because there is nothing to command: a footfall counter, a temperature probe, a bin fill sensor.

A Digital Twin mirrors a physical thing both ways. Readings flow in like a shadow's, and an authorised Action can send a command back to the device. The twin's state still changes only when the device reports it: Klorad never pretends a barrier is open because someone asked it to open.

The types enforce it

A shadow or a twin without a binding does not compile, and a spec that has a binding but does not say "shadow" or "twin" does not compile either (and add throws on it in plain JavaScript), so a sensor is never silently demoted to a plain object. At runtime, offering a reading to a Digital Object returns { status: "rejected", reason: "not-observable" }. isObservable(object) narrows a SceneObject to a shadow or a twin.

scene.add({ name: "Probe", position: { east: 0, north: 0 }, binding: { source: "bms", entity: "t1" } });
// type error: a binding needs correspondence: "shadow" or "twin"

Choosing

Start from the physical thing. If nothing reports on it, it is an object. If something reports on it and you only watch, it is a shadow. Make it a twin only when you have a real path to command it, and an Action that uses that path.

Run it liveSandbox: Scene ObjectsDigital Objects, Shadows and Twins added, moved and removed; every change is one ordered event.

Something wrong or unclear? Tell your contact at Prieston Technologies.