Creating Script Generation Warning.Md Animation
Script Generation Warning Animation - 3D Voxel Learning Example
This guide walks you through how to generate a looping 3D voxel animation of a warning display using SpatialStudio.
The script creates an animated warning interface with pulsing alert symbols, scrolling text, and glowing indicators inside a cubic 3D space, then saves the animation to a .splv
file.
What this script does
- Creates a 3D scene of size 128×128×128
- Generates a warning interface with:
- Pulsing triangular warning symbols
- Scrolling "SCRIPT GENERATION" text
- Blinking alert indicators
- Glowing borders and highlights
- Animates the warning display for 6 seconds at 30 FPS
- Outputs the file
script_generation_warning.splv
that you can play in your viewer
How it works (simplified)
-
Voxel volume Each frame is a 3D grid filled with RGBA values (
SIZE × SIZE × SIZE × 4
). -
Warning symbols Triangular warning icons are drawn with hollow centers and pulsing orange/red colors.
-
Text scrolling Letter shapes are rendered as voxel patterns that move horizontally across the display.
-
Alert indicators Small circular dots that blink on and off with different timing patterns.
-
Glow effects Bright yellow/white voxels create glowing borders and highlights around interface elements.
-
Animation loop A normalized time variable
t
cycles from0 → 2π
, ensuring smooth looping with synchronized pulsing and scrolling. -
Encoding Frames are passed into
splv.Encoder
, which writes them into the.splv
video file.
Try it yourself
Install requirements first:
pip install spatialstudio numpy tqdm
Then copy this script into script_generation_warning.py
and run:
python script_generation_warning.py
Full Script
import numpy as np
from spatialstudio import splv
from tqdm import tqdm
# Scene setup
SIZE, FPS, SECONDS = 128, 30, 6
FRAMES = FPS * SECONDS
CENTER_X = CENTER_Y = CENTER_Z = SIZE // 2
OUT_PATH = "../outputs/script_generation_warning.splv"
# Warning display settings
WARNING_SYMBOL_SIZE = 12
TEXT_HEIGHT = 8
INDICATOR_COUNT = 6
def add_voxel(volume, x, y, z, color):
if 0 <= x < SIZE and 0 <= y < SIZE and 0 <= z < SIZE:
volume[x, y, z, :3] = color
volume[x, y, z, 3] = 255
def generate_warning_triangle(volume, cx, cy, cz, size, intensity):
base_color = (255, int(140 * intensity), 0) # Orange to red
outline_color = (255, int(200 * intensity), int(100 * intensity))
# Draw triangle outline
for i in range(size):
# Left edge
x1 = cx - i
y1 = cy + size - i
add_voxel(volume, x1, y1, cz, outline_color)
# Right edge
x2 = cx + i
y2 = cy + size - i
add_voxel(volume, x2, y2, cz, outline_color)
# Base
if i < size:
add_voxel(volume, cx - size + i, cy + size, cz, outline_color)
add_voxel(volume, cx + size - i, cy + size, cz, outline_color)
# Fill triangle with pulsing color
for dy in range(size):
width = dy + 1
for dx in range(-width + 1, width):
add_voxel(volume, cx + dx, cy + size - dy, cz, base_color)
# Add exclamation mark
excl_color = (255, 255, 255)
for i in range(size // 2):
add_voxel(volume, cx, cy + size - 2 - i, cz + 1, excl_color)
add_voxel(volume, cx, cy + size, cz + 1, excl_color)
def generate_letter_pattern(letter, x_offset, y_offset, z_offset):
"""Return voxel coordinates for letter shapes"""
patterns = {
'S': [(0,0), (1,0), (2,0), (0,1), (1,2), (2,2), (2,3), (1,4), (0,4)],
'C': [(0,1), (0,2), (0,3), (1,0), (1,4), (2,0), (2,4)],
'R': [(0,0), (0,1), (0,2), (0,3), (0,4), (1,0), (1,2), (2,0), (2,1), (2,3), (2,4)],
'I': [(0,0), (1,0), (2,0), (1,1), (1,2), (1,3), (0,4), (1,4), (2,4)],
'P': [(0,0), (0,1), (0,2), (0,3), (0,4), (1,0), (1,2), (2,0), (2,1)],
'T': [(0,0), (1,0), (2,0), (1,1), (1,2), (1,3), (1,4)],
'G': [(1,0), (2,0), (0,1), (0,2), (0,3), (1,4), (2,4), (2,3), (1,2)],
'E': [(0,0), (0,1), (0,2), (0,3), (0,4), (1,0), (1,2), (1,4), (2,0), (2,2), (2,4)],
'N': [(0,0), (0,1), (0,2), (0,3), (0,4), (1,1), (2,2), (2,0), (2,1), (2,3), (2,4)],
'A': [(1,0), (0,1), (2,1), (0,2), (1,2), (2,2), (0,3), (2,3), (0,4), (2,4)],
'O': [(1,0), (0,1), (2,1), (0,2), (2,2), (0,3), (2,3), (1,4)],
}
coords = []
if letter in patterns:
for px, py in patterns[letter]:
coords.append((x_offset + px, y_offset + py, z_offset))
return coords
def generate_scrolling_text(volume, t):
text = "SCRIPT GENERATION"
text_color = (255, 255, 100) # Yellow
glow_color = (255, 255, 200) # Bright yellow glow
scroll_offset = int((t / (2*np.pi)) * 60) % 200
start_x = SIZE - scroll_offset
for i, char in enumerate(text):
if char == ' ':
continue
char_x = start_x + i * 6
char_y = CENTER_Y - 20
char_z = CENTER_Z + 5
if -10 < char_x < SIZE + 10: # Only render visible characters
coords = generate_letter_pattern(char, char_x, char_y, char_z)
# Draw letters with glow effect
for x, y, z in coords:
add_voxel(volume, x, y, z, text_color)
# Add glow around letters
for gx in [-1, 0, 1]:
for gy in [-1, 0, 1]:
if gx != 0 or gy != 0:
glow_intensity = 0.3
glow_col = tuple(int(c * glow_intensity) for c in glow_color)
add_voxel(volume, x+gx, y+gy, z-1, glow_col)
def generate_alert_indicators(volume, t):
indicator_color = (255, 50, 50) # Red
bright_color = (255, 150, 150) # Bright red
positions = [
(20, 20, CENTER_Z), (SIZE-20, 20, CENTER_Z),
(20, SIZE-20, CENTER_Z), (SIZE-20, SIZE-20, CENTER_Z),
(CENTER_X-30, CENTER_Y+30, CENTER_Z), (CENTER_X+30, CENTER_Y+30, CENTER_Z)
]
for i, (x, y, z) in enumerate(positions):
# Different blinking patterns for each indicator
blink_phase = (t + i * np.pi/3) % (2*np.pi)
if np.sin(blink_phase * 4) > 0:
color = bright_color if np.sin(blink_phase * 8) > 0.5 else indicator_color
# Draw circular indicator
for dx in range(-2, 3):
for dy in range(-2, 3):
if dx*dx + dy*dy <= 4:
add_voxel(volume, x+dx, y+dy, z, color)
def generate_warning_border(volume, t):
border_color = (255, 255, 0) # Yellow
pulse_intensity = (np.sin(t * 3) + 1) / 2 # Pulsing effect
final_color = tuple(int(c * (0.5 + pulse_intensity * 0.5)) for c in border_color)
# Draw border frame
thickness = 3
for i in range(thickness):
# Top and bottom edges
for x in range(SIZE):
for z in range(CENTER_Z-2, CENTER_Z+3):
add_voxel(volume, x, i, z, final_color)
add_voxel(volume, x, SIZE-1-i, z, final_color)
# Left and right edges
for y in range(SIZE):
for z in range(CENTER_Z-2, CENTER_Z+3):
add_voxel(volume, i, y, z, final_color)
add_voxel(volume, SIZE-1-i, y, z, final_color)
def generate_warning_display(volume, t):
# Main warning triangles
pulse = (np.sin(t * 2) + 1) / 2 * 0.7 + 0.3 # Pulsing intensity
# Left warning symbol
generate_warning_triangle(volume, CENTER_X - 35, CENTER_Y - 10, CENTER_Z,
WARNING_SYMBOL_SIZE, pulse)
# Right warning symbol
generate_warning_triangle(volume, CENTER_X + 35, CENTER_Y - 10, CENTER_Z,
WARNING_SYMBOL_SIZE, pulse * 0.8)
# Central warning (larger)
generate_warning_triangle(volume, CENTER_X, CENTER_Y + 10, CENTER_Z,
WARNING_SYMBOL_SIZE + 4, pulse * 1.2)
def generate_scene(volume, t):
generate_warning_border(volume, t)
generate_warning_display(volume, t)
generate_scrolling_text(volume, t)
generate_alert_indicators(volume, t)
enc = splv.Encoder(SIZE, SIZE, SIZE, framerate=FPS, outputPath=OUT_PATH, motionVectors="off")
for frame in tqdm(range(FRAMES), desc="Generating warning display"):
volume = np.zeros((SIZE, SIZE, SIZE, 4), dtype=np.uint8)
t = (frame / FRAMES) * 2*np.pi
generate_scene(volume, t)
enc.encode(splv.Frame(volume, lrAxis="x", udAxis="y", fbAxis="z"))
enc.finish()
print(f"Created {OUT_PATH}")
Next steps
- Change
WARNING_SYMBOL_SIZE
to make warning triangles larger or smaller. - Edit the
text
variable to display different scrolling messages. - Modify
INDICATOR_COUNT
and add more blinking alert positions. - Adjust pulsing speed by changing the multiplier in
np.sin(t * 2)
. - Add sound-reactive elements by making pulse intensity respond to audio input.