NaraMotion / DOCUMENTATION.md
ArifiIslam's picture
Release NaraMotion v0.26.0: Structure of Arrays (SoA), Path Arena Allocator, Uniform Grid Indexing, Dual-Buffer Rendering & Centroid Spring Pop-in
b516e00 verified
|
Raw History Blame Contribute Delete
35.9 kB

NaraMotion Complete API Documentation & Reference Guide 📚✨

Author & Creator: Islam Arifi
Official PyPI Package: naramotion (v0.26.0)
Core Engine: Powered by Blend2D (Native C++ JIT Compiler & SIMD Hardware Acceleration)
License: Proprietary Commercial License (with Evaluation Mode)


📑 Table of Contents

  1. Official Installation
  2. Commercial License & Evaluation Watermark Removal
  3. Architectural Overview: C++ vs. Python
  4. C++ to Python Translation Cheat Sheet
  5. Strict Color Input Specifications & Restrictions
  6. Image Handling (naramotion.Image)
  7. 2D Rendering Context (naramotion.Context)
  8. Vector Path Builder (naramotion.Path)
  9. Typography & Fonts (naramotion.Font, naramotion.FontFace)
  10. Gradients & Patterns (naramotion.style)
  11. Geometric Primitives (naramotion.geometry)
  12. Affine Transformations (naramotion.Matrix2D)
  13. Bulk & Batch Operations for Big Data
  14. Zero-Copy NumPy & FFmpeg Video Streaming
  15. Hardware-Accelerated Video Engine (naramotion.video)
  16. Geospatial & Big Data Engine (naramotion.shapgeo / naramotion.geo)
  17. Motion Graphics & Animation (naramotion.motion)
  18. Kinetic Perspective & 3D Globe (naramotion.motion.PerspectiveCamera)
  19. Cinematic Visual FX & Post-Processing (naramotion.fx)
  20. Enumerations Reference
  21. Performance & Best Practices Guide
  22. Comprehensive Error Catalog, Exceptions & Troubleshooting Guide

1. Official Installation

NaraMotion is published officially on PyPI (naramotion) with pre-compiled native C++ binaries for maximum performance:

📦 Standard PyPI Installation:

pip install naramotion

🛠️ Optional Ecosystem Dependencies:

# NumPy & Pillow integration (Zero-Copy views)
pip install "naramotion[numpy,pil]"

# Full GIS & Testing Suite (GeoPandas, Shapely, Pytest)
pip install "naramotion[all]"

✅ Quick Verification & Sanity Check:

import naramotion

print(f"✨ NaraMotion Version: {naramotion.__version__} by {naramotion.__author__}")

# Render test surface
img = naramotion.Image(400, 400)
with naramotion.Context(img) as ctx:
    ctx.fill_all("#090D16")
    ctx.fill_circle(200, 200, 80, "#38BDF8")

img.save("test_render.png")
print("🚀 NaraMotion is installed and rendering with 100% hardware acceleration!")

2. Commercial License & Evaluation Watermark Removal

NaraMotion is distributed under a Proprietary Commercial License with an Evaluation Mode.

Evaluation Mode Behavior:

  • When unlicensed, rendered images saved to disk or encoded to bytes contain a semi-transparent "Auras" watermark in the center.
  • Full API functionality, SIMD acceleration, GIS, and video features remain active during evaluation.

Activating the Commercial License:

Call naramotion.set_license() with your commercial activation key at script startup:

import naramotion

# Activate commercial license (replaces 'YOUR_COMMERCIAL_KEY' with your purchased key)
naramotion.set_license("YOUR_COMMERCIAL_KEY")

print(f"🔑 License Activated: {naramotion.is_licensed()}")

Or set the environment variable on your system/server:

export NARAMOTION_LICENSE_KEY="YOUR_COMMERCIAL_KEY"  # Linux / macOS
set NARAMOTION_LICENSE_KEY="YOUR_COMMERCIAL_KEY"     # Windows

3. Architectural Overview: C++ vs. Python

NaraMotion exposes the full power of Blend2D's native JIT engine while adapting all APIs into clean, idiomatic Python:

Concept C++ (Blend2D) Python (NaraMotion)
Naming Convention CamelCase (fillCircle, setStrokeWidth) snake_case (fill_circle, stroke_width = ...)
Context Lifecycle BLContext ctx(img); ... ctx.end(); with Context(img) as ctx: (Auto end/flush)
Colors BLRgba32(0xFF0000FF) String ("#FF0000"), Tuple (255, 0, 0), or 0xFFFF0000
Properties ctx.setCompOp(...), ctx.getCompOp() ctx.comp_op = CompOp.SRC_OVER
Matrix Math m.postTranslate(x, y) m.translate(x, y) or m1 * m2
NumPy Access BLImageData::pixelData img.to_numpy(copy=False) (Zero-copy ndarray)
Video Streaming Manual pointer copy img.buffer (Zero-copy Python memoryview)

