Release NaraMotion v0.26.0: Structure of Arrays (SoA), Path Arena Allocator, Uniform Grid Indexing, Dual-Buffer Rendering & Centroid Spring Pop-in
b516e00 verified |
Download DOCUMENTATION.md from ArifiIslam/NaraMotion: direct link, hf CLI and curl.
- Browser
- Download file 35.9 kB
-
https://huggingface.co/ArifiIslam/NaraMotion/resolve/main/DOCUMENTATION.md
- Command line
-
hf download hf://ArifiIslam/NaraMotion/DOCUMENTATION.md
-
curl -L -o DOCUMENTATION.md https://huggingface.co/ArifiIslam/NaraMotion/resolve/main/DOCUMENTATION.md
35.9 kB
| # NaraMotion Complete API Documentation & Reference Guide 📚✨ | |
| **Author & Creator**: Islam Arifi | |
| **Official PyPI Package**: [`naramotion`](https://pypi.org/project/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](#1-official-installation) | |
| 2. [Commercial License & Evaluation Watermark Removal](#2-commercial-license--evaluation-watermark-removal) | |
| 3. [Architectural Overview: C++ vs. Python](#3-architectural-overview-c-vs-python) | |
| 4. [C++ to Python Translation Cheat Sheet](#4-c-to-python-translation-cheat-sheet) | |
| 5. [Strict Color Input Specifications & Restrictions](#5-strict-color-input-specifications--restrictions) | |
| 6. [Image Handling (`naramotion.Image`)](#6-image-handling-blend2dimage) | |
| 7. [2D Rendering Context (`naramotion.Context`)](#7-2d-rendering-context-blend2dcontext) | |
| 8. [Vector Path Builder (`naramotion.Path`)](#8-vector-path-builder-blend2dpath) | |
| 9. [Typography & Fonts (`naramotion.Font`, `naramotion.FontFace`)](#9-typography--fonts-blend2dfont-blend2dfontface) | |
| 10. [Gradients & Patterns (`naramotion.style`)](#10-gradients--patterns-blend2dstyle) | |
| 11. [Geometric Primitives (`naramotion.geometry`)](#11-geometric-primitives-blend2dgeometry) | |
| 12. [Affine Transformations (`naramotion.Matrix2D`)](#12-affine-transformations-blend2dmatrix2d) | |
| 13. [Bulk & Batch Operations for Big Data](#13-bulk--batch-operations-for-big-data) | |
| 14. [Zero-Copy NumPy & FFmpeg Video Streaming](#14-zero-copy-numpy--ffmpeg-video-streaming) | |
| 15. [Hardware-Accelerated Video Engine (`naramotion.video`)](#15-hardware-accelerated-video-engine-blend2dvideo) | |
| 16. [Geospatial & Big Data Engine (`naramotion.shapgeo` / `naramotion.geo`)](#16-geospatial--big-data-engine-blend2dshapgeo--blend2dgeo) | |
| 17. [Motion Graphics & Animation (`naramotion.motion`)](#17-motion-graphics--animation-blend2dmotion) | |
| - [17.1 Easing Curves Reference Table & Physics Springs](#171-easing-curves-reference-table--physics-springs) | |
| - [17.2 Vector Path Animations & Trimming](#172-vector-path-animations--trimming) | |
| - [17.3 Particle Simulation & VFX Engine](#173-particle-simulation--vfx-engine) | |
| - [17.4 Scene Graph, Layers & Camera2D](#174-scene-graph-layers--camera2d) | |
| - [17.5 Multi-Track Timeline & Direct Video Export](#175-multi-track-timeline--direct-video-export) | |
| 18. [Kinetic Perspective & 3D Globe (`naramotion.motion.PerspectiveCamera`)](#18-kinetic-perspective--3d-globe-blend2dmotionperspectivecamera) | |
| 19. [Cinematic Visual FX & Post-Processing (`naramotion.fx`)](#19-cinematic-visual-fx--post-processing-blend2dfx) | |
| 20. [Enumerations Reference](#20-enumerations-reference) | |
| 21. [Performance & Best Practices Guide](#21-performance--best-practices-guide) | |
| 22. [Comprehensive Error Catalog, Exceptions & Troubleshooting 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: | |
| ```bash | |
| pip install naramotion | |
| ``` | |
| ### 🛠️ Optional Ecosystem Dependencies: | |
| ```bash | |
| # 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: | |
| ```python | |
| 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: | |
| ```python | |
| 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: | |
| ```bash | |
| 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++:** | |
| ```cpp | |
| 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:** | |
| ```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 | |
| > [!WARNING] | |
| > **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`) | |
| ```python | |
| # Constructor Signature: | |
| Image(width: int = 0, height: int = 0, format: Format = Format.PRGB32) | |
| ``` | |
| ```python | |
| # 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`) | |
| ```python | |
| # Context Manager Usage: | |
| with Context(image: Image) as ctx: | |
| ... | |
| ``` | |
| ```python | |
| # 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`) | |
| ```python | |
| # Constructor Signature: | |
| Path() | |
| ``` | |
| ```python | |
| # 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`) | |
| ```python | |
| # Signatures: | |
| FontFace.from_file(filepath: str) -> FontFace | |
| Font(face: FontFace, size: float = 12.0) | |
| ``` | |
| ```python | |
| # 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: | |
| ```python | |
| LinearGradient(x0: float, y0: float, x1: float, y1: float, extend_mode: ExtendMode = ExtendMode.PAD) | |
| ``` | |
| ```python | |
| 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: | |
| ```python | |
| RadialGradient(x0: float, y0: float, x1: float, y1: float, r0: float, extend_mode: ExtendMode = ExtendMode.PAD) | |
| ``` | |
| ```python | |
| 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: | |
| ```python | |
| ConicGradient(cx: float, cy: float, angle_rad: float = 0.0) | |
| ``` | |
| ```python | |
| 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: | |
| ```python | |
| 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`) | |
| ```python | |
| # 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) | |
| ``` | |
| ```python | |
| # 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: | |
| ```python | |
| # 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 | |
| ```python | |
| 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`) | |
| ```python | |
| # 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" | |
| ) | |
| ``` | |
| ```python | |
| # 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: | |
| ```python | |
| 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 | |
| ) | |
| ``` | |
| ```python | |
| # 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: | |
| ```python | |
| # 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: | |
| ```python | |
| 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`): | |
| ```python | |
| 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: | |
| ```python | |
| 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: | |
| ```python | |
| 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`): | |
| ```python | |
| 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`): | |
| ```python | |
| 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`): | |
| ```python | |
| 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 | |
| ```python | |
| 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: | |
| ```python | |
| 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: | |
| ```python | |
| 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 | |
| ```python | |
| # 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 | |
| ```python | |
| 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 | |
| ```python | |
| 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 | |
| ```python | |
| 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`) | |
| ```python | |
| # 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 | |
| ) | |
| ``` | |
| ```python | |
| # 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: | |
| ```python | |
| 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`) | |
| ```python | |
| # 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: | |
| ```python | |
| 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: | |
| ```python | |
| # ❌ 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: | |
| ```python | |
| 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: | |
| ```python | |
| # 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` | |
| - **When it happens**: Missing Visual C++ runtime on Windows. | |
| - **Fix**: Install the official [Microsoft Visual C++ 2015-2022 Redistributable (x64)](https://aka.ms/vs/17/release/vc_redist.x64.exe) or reinstall with: | |
| ```bash | |
| pip install --force-reinstall naramotion | |
| ``` | |
| --- | |
| ### 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. | | |