3D worlds, coordinates, and cameras

Programming guides

3D means three dimensions: width, height, and depth. A position (x, y, z) is measured along three imaginary rulers, called axes. Their meeting point (0, 0, 0) is the origin. Pliro measures distances in world units: units you choose for your imaginary world, not screen pixels. Here +Y points up. At the camera’s starting angle, +X is right and -Z is forward.

The camera is the viewpoint from which you see the world. Yaw turns it left or right; pitch tilts it up or down. Angles use degrees: 90 is a quarter-turn and 360 is a full turn. Yaw 0 faces -Z, positive yaw turns right, and positive pitch looks up. Moving the camera stays horizontal even while it looks up or down; positive sideways movement goes to its right.

Wrapping an angle brings it back around the circle: yaw 370 becomes 10. The notation [0, 360) includes 0 but excludes 360. Clamping stops a value at a limit: camera pitch 100 becomes 89. The range [-89, 89] includes both ends. An absolute value is a number’s distance from zero: -5 and 5 both have absolute value 5.

Shapes and the camera

A primitive is a basic shape, such as a box, sphere, or cylinder. A radius goes from the center to the edge; the diameter goes all the way across and is twice as large. A cylinder’s axis is the imaginary line through the centers of its round ends. Geometry means the mathematical shape and its dimensions. An oriented box follows its rotation; an axis-aligned box would keep its edges parallel to the world’s axes.

A collider is an invisible shape used to check whether movement would hit something. Pliro’s camera collider is a small ball. A solid object can block moveCamera3D; turning solidity off does not hide an object or exclude it from touching3D and aim3D.

A ray is an imaginary straight line cast forward from the camera to ask what it points at. The nearest hit is the first object it meets within the allowed distance. These checks use shapes, not the colors of screen pixels. Insertion order means the order in which objects were first created.

Field of view is how wide an angle the camera sees. Near and far planes mark the distance window used when drawing; they are not walls in the world. A texture is a surface pattern. Its scale here controls how many pattern repetitions fit in one unit measured along the object.

A frame is one complete drawn picture. A HUD, short for heads-up display, is information such as a score drawn over the world. Rendering means making that picture. WebGL2 is a browser graphics interface that can use the GPU, the processor specialized in drawing. A software renderer does the drawing calculations on the main processor, the CPU. See MDN’s WebGL explanation.

World settings and limits

Boxes use full width, height, and depth. Cylinders use radius and full height,
with their axis along +Y. Objects start at (0, 0, 0) with yaw 0, color
"#f59e0b", solidity true, pattern "none", and texture scale 1. Recreating a
name resets all those properties but preserves its insertion order.

Value Requirement
Object name Case-sensitive, non-blank Text, at most 64 UTF-8 bytes.
World capacity At most 256 objects.
Position component Finite Number, absolute value at most 10,000.
Dimension or radius Finite Number, greater than 0 and at most 1,000.
Turn amount Finite Number, absolute value at most 1,000,000,000.
Camera move component Finite Number, absolute value at most 10 per call.
Aiming distance Finite Number, greater than 0 and at most 1,000.
Texture scale Finite Number, greater than 0 and at most 32.

Object operations require an existing name, except shape creation and the
no-op removal of an absent name. Invalid arguments do not partially change the
world. Colors follow the portable color table.

The initial/reset camera is at (0, 1.5, 5) with yaw and pitch 0, a vertical
field of view of 60 degrees, and near/far planes of 0.05 and 1,000. camera3D
places it directly, even inside objects. lookAt3D rejects a target equal to
the camera position. moveCamera3D uses a radius-0.2 camera collider against
solid objects, with bounded steps, X then Z movement, and wall sliding. There
is no automatic gravity, jumping, velocity, or object movement.

touching3D uses the actual primitive geometry, independently of the solid
flag. aim3D includes nonsolid objects and returns the nearest hit; equal
hits prefer insertion order, and a ray starting inside an object hits at zero
distance. These queries do not depend on rendered pixels.

texture3D accepts "none", "checker", and "brick", ignoring surrounding
whitespace and letter case. Scale means pattern repetitions per local world
unit; omitting it resets scale to 1. Patterns move with the object, require no
image assets, and preserve its color, geometry, and solidity. Pattern strings
are data and are not translated with the syntax locale.

World changes do not draw automatically. draw3D() captures a complete frame,
replacing previous 2D shapes and sprites. Draw 2D text or shapes after it for
a HUD, then use a positive wait in an animation loop. clearCanvas hides the
3D frame without deleting the world. clear3D resets the world and camera but
needs a following draw3D() to display the result. Reset/disposal releases the
world; normal Stop preserves the last visible frame.

IDE/browser rendering uses WebGL2 with a fallback or diagnostic when unavailable.
Native Windows, Linux, and Raspberry Pi use a software renderer at 640 × 360.
Pixel edges may differ across renderers; world state, movement, collision, and
aiming results have the same semantics. See the 3D specification.

# language: en
clear3D("#16213e")
box3D("crate", 1.5, 1.5, 1.5)
color3D("crate", "orange")
texture3D("crate", "checker", 2)
turn3D("crate", 25)

cylinder3D("pillar", 0.35, 2)
position3D("pillar", 2, 0, 0)
color3D("pillar", "blauw")
texture3D("pillar", "brick")

sphere3D("ball", 0.5)
position3D("ball", -2, 0, 0)
color3D("ball", "rood")
solid3D("ball", false)

camera3D(0, 2, 6)
lookAt3D(0, 0, 0)
say "Crate touches pillar:", touching3D("crate", "pillar")
say "Aimed object:", aim3D(20)
draw3D()
drawText(320, 20, "My 3D world", 24, "white", "sans", "center")

The pattern strings and mixed English/Dutch color values stay unchanged when
this program is converted to Dutch syntax. More examples are available in
rotating-box.pliro and
laser-maze-3d.pliro.

Syntax and values · Built-ins · Programming guides