4. C++ to Python Translation Cheat Sheet

Creating an Image and Context

C++:

BLImage img(800, 600, BL_FORMAT_PRGB32);
BLContext ctx(img);
ctx.fillAll(BLRgba32(0xFF000000));
ctx.fillCircle(BLCircle(400, 300, 100), BLRgba32(0xFFFF3366));
ctx.end();
img.writeToFile("output.png");

Python:

from naramotion import Image, Context, Format

img = Image(800, 600, Format.PRGB32)
with Context(img) as ctx:
    ctx.fill_all("black")
    ctx.fill_circle(400, 300, 100, "#FF3366")

img.save("output.png")

5. Strict Color Input Specifications & Restrictions

Strict C++ Parser Rule: The Blend2D parser does NOT accept CSS functional syntax like "rgba(255, 0, 0, 0.5)" or "rgb(0, 255, 0)". Colors must strictly be provided in one of the 5 formats below:

Format Type Syntax Example Technical Notes
1. Hex String (RGB) "#38BDF8" or "#F00" 6 or 3 hex characters prefixed with #
2. Hex String with Alpha (RGBA) "#38BDF888" or "#F008" 8 or 4 hex characters (AA at end)
3. Named SVG / CSS Colors "crimson", "deepskyblue", "black" Standard keyword identifiers
4. Numeric Tuple (RGB / RGBA) (56, 189, 248) or (56, 189, 248, 128) Integers strictly between [0, 255]
5. 32-bit Packed Integer (ARGB) 0x8838BDF8 Memory layout: 0xAARRGGBB
6. Class Instances Rgba32(56, 189, 248, 255) or Rgba(0.22, 0.74, 0.97, 1.0) Native C struct wrappers

6. Image Handling (naramotion.Image)

# Constructor Signature:
Image(width: int = 0, height: int = 0, format: Format = Format.PRGB32)
# 3-Line MWE:
from naramotion import Image, Format
img = Image(1920, 1080, Format.PRGB32)
img.save("frame.png")

Supported Pixel Formats:

  • Format.PRGB32: 32-bit Premultiplied ARGB (Default, fastest SIMD execution and highest quality).
  • Format.XRGB32: 32-bit RGB with ignored alpha.
  • Format.A8: 8-bit Alpha mask only (ideal for glyph caches and matte compositing).

Complete Method Signatures:

  • img.create(width: int, height: int, format: Format = Format.PRGB32): Reallocate image buffer.
  • img.reset(): Free underlying native image memory.
  • img.copy() -> Image / img.clone() -> Image: Create a deep copy of the image.
  • img.convert(format: Format): In-place format conversion.
  • img.read_from_file(path: str): Load PNG, JPEG, BMP from disk.
  • img.write_to_file(path: str, codec: str = "PNG"): Write to disk.
  • img.save(path: str): Alias for write_to_file.
  • img.to_data(codec: str = "PNG") -> bytes: Encode directly to in-memory bytes.
  • Image.from_file(path: str) -> Image: Classmethod to load an image.
  • Image.from_data(data: bytes) -> Image: Classmethod to decode bytes.
  • img.to_numpy(copy: bool = False) -> np.ndarray: Return (H, W, 4) uint8 BGRA view.
  • Image.from_numpy(arr: np.ndarray) -> Image: Wrap or copy NumPy ndarray into Blend2D Image.
  • img.to_pil() -> PIL.Image: Convert to Pillow Image.
  • Image.from_pil(pil_img) -> Image: Convert Pillow Image to Blend2D Image.
  • img.buffer -> memoryview: Zero-copy memoryview for high-throughput streaming.

7. 2D Rendering Context (naramotion.Context)

# Context Manager Usage:
with Context(image: Image) as ctx:
    ...
# 3-Line MWE:
from naramotion import Image, Context
img = Image(800, 600)
with Context(img) as ctx:
    ctx.fill_all("#0B0F19")
    ctx.fill_circle(400, 300, 120, "#38BDF8")

Complete Rendering API Signatures:

1. Canvas Clearing & Rectangles:

  • ctx.fill_all(style): Fill entire surface with color, gradient, or pattern.
  • ctx.clear_all(): Clear surface to fully transparent black (0x00000000).
  • ctx.fill_rect(x: float, y: float, w: float, h: float, style)
  • ctx.stroke_rect(x: float, y: float, w: float, h: float, style)
  • ctx.fill_round_rect(x: float, y: float, w: float, h: float, rx: float, ry: Optional[float] = None, style)
  • ctx.stroke_round_rect(x: float, y: float, w: float, h: float, rx: float, ry: Optional[float] = None, style)

