Your First Scene
Build a small Python scene: a title, a square, a circle, and two moves. By the end you can preview it in a window or write a PNG.
Rust engine contributors should use Your First Scene (Rust) instead.
Prerequisites​
python3 -m pip install murali-kit
See Installation if that fails.
The complete scene​
Save this as my_first_scene.py:
from murali_engine import Circle, Label, Scene, Square, Timeline
from murali_kit.colors import GREEN_D, RED_B, WHITE
from murali_kit.themes import DarkTheme
scene = Scene()
scene.apply_theme(DarkTheme())
title = scene.add(Label("My First Scene", height=0.38, color=WHITE))
scene.to_edge(title, "up", margin=0.8)
square = scene.add(
Square(size=1.2, color=RED_B).with_stroke(0.04, WHITE),
at=(-4.0, 0.0, 0.0),
)
circle = scene.add(
Circle(radius=0.65, color=GREEN_D, segments=48).with_stroke(0.04, WHITE),
at=(4.0, 0.0, 0.0),
)
timeline = Timeline()
timeline.animate(square).at(0.0).for_duration(2.0).ease("in_out_quad").move_to((2.0, 0.0, 0.0)).spawn()
timeline.animate(circle).at(0.5).for_duration(2.0).ease("out_quad").move_to((-2.0, 0.0, 0.0)).spawn()
scene.play(timeline)
scene.preview()
Run it:
python3 my_first_scene.py
What each part does​
Theme. Scene() comes from the engine. scene.apply_theme(DarkTheme()) is kit styling. The
engine does not own named themes.
Tattvas. scene.add(...) places an object and returns a handle. Use that handle to lay it out
and to animate it.
Position. at=(x, y, z) is world space, not pixels. The origin is the center of the frame.
to_edge(title, "up", margin=0.8) is a layout helper; "up", "down", "left", and "right"
are the direction names.
Color. Named swatches such as WHITE and RED_B live in murali_kit.colors. The engine
accepts any RGBA tuple (r, g, b, a) with values from 0.0 to 1.0.
Timeline. .animate(handle) starts a builder. .at(seconds) is start time, .for_duration(...)
is length, .ease(...) is the curve, then a verb such as .move_to(...). .spawn() commits
the animation. Without it, nothing is scheduled.
Play, then run. scene.play(timeline) installs the schedule. scene.preview() opens a window
and consumes the scene.
Export instead of preview​
Replace the last line with one of:
scene.save_png("my_first_scene.png", width=1920)
scene.export_video("my_first_scene.mp4", width=1920, fps=60)
Do not call preview(), save_png(), and export_video() on the same scene object. Each one
takes ownership of the scene.
A PNG at duration=0.0 is the opening frame. Appear, typewrite, and draw animations keep those
tattvas hidden on frame one, so a duration-zero PNG can look empty. Export a later time, or use
video, when you want the motion visible.
Portrait and other frames​
scene = Scene(frame="portrait")
scene.apply_theme(DarkTheme())
"landscape", "portrait", and "square" are the frame names. See Video Formats.
Coordinate system​
Right-handed world space:
- X — left (negative) to right (positive)
- Y — down (negative) to up (positive)
- Z — into the screen (negative) to toward the camera (positive)
If your numbers are in the hundreds, you are probably thinking in pixels. A circle of radius 1.0
is a reasonable starting size.
Kit examples​
Broader Python examples live in
murali-kit/examples.
hello_shapes.py and motion_basics.py are the next two to read.
What's next​
If nothing appears​
- Confirm
scene.play(timeline)runs beforepreview()/ export - Confirm every animation ends with
.spawn() - Stay near the origin; try
at=(0.0, 0.0, 0.0) - Use alpha
1.0so colors are opaque - Remember that
preview()cannot be followed bysave_png()on the same object