Skip to main content
Version: Next 🚧

Coordinate system

Murali uses a right-handed world space with the origin at the center of the frame. Positions are not pixels.

Axes​

  • X — left (negative) to right (positive)
  • Y — down (negative) to up (positive)
  • Z — into the screen (negative) to toward the camera (positive)
from murali_engine import Circle, Scene
from murali_kit.colors import GREEN_D, WHITE
from murali_kit.themes import DarkTheme

scene = Scene()
scene.apply_theme(DarkTheme())
scene.add(Circle(radius=0.8, color=GREEN_D).with_stroke(0.04, WHITE), at=(0.0, 0.0, 0.0))
scene.add(Circle(radius=0.4, color=GREEN_D), at=(-4.0, 2.5, 0.0))

If your numbers are in the hundreds, you are thinking in pixels. A circle of radius 1.0 is a reasonable starting size.

Frames​

Every scene owns a composition frame. Landscape is the default:

Scene()
Scene(frame="portrait")
Scene(frame="square")
FrameAspectX boundsY bounds
"landscape"16:9-8 to 8-4.5 to 4.5
"portrait"9:16-4.5 to 4.5-8 to 8
"square"1:1-8 to 8-8 to 8

Selecting portrait does not reflow existing objects. Compose inside that frame. Layout helpers such as to_edge use the frame immediately.

See Video Formats.

Layout​

title = scene.add(Label("Title", height=0.38, color=WHITE))
scene.to_edge(title, "up", margin=0.8)
scene.next_to(caption, title, "down", 0.4)
scene.align_to(left, right, "center")

Directions are "up", "down", "left", "right". Kit Group, HStack, and VStack stack handles when several objects should move together.

Camera​

Orthographic by default. In 2D, set_view_width controls how much world fits across the frame. Camera Z does not change the ortho crop.

scene.set_view_width(16.0)
scene.set_camera(position=(0.0, 0.0, 10.0), target=(0.0, 0.0, 0.0))

See Camera.

Colors​

The engine takes RGBA tuples (r, g, b, a) in 0.0…1.0. Named swatches live in kit:

from murali_kit.colors import WHITE, BLUE_D, GOLD_C

WHITE # (1, 1, 1, 1)
(1.0, 0.0, 0.0, 0.5) # also fine

The color table is on Visual Foundations.