2. Circles, Ellipses & Arcs:

  • ctx.fill_circle(cx: float, cy: float, r: float, style)
  • ctx.stroke_circle(cx: float, cy: float, r: float, style)
  • ctx.fill_ellipse(cx: float, cy: float, rx: float, ry: float, style)
  • ctx.stroke_ellipse(cx: float, cy: float, rx: float, ry: float, style)
  • ctx.fill_arc(cx: float, cy: float, rx: float, ry: float, start: float, sweep: float, style)
  • ctx.stroke_arc(cx: float, cy: float, rx: float, ry: float, start: float, sweep: float, style)
  • ctx.fill_chord(cx: float, cy: float, rx: float, ry: float, start: float, sweep: float, style)
  • ctx.fill_pie(cx: float, cy: float, rx: float, ry: float, start: float, sweep: float, style)

3. Lines & Polygons:

  • ctx.stroke_line(x0: float, y0: float, x1: float, y1: float, style)
  • ctx.fill_polygon(points: Sequence[Tuple[float, float]], style)
  • ctx.stroke_polygon(points: Sequence[Tuple[float, float]], style)
  • ctx.fill_polyline(points: Sequence[Tuple[float, float]], style)
  • ctx.stroke_polyline(points: Sequence[Tuple[float, float]], style)

4. Vector Paths:

  • ctx.fill_path(path: Path, style)
  • ctx.stroke_path(path: Path, style)

5. Image Blitting:

  • ctx.blit_image(pt_or_x, y_or_img, image=None, src_rect=None): Blit an image at specified coordinates.

6. State Stack & Clipping:

  • ctx.save() -> int: Push context state (matrix, clip, styles) and return cookie ID.
  • ctx.restore(cookie: Optional[int] = None): Pop state back to cookie ID.
  • ctx.clip_to_rect(x: float, y: float, w: float, h: float)
  • ctx.clip_to_path(path: Path)
  • ctx.restore_clipping()

7. Context Properties:

  • ctx.comp_op = CompOp.SRC_OVER: Composite operation mode.
  • ctx.global_alpha = 0.75: Global opacity multiplier [0.0, 1.0].
  • ctx.stroke_width = 3.5: Stroke line width in pixels.
  • ctx.stroke_cap = StrokeCap.ROUND: Stroke end caps (BUTT, SQUARE, ROUND).
  • ctx.stroke_join = StrokeJoin.ROUND: Corner joins (MITER_CLIP, BEVEL, ROUND).
  • ctx.stroke_miter_limit = 4.0: Miter limit ratio.
  • ctx.stroke_dash_offset = 0.0: Dash pattern offset.
  • ctx.set_stroke_dash_array(dashes: Sequence[float]): e.g. [10.0, 5.0].

8. Vector Path Builder (naramotion.Path)

# Constructor Signature:
Path()
# 3-Line MWE:
from naramotion import Path
p = Path()
p.move_to(100, 100).line_to(200, 100).cubic_to(250, 150, 250, 250, 100, 200).close()

Path Verbs & Signatures:

  • p.move_to(x: float, y: float) -> Path
  • p.line_to(x: float, y: float) -> Path
  • p.quad_to(x1: float, y1: float, x2: float, y2: float) -> Path
  • p.cubic_to(x1: float, y1: float, x2: float, y2: float, x3: float, y3: float) -> Path
  • p.arc_to(cx: float, cy: float, rx: float, ry: float, start: float, sweep: float) -> Path
  • p.close() -> Path
  • p.clear() -> Path
  • p.add_circle(cx: float, cy: float, r: float) -> Path
  • p.add_rect(x: float, y: float, w: float, h: float) -> Path
  • p.add_round_rect(x: float, y: float, w: float, h: float, rx: float, ry: Optional[float] = None) -> Path
  • p.add_path(other: Path, matrix: Optional[Matrix2D] = None) -> Path
  • p.hit_test(x: float, y: float, fill_rule: FillRule = FillRule.NON_ZERO) -> HitTest
  • p.get_length() -> float: Calculate total arc length in pixels.
  • p.get_vertices() -> List[Tuple[int, float, float]]: Extract raw control points and verb tags.
  • p.to_svg_d() -> str: Export path as standard SVG d="..." string.

9. Typography & Fonts (naramotion.Font, naramotion.FontFace)

# Signatures:
FontFace.from_file(filepath: str) -> FontFace
Font(face: FontFace, size: float = 12.0)
# 3-Line MWE:
from naramotion import FontFace, Font, Context
face = FontFace.from_file("C:/Windows/Fonts/arial.ttf")
font = Font(face, size=32.0)
ctx.fill_text(100, 100, font, "NaraMotion Engine", style="#FFFFFF")

