File size: 35,902 Bytes
b516e00
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
# 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. |