Metrics & Text Measurement:

  • font.metrics: Returns ascent, descent, line gap, x-height, cap-height.
  • font.get_text_metrics(text: str): Returns text advance vector (advance.x, advance.y) and bounding box.
  • ctx.fill_text(x: float, y: float, font: Font, text: str, style)
  • ctx.stroke_text(x: float, y: float, font: Font, text: str, style)

10. Gradients & Patterns (naramotion.style)

1. Linear Gradient:

LinearGradient(x0: float, y0: float, x1: float, y1: float, extend_mode: ExtendMode = ExtendMode.PAD)
from naramotion.style import LinearGradient
grad = LinearGradient(0, 0, 800, 0)
grad.add_stop(0.0, "#38BDF8").add_stop(1.0, "#F43F5E")
ctx.fill_rect(0, 0, 800, 600, style=grad)

2. Radial Gradient:

RadialGradient(x0: float, y0: float, x1: float, y1: float, r0: float, extend_mode: ExtendMode = ExtendMode.PAD)
from naramotion.style import RadialGradient
rad = RadialGradient(400, 300, 400, 300, 200)
rad.add_stop(0.0, "#FFFFFF").add_stop(1.0, "#090D16")
ctx.fill_circle(400, 300, 200, style=rad)

3. Conic Gradient:

ConicGradient(cx: float, cy: float, angle_rad: float = 0.0)
from naramotion.style import ConicGradient
conic = ConicGradient(400, 300, 0.0)
conic.add_stop(0.0, "red").add_stop(0.5, "blue").add_stop(1.0, "red")
ctx.fill_circle(400, 300, 150, style=conic)

4. Image Pattern:

Pattern(image: Image, extend_mode: ExtendMode = ExtendMode.REPEAT)

11. Geometric Primitives (naramotion.geometry)

NaraMotion provides direct C-struct wrappers for 2D primitives:

  • Point(x, y) / PointI(x, y)
  • Size(w, h) / SizeI(w, h)
  • Rect(x, y, w, h) / RectI(x, y, w, h)
  • Circle(cx, cy, r)
  • Ellipse(cx, cy, rx, ry)
  • RoundRect(x, y, w, h, rx, ry)
  • Line(x0, y0, x1, y1)
  • Arc(cx, cy, rx, ry, start, sweep)
  • Chord(cx, cy, rx, ry, start, sweep)
  • Pie(cx, cy, rx, ry, start, sweep)

12. Affine Transformations (naramotion.Matrix2D)

# Constructor Signature:
Matrix2D(m00: float = 1.0, m01: float = 0.0, m10: float = 0.0, m11: float = 1.0, m20: float = 0.0, m21: float = 0.0)
# 3-Line MWE:
from naramotion import Matrix2D
m = Matrix2D.make_translation(100, 50).scale(2.0, 2.0).rotate_deg(45.0)
ctx.transform(m)

Transformation Methods:

  • Matrix2D.identity()
  • Matrix2D.make_translation(x, y)
  • Matrix2D.make_scaling(sx, sy)
  • Matrix2D.make_rotation(angle_rad) / Matrix2D.make_rotation_deg(angle_deg)
  • m.translate(x, y) / m.scale(sx, sy) / m.rotate(rad) / m.rotate_deg(deg)
  • m.invert() -> Matrix2D
  • m1 * m2: Matrix multiplication operator.
  • m.map_point(x, y) -> Tuple[float, float]

13. Bulk & Batch Operations for Big Data

Render millions of shapes in a single SIMD call with zero Python interpreter overhead:

# 1. Batch Circles:
ctx.fill_circle_array(circles_array, style="#38BDF8")

# 2. Batch Rectangles:
ctx.fill_rect_array(rects_array, style="#10B981")

# 3. Batch Lines:
ctx.stroke_line_array(lines_array, style="#F59E0B")

14. Zero-Copy NumPy & FFmpeg Video Streaming

import naramotion
import numpy as np

# Zero-copy NumPy view (changes in ndarray reflect instantly in Blend2D image)
img = naramotion.Image(1920, 1080)
arr = img.to_numpy(copy=False)
arr[:, :, 0] = 255 # Fill blue channel directly in memory

# Direct pipe to FFmpeg process
import subprocess
ffmpeg = subprocess.Popen([
    "ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "bgra",
    "-s", "1920x1080", "-r", "60", "-i", "-",
    "-c:v", "libx264", "-pix_fmt", "yuv420p", "output.mp4"
], stdin=subprocess.PIPE)

# Zero copy write from memoryview
ffmpeg.stdin.write(img.buffer)

15. Hardware-Accelerated Video Engine (naramotion.video)

# Constructor Signature:
VideoWriter(
    output_path: str,
    width: int,
    height: int,
    fps: int = 60,
    bitrate: str = "12M",
    codec: Optional[str] = None, # "h264_nvenc", "h264_qsv", "h264_amf", "libx264", "prores"
    preset: str = "fast",
    crf: Optional[int] = None,
    pixel_format: str = "yuv420p"
)
# 3-Line MWE:
from naramotion.video import VideoWriter
with VideoWriter("render.mp4", width=3840, height=2160, fps=60, codec="h264_nvenc") as vw:
    with vw.render_frame_context() as ctx:
        ctx.fill_all("#090D16")

16. Geospatial & Big Data Engine (naramotion.shapgeo / naramotion.geo)

NaraMotion natively streams and renders massive GIS datasets (e.g. secondary_roads.parquet, roads.parquet, 03_secondary_roads.geojson, Shapefiles) directly with zero memory bloat.

GeoCanvas Signature:

GeoCanvas(
    width: int = 1920,
    height: int = 1080,
    bounds: Optional[Tuple[float, float, float, float]] = None,
    bg_color: Union[str, Rgba32] = "#050811",
    padding: float = 0.05
)
# 3-Line MWE (Multi-Layer Parquet & GeoJSON Map):
from naramotion.shapgeo import GeoCanvas

with GeoCanvas(width=3840, height=2160, bg_color="#050811") as canvas:
    # 1. Add massive Parquet vector layer (e.g. roads, secondary roads)
    canvas.add_parquet("secondary_roads.parquet", stroke_color="#00F0FF", stroke_width=2.5)
    
    # 2. Add GeoJSON overlay layer
    canvas.add_geojson("03_secondary_roads.geojson", stroke_color="#FF007F", stroke_width=1.5)
    
    canvas.save("world_roads_4k.png")

Dynamic Stroke & Scale-Aware Level of Detail (LOD):

Avoid map clutter and ink bleed when zooming out to country or continental level:

# dynamic_stroke=True automatically scales line width proportionally to zoom bounds!
canvas.add_parquet("secondary_roads.parquet", stroke_color="#00F0FF", stroke_width=2.0, dynamic_stroke=True)
canvas.add_geojson("03_secondary_roads.geojson", stroke_color="#FF007F", stroke_width=1.5, dynamic_stroke=True)

Center, Centroid & Auto-Focusing Viewport:

from naramotion import compute_center, get_centroid

# Compute center of GeoDataFrame, Shapefile, Path, or Bounding Box:
cx, cy = compute_center(gdf_roads)
print(f"Road network center: lon={cx:.4f}, lat={cy:.4f}")

# Dynamically focus canvas camera onto a specific city or country with zoom factor:
canvas.focus_on(gdf_city, zoom=2.5)

High-Speed GIS Readers (read_parquet, read_parquet_native, read_geojson, read_file):

from naramotion.shapgeo import read_parquet, read_parquet_native, read_geojson, read_file

# 1. Read directly into GeoDataFrame or native GeoDataset
gdf_roads = read_parquet("secondary_roads.parquet")
gdf_json  = read_geojson("03_secondary_roads.geojson")
gdf_auto  = read_file("boundaries.shp")

# 2. Pure Native C++ WKB Parsing directly to SoA (bypasses Shapely/Python completely):
soa_layer = read_parquet_native("census_blocks.parquet", return_native_soa=True)

Structure of Arrays (SoA) & Path Memory Arena (NativeGeoLayerSoA):

For massive cityscapes (30,000+ building blocks / parcels), SoA layout keeps all data in contiguous cache lines (distances, bboxes, paths, centroids, start_frames), eliminating Python object overhead:

from naramotion import NativeGeoLayerSoA, GeoCanvas

layer = NativeGeoLayerSoA(capacity=50000)
# Parse WKB directly in C++ into BLPathCore
layer.from_wkb_batch(wkb_buffers, transform=canvas.transform)

# Compute shockwave timeline in L1/L2 cache
layer.compute_propagation(epicenters=[(-74.0060, 40.7128)], duration_frames=300.0)

# Vectorized BBox clipping and frame activation
vis_count = layer.cull_and_update(viewport_bbox=(0, 0, 3840, 2160), current_frame=frame)

Dual-Buffer Polygon Render Pipeline & Centroid Spring Pop-In:

Alternating fill and stroke flushes the JIT pipeline. Dual-Buffer batch rendering separates all fills (Pass 1) from all strokes (Pass 2) for maximum speed. render_popin applies an elastic spring back-out scale expansion around each polygon's centroid:

with GeoCanvas(3840, 2160) as canvas:
    # 1. Dual-Buffer Batch Render
    layer.render_dual_buffer(canvas, fill_color="#00F0FF", stroke_color="#FFFFFF", stroke_width=1.0)
    
    # 2. Spring Pop-In Animation (Scale(t) = Easing::back_out(t))
    layer.render_popin(canvas, current_frame=frame, fill_color="#00F0FF", stroke_color="#FFFFFF", stroke_width=1.0)

Flat Uniform Grid Spatial Index (UniformGridIndex):

from naramotion import UniformGridIndex

grid = UniformGridIndex(bounds=(-74.1, 40.6, -73.8, 40.9), grid_w=64, grid_h=64)
grid.build_from_bboxes(bboxes)
visible_ids = grid.query_bbox(-74.01, 40.70, -73.98, 40.75) # < 1 microsecond!

Curated Palettes & Color Harmony Engine (naramotion.Palette):

from naramotion import Palette

# 1. Designer Pre-built Palettes:
cyberpunk = Palette.CYBERPUNK       # Cyan, Hot Pink, Electric Purple, Neon Green, Acid Yellow
tokyo     = Palette.TOKYO_NIGHT     # Soft Blue, Lavender, Sky, Crimson, Gold
solar     = Palette.SOLAR_HEAT      # Red Orange, Solar Gold, Deep Pink, Plum
nordic    = Palette.NORDIC_FROST    # Ice Blue, Glacier, Deep Ocean, Frost Mauve
midnight  = Palette.MIDNIGHT_BLUE   # Electric Cyan, Indigo, Purple, Rose, Emerald

# 2. Golden-Ratio Harmonic Generator (Guaranteed zero color clash for N layers):
layer_colors = Palette.generate(8, base_color="#00F0FF", mode="golden_ratio")

Anti-Burnout ACES Filmic Tone Mapping (naramotion.fx.tone_map_aces):

from naramotion.fx import tone_map_aces, bloom

# Render 10,000 glowing intersecting lines without clipping to solid white!
tone_map_aces(canvas.img, exposure=1.1)

17. Motion Graphics & Animation (naramotion.motion)

17.1 Declarative Action Chaining & Kinetic Animations

from naramotion.motion import DrawReveal, Typewriter, Stagger, Spring

# Progressive line drawing reveal (0% to 100%):
reveal_action = DrawReveal(target_path, duration=2.0, color="#00F0FF", width=2.5)

# Kinetic Typewriter with glowing blinking cursor:
typewriter_action = Typewriter("NARAMOTION V0.23", x=100, y=200, duration=1.5, font_size=36)

# Stagger actions sequentially:
staggered_actions = Stagger.create([reveal_action, typewriter_action], delay_step=0.4)

17.2 Easing Curves Reference Table & Physics Springs

All easing functions accept progress $t \in [0.0, 1.0]$:

Family In (_in) Out (_out) In-Out (_in_out)
Linear Easing.linear(t) Easing.linear(t) Easing.linear(t)
Quadratic Easing.quad_in(t) Easing.quad_out(t) Easing.quad_in_out(t)
Cubic Easing.cubic_in(t) Easing.cubic_out(t) Easing.cubic_in_out(t)
Quartic Easing.quart_in(t) Easing.quart_out(t) Easing.quart_in_out(t)
Quintic Easing.quint_in(t) Easing.quint_out(t) Easing.quint_in_out(t)
Sine Easing.sine_in(t) Easing.sine_out(t) Easing.sine_in_out(t)
Exponential Easing.expo_in(t) Easing.expo_out(t) Easing.expo_in_out(t)
Circular Easing.circ_in(t) Easing.circ_out(t) Easing.circ_in_out(t)
Elastic Easing.elastic_in(t) Easing.elastic_out(t) Easing.elastic_in_out(t)
Back (Overshoot) Easing.back_in(t) Easing.back_out(t) Easing.back_in_out(t)
Bounce Easing.bounce_in(t) Easing.bounce_out(t) Easing.bounce_in_out(t)

Spring Physics Dynamics:

from naramotion.motion import Spring
spring = Spring(stiffness=170.0, damping=26.0, mass=1.0)
pos = spring.evaluate(t=0.35)

Cubic Bezier Curves:

from naramotion.motion import CubicBezier
bezier = CubicBezier(0.25, 0.1, 0.25, 1.0)
val = bezier.evaluate(t=0.5)

17.2 Vector Path Animations & Trimming

# Trim path line-drawing reveal:
from naramotion.motion import trim_path, PathFollower, path_morph
revealed = trim_path(full_path, start=0.0, end=0.8)

# Follow tangent and position along path:
follower = PathFollower(full_path)
x, y, angle_rad = follower.point_at(t=0.5)

# Morph between two paths:
morphed_path = path_morph(path_a, path_b, progress=0.5)

17.3 Particle Simulation & VFX Engine

from naramotion.motion import ParticleSystem
ps = ParticleSystem(max_particles=20000).add_gravity(0, 500)
ps.preset_fireworks(x=960, y=540, count=250)
ps.update(1.0 / 60.0)
ps.render(ctx)

17.4 Scene Graph, Layers & Camera2D

from naramotion.motion import Scene, Node, Camera2D
scene = Scene(1920, 1080)
scene.camera.look_at(500, 500)
scene.camera.shake(intensity=15.0, duration=0.6)
scene.render(ctx)

17.5 Multi-Track Timeline & Direct Video Export

from naramotion.motion import Timeline
tl = Timeline(duration=5.0, fps=60)
tl.animate(cam, "pitch", start_val=0.0, end_val=70.0, duration=3.0, easing="easeInOutCubic")
tl.render_video("cinematic.mp4", width=3840, height=2160, fps=60, draw_fn=render_callback)

18. Kinetic Perspective & 3D Globe (naramotion.motion.PerspectiveCamera)

# Constructor Signature:
PerspectiveCamera(
    width: int = 1920,
    height: int = 1080,
    fov: float = 60.0,
    pitch: float = 0.0,      # Tilt (0 = top-down 2D, 75 = horizon perspective)
    yaw: float = 0.0,        # Heading rotation
    roll: float = 0.0,       # Banking angle
    distance: float = 1000.0,# Altitude / zoom
    target_x: float = 0.0,   # Focus point X
    target_y: float = 0.0,   # Focus point Y
    near_clip: float = 10.0  # Near-plane clipping
)
# 3-Line MWE:
from naramotion.motion import PerspectiveCamera
cam = PerspectiveCamera(width=3840, height=2160, pitch=72.0, distance=900.0)
proj_lines, scales, valid = cam.transform_lines(street_lines_nx4)
cam.render_fog(ctx, fog_color="#050811", horizon_y_ratio=0.3)

3D Globe Renderer:

from naramotion.motion import render_globe
render_globe(
    dst_image=canvas_img,
    texture_image=world_texture_img,
    cx=960, cy=540, radius=400,
    rot_lon=45.0, rot_lat=15.0,
    glow_color="#38BDF8FF"
)

19. Cinematic Visual FX & Post-Processing (naramotion.fx)

# Signatures for All Filters:
gaussian_blur(image: Image, sigma: float = 3.0, in_place: bool = True) -> Image
bloom(image: Image, threshold: float = 0.6, intensity: float = 1.2, radius: float = 10.0, tint: str = "#FFFFFFFF") -> Image
neon_glow(image: Image, color: str = "#38BDF8FF", intensity: float = 1.8, radius: float = 14.0) -> Image
chromatic_aberration(image: Image, shift_x: float = 6.0, shift_y: float = 0.0) -> Image
vignette(image: Image, intensity: float = 0.6, radius: float = 0.4, smoothness: float = 0.45) -> Image
film_grain(image: Image, amount: float = 0.08, seed: int = 0) -> Image
color_grade(image: Image, brightness: float = 0.0, contrast: float = 1.0, saturation: float = 1.0, gamma: float = 1.0) -> Image
drop_shadow(image: Image, dx: float = 12.0, dy: float = 12.0, blur: float = 15.0, shadow_color: str = "#000000AA") -> Image
scanlines(image: Image, spacing: int = 4, intensity: float = 0.35) -> Image
glitch_displacement(image: Image, num_slices: int = 12, max_displacement: int = 30) -> Image

Fluent Chaining Pipeline:

from naramotion.fx import FXPipeline
pipe = (
    FXPipeline()
    .bloom(threshold=0.5, intensity=1.4, radius=12.0)
    .chromatic_aberration(shift_x=5.0)
    .vignette(intensity=0.55)
    .film_grain(amount=0.06)
)
pipe.apply(img)

20. Enumerations Reference

CompOp (Composite Modes):

SRC_OVER, SRC_COPY, SRC_IN, SRC_OUT, SRC_ATOP, DST_OVER, DST_IN, DST_OUT, DST_ATOP, XOR, CLEAR, PLUS, MINUS, MULTIPLY, SCREEN, OVERLAY, DARKEN, LIGHTEN, COLOR_DODGE, COLOR_BURN, HARD_LIGHT, SOFT_LIGHT, DIFFERENCE, EXCLUSION.

StrokeCap:

BUTT, SQUARE, ROUND, ROUND_REV, TRIANGLE, TRIANGLE_REV.

StrokeJoin:

MITER_CLIP, MITER_BEVEL, MITER_ROUND, BEVEL, ROUND.

FillRule:

NON_ZERO, EVEN_ODD.

Format:

PRGB32 (Premultiplied 32-bit ARGB), XRGB32 (Opaque 32-bit RGB), A8 (8-bit Alpha mask).

ExtendMode:

PAD, REPEAT, REFLECT, PAD_X_PAD_Y, REPEAT_X_REPEAT_Y.


21. Performance & Best Practices Guide

  1. Always Use the Context Manager (with Context(img) as ctx:):
    • Ensures automatic native flushing and exception safety.
  2. Prefer In-Place Batch Arrays for Big Data:
    • Use ctx.fill_circle_array() and cam.transform_lines() instead of looping in Python.
  3. Prefer PRGB32 Format:
    • Blend2D's JIT compiler generates AVX2 / AVX-512 vector pipelines specifically optimized for premultiplied 32-bit pixel buffers.
  4. Use Zero-Copy img.buffer for Video Encoding:
    • Stream directly into VideoWriter or FFmpeg without memory allocation overhead.

22. Comprehensive Error Catalog, Exceptions & Troubleshooting Guide

NaraMotion wraps all native C++ engine errors into standard Python exceptions. Below is the complete catalog of errors, their root causes, and step-by-step resolution.

22.1 Native Engine Errors (naramotion.Blend2DError)

Error Code Exception Output Root Cause Resolution
BL_ERROR_INVALID_VALUE (1) Blend2DError: Invalid value Passing invalid image width/height ($\le 0$), negative radius, NaN, or Inf coordinates. Ensure dimensions are integers $> 0$ and coordinates are valid finite numbers (math.isfinite(x)).
BL_ERROR_INVALID_STATE (2) Blend2DError: Invalid state Calling drawing methods on a context after ctx.end(), or before ctx.begin(). Always use the context manager with Context(img) as ctx: which guarantees safe lifecycle.
BL_ERROR_INVALID_HANDLE (3) Blend2DError: Invalid handle Calling methods on a destroyed image/path resource (e.g. after img.reset()). Do not access an image after calling img.reset(). Create a new image if needed.
BL_ERROR_NO_MATCHING_VERTEX (4) Blend2DError: No matching vertex Attempting to trim or query path tangent on an empty Path(). Ensure the path contains at least one move_to and line_to before calling trim_path() or PathFollower.
BL_ERROR_OUT_OF_MEMORY (6) Blend2DError: Out of memory Requesting an image allocation larger than available RAM (e.g. $100000 \times 100000$). Verify image dimensions before creating canvas. For large maps, render in tiles or at 4K/8K.
BL_ERROR_FONT_NOT_MATCHED (14) Blend2DError: Font not matched Passing a corrupted font file or unsupported font format. Provide a standard OpenType (.otf) or TrueType (.ttf / .ttc) font file.

22.2 Common Python Exceptions in NaraMotion

1. ValueError: Unsupported color format

  • When it happens: Passing CSS functional strings like "rgba(255, 0, 0, 0.5)" or "rgb(0, 255, 0)".
  • Fix: Convert to hex string or numeric tuple:
    # ❌ Incorrect:
    ctx.fill_circle(100, 100, 50, "rgba(56, 189, 248, 0.5)")
    
    # ✅ Correct:
    ctx.fill_circle(100, 100, 50, "#38BDF880")               # Hex with 50% alpha
    ctx.fill_circle(100, 100, 50, (56, 189, 248, 128))        # Tuple with alpha
    

2. RuntimeError: FFmpeg executable not found

  • When it happens: Using VideoWriter or VideoReader when FFmpeg is not installed or not in system PATH.
  • Fix:
    • Windows: winget install Gyan.FFmpeg
    • Ubuntu / Debian: sudo apt update && sudo apt install -y ffmpeg
    • macOS: brew install ffmpeg

3. TypeError: Array must be C-contiguous and uint8

  • When it happens: Passing a non-contiguous slice or float array to Image.from_numpy().
  • Fix: Ensure array is C-contiguous with uint8 dtype:
    import numpy as np
    arr = np.ascontiguousarray(arr, dtype=np.uint8)
    img = Image.from_numpy(arr)
    

4. FileNotFoundError: Font file not found

  • When it happens: Calling FontFace.from_file("arial.ttf") when the file does not exist at that path.
  • Fix: Use absolute paths:
    # Windows:
    face = FontFace.from_file("C:/Windows/Fonts/segoeui.ttf")
    # Linux:
    face = FontFace.from_file("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf")
    

5. ImportError: DLL load failed while importing _bin


22.3 Environment Conflicts & Compatibility Solutions

Environment Issue Cause Solution
GeoPandas / Shapely version mismatch Old versions missing __geo_interface__ pip install --upgrade geopandas shapely
Virtualenv DLL isolation Custom sandbox blocking .dll search NaraMotion auto-adds blend2d/_bin with os.add_dll_directory().
Multithreading OpenMP / Context Sharing Two threads drawing to the same Context simultaneously Create one Context per image per thread. Images can be rendered in parallel across threads.