hyperstellar 1.5.6__py3-none-win_amd64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. hyperstellar/__init__.py +299 -0
  2. hyperstellar/__init__.pyi +1019 -0
  3. hyperstellar/_native/linux-x64/shaders/axis.frag +8 -0
  4. hyperstellar/_native/linux-x64/shaders/axis.vert +13 -0
  5. hyperstellar/_native/linux-x64/shaders/fragShader.frag +27 -0
  6. hyperstellar/_native/linux-x64/shaders/geoShader.geom +69 -0
  7. hyperstellar/_native/linux-x64/shaders/math.comp +2177 -0
  8. hyperstellar/_native/linux-x64/shaders/paint.comp +1214 -0
  9. hyperstellar/_native/linux-x64/shaders/quad.frag +26 -0
  10. hyperstellar/_native/linux-x64/shaders/quad.geom +149 -0
  11. hyperstellar/_native/linux-x64/shaders/quad.vert +39 -0
  12. hyperstellar/_native/linux-x64/shaders/vertexShader.vert +13 -0
  13. hyperstellar/_native/linux-x64/stellar.so +0 -0
  14. hyperstellar/_native/windows-x64/shaders/axis.frag +8 -0
  15. hyperstellar/_native/windows-x64/shaders/axis.vert +13 -0
  16. hyperstellar/_native/windows-x64/shaders/fragShader.frag +27 -0
  17. hyperstellar/_native/windows-x64/shaders/geoShader.geom +69 -0
  18. hyperstellar/_native/windows-x64/shaders/math.comp +2177 -0
  19. hyperstellar/_native/windows-x64/shaders/paint.comp +1214 -0
  20. hyperstellar/_native/windows-x64/shaders/quad.frag +26 -0
  21. hyperstellar/_native/windows-x64/shaders/quad.geom +149 -0
  22. hyperstellar/_native/windows-x64/shaders/quad.vert +39 -0
  23. hyperstellar/_native/windows-x64/shaders/vertexShader.vert +13 -0
  24. hyperstellar/_native/windows-x64/stellar.pyd +0 -0
  25. hyperstellar/debug.py +169 -0
  26. hyperstellar/jit.py +2010 -0
  27. hyperstellar/jit_linter.py +3 -0
  28. hyperstellar/py.typed +0 -0
  29. hyperstellar/shader.py +1356 -0
  30. hyperstellar/typed.py +152 -0
  31. hyperstellar-1.5.6.dist-info/METADATA +470 -0
  32. hyperstellar-1.5.6.dist-info/RECORD +35 -0
  33. hyperstellar-1.5.6.dist-info/WHEEL +5 -0
  34. hyperstellar-1.5.6.dist-info/licenses/LICENSE +24 -0
  35. hyperstellar-1.5.6.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1019 @@
1
+ # Type stubs for hyperstellar package
2
+ import typing
3
+ from typing import Any, List, Dict, Optional, Union, Callable, ClassVar, Tuple, overload
4
+
5
+ # ============================================================================
6
+ # ENUMS
7
+ # ============================================================================
8
+
9
+ class SkinType:
10
+ """Visual representation type for objects."""
11
+ CIRCLE: int
12
+ RECTANGLE: int
13
+ POLYGON: int
14
+
15
+ class CollisionShape:
16
+ """Collision shape type for physics objects."""
17
+ NONE: int # No collision
18
+ CIRCLE: int # Circular collision shape
19
+ AABB: int # Axis-aligned bounding box
20
+ POLYGON: int # Polygon collision shape
21
+
22
+ class ConstraintType:
23
+ """Type of physics constraint."""
24
+ DISTANCE: int # Distance constraint between objects
25
+ BOUNDARY: int # Boundary/box constraint
26
+
27
+ # ============================================================================
28
+ # DATA CLASSES
29
+ # ============================================================================
30
+
31
+ class ObjectState:
32
+ """Complete state of a physics object.
33
+
34
+ Attributes:
35
+ x (float): X position
36
+ y (float): Y position
37
+ vx (float): X velocity
38
+ vy (float): Y velocity
39
+ mass (float): Mass of object
40
+ charge (float): Electric charge
41
+ rotation (float): Rotation angle in radians
42
+ angular_velocity (float): Angular velocity in rad/s
43
+ width (float): Width for rectangles
44
+ height (float): Height for rectangles
45
+ radius (float): Radius for circles/polygons
46
+ polygon_sides (int): Number of sides for polygons
47
+ skin_type (SkinType): Visual type
48
+ r,g,b,a (float): Color components (0.0-1.0)
49
+ """
50
+ x: float
51
+ y: float
52
+ vx: float
53
+ vy: float
54
+ mass: float
55
+ charge: float
56
+ rotation: float
57
+ angular_velocity: float
58
+ width: float
59
+ height: float
60
+ radius: float
61
+ polygon_sides: int
62
+ skin_type: SkinType
63
+ r: float
64
+ g: float
65
+ b: float
66
+ a: float
67
+
68
+ def __init__(self) -> None: ...
69
+ def __repr__(self) -> str: ...
70
+
71
+ class CollisionConfig:
72
+ """Collision configuration for an object.
73
+
74
+ Attributes:
75
+ enabled (bool): Whether collision detection is enabled
76
+ shape (CollisionShape): Collision shape type
77
+ restitution (float): Bounciness (0.0-1.0)
78
+ friction (float): Surface friction (0.0-1.0)
79
+ """
80
+ enabled: bool
81
+ shape: CollisionShape
82
+ restitution: float
83
+ friction: float
84
+
85
+ def __init__(self) -> None: ...
86
+ def __repr__(self) -> str: ...
87
+
88
+ class KeyState:
89
+ """Represents the state of a single keyboard key for the current frame.
90
+
91
+ Attributes:
92
+ pressed (bool): True if the key is currently held down.
93
+ released (bool): True if the key was just released this frame.
94
+ held (bool): Alias for pressed.
95
+ """
96
+ @property
97
+ def pressed(self) -> bool: ...
98
+ @property
99
+ def released(self) -> bool: ...
100
+ @property
101
+ def held(self) -> bool: ...
102
+ def __repr__(self) -> str: ...
103
+
104
+ class KeyboardMonitor:
105
+ """
106
+ Provides access to keyboard states via attributes or indexing.
107
+
108
+ Example:
109
+ if sim.keyboard.Z.pressed: ...
110
+ if sim.keyboard["Space"].released: ...
111
+
112
+ Supported key names include: A-Z, 0-9, Space, Shift, Control, Alt,
113
+ Escape, Enter, Tab, Backspace, Delete, Home, End, PageUp, PageDown,
114
+ Insert, Up, Down, Left, Right, F1-F12.
115
+ """
116
+ def __init__(self, sim: "Simulation") -> None: ...
117
+ def __getattr__(self, name: str) -> KeyState: ...
118
+ def __getitem__(self, name: str) -> KeyState: ...
119
+ def get_key_state(self, key_name: str) -> KeyState:
120
+ """Get the state of a specific key by name."""
121
+ ...
122
+
123
+ class ObjectConfig:
124
+ """Configuration for creating objects in batch mode.
125
+
126
+ Attributes:
127
+ x,y,vx,vy,mass,charge,rotation,angular_velocity: Same as ObjectState
128
+ skin (SkinType): Visual type
129
+ size (float): General size parameter
130
+ width,height (float): Dimensions for rectangles
131
+ r,g,b,a (float): Color
132
+ polygon_sides (int): Polygon sides
133
+ equation (str): Physics equation string
134
+ constraints (List[ConstraintConfig]): List of constraints
135
+ """
136
+ x: float
137
+ y: float
138
+ vx: float
139
+ vy: float
140
+ mass: float
141
+ charge: float
142
+ rotation: float
143
+ angular_velocity: float
144
+ skin: SkinType
145
+ size: float
146
+ width: float
147
+ height: float
148
+ r: float
149
+ g: float
150
+ b: float
151
+ a: float
152
+ polygon_sides: int
153
+ equation: str
154
+ constraints: List["ConstraintConfig"]
155
+
156
+ def __init__(self) -> None: ...
157
+ def __repr__(self) -> str: ...
158
+
159
+ class ConstraintConfig:
160
+ """Constraint configuration for batch mode.
161
+
162
+ Attributes:
163
+ type (ConstraintType): Constraint type (DISTANCE or BOUNDARY)
164
+ target (int): Target object ID
165
+ param1 (float): Distance: rest_length, Boundary: min_x, Angle: min_angle
166
+ param2 (float): Boundary: max_x, Angle: max_angle
167
+ param3 (float): Boundary: min_y
168
+ param4 (float): Boundary: max_y
169
+ """
170
+ type: ConstraintType
171
+ target: int
172
+ param1: float
173
+ param2: float
174
+ param3: float
175
+ param4: float
176
+
177
+ def __init__(self) -> None: ...
178
+
179
+ class BatchConfig:
180
+ """Configuration for batch simulations.
181
+
182
+ Attributes:
183
+ objects (list[ObjectConfig]): List of object configurations
184
+ duration (float): Simulation duration in seconds
185
+ dt (float): Time step per update
186
+ output_file (str): Optional output file path
187
+ """
188
+ objects: List[ObjectConfig]
189
+ duration: float
190
+ dt: float
191
+ output_file: str
192
+
193
+ def __init__(self) -> None: ...
194
+
195
+ class BatchGetData:
196
+ """Batch get data structure."""
197
+ x: float
198
+ y: float
199
+ vx: float
200
+ vy: float
201
+ mass: float
202
+ charge: float
203
+ rotation: float
204
+ angular_velocity: float
205
+ width: float
206
+ height: float
207
+ radius: float
208
+ polygon_sides: int
209
+ skin_type: int
210
+ r: float
211
+ g: float
212
+ b: float
213
+ a: float
214
+
215
+ def __init__(self) -> None: ...
216
+
217
+ class BatchUpdateData:
218
+ """Batch update data structure."""
219
+ index: int
220
+ x: float
221
+ y: float
222
+ vx: float
223
+ vy: float
224
+ mass: float
225
+ charge: float
226
+ rotation: float
227
+ angular_velocity: float
228
+ size: float # radius for circle/polygon
229
+ width: float
230
+ height: float
231
+ r: float
232
+ g: float
233
+ b: float
234
+ a: float
235
+ polygon_sides: int
236
+
237
+ def __init__(self) -> None: ...
238
+
239
+ class DistanceConstraint:
240
+ """Maintain distance between two objects.
241
+
242
+ Args:
243
+ target_object (int): ID of target object to maintain distance with
244
+ rest_length (float): Desired distance between objects
245
+ """
246
+ target_object: int
247
+ rest_length: float
248
+
249
+ def __init__(self, target_object: int = 0, rest_length: float = 5.0) -> None: ...
250
+ def __repr__(self) -> str: ...
251
+
252
+ class BoundaryConstraint:
253
+ """Keep object within a rectangular boundary.
254
+
255
+ Args:
256
+ min_x (float): Minimum X boundary
257
+ max_x (float): Maximum X boundary
258
+ min_y (float): Minimum Y boundary
259
+ max_y (float): Maximum Y boundary
260
+ """
261
+ min_x: float
262
+ max_x: float
263
+ min_y: float
264
+ max_y: float
265
+
266
+ def __init__(self, min_x: float = -10.0, max_x: float = 10.0, min_y: float = -10.0, max_y: float = 10.0) -> None: ...
267
+ def __repr__(self) -> str: ...
268
+
269
+ # ============================================================================
270
+ # MAIN SIMULATION CLASS
271
+ # ============================================================================
272
+
273
+ class Simulation:
274
+ """Main physics simulation class.
275
+
276
+ Provides real-time physics simulation with GPU acceleration.
277
+ Can run in headless mode (no window) or with OpenGL visualization.
278
+ """
279
+
280
+ def __init__(self,
281
+ headless: bool = True,
282
+ width: int = 1280,
283
+ height: int = 720,
284
+ title: str = "Physics Simulation",
285
+ enable_grid: bool = True) -> None:
286
+ """
287
+ Create a new simulation instance.
288
+
289
+ Args:
290
+ headless (bool): Run without graphical window. Default: True.
291
+ width (int): Window width in pixels. Default: 1280.
292
+ height (int): Window height in pixels. Default: 720.
293
+ title (str): Window title. Default: "Physics Simulation".
294
+ enable_grid (bool): Enable grid/axis rendering. Default: True.
295
+
296
+ Example:
297
+ >>> sim = Simulation(headless=True, enable_grid=False)
298
+ >>> sim = Simulation(width=1920, height=1080, title="My Simulation", enable_grid=True)
299
+ """
300
+ ...
301
+
302
+ # ========================================================================
303
+ # WINDOW MANAGEMENT
304
+ # ========================================================================
305
+
306
+ def render(self) -> None:
307
+ """Render the current frame to the window (visual mode only)."""
308
+ ...
309
+
310
+ def paint(self, arg: Union[str, int]) -> None:
311
+ """
312
+ Unified paint method.
313
+
314
+ If arg is a string, it's treated as a DSL equation.
315
+ If arg is an int, it's treated as a JIT script ID (from register_script).
316
+
317
+ DSL equation variables: px, py, t, p[id].x etc.
318
+ Assign color.r, color.g, color.b.
319
+ """
320
+ ...
321
+
322
+ def set_paint_resolution(self, width: int, height: int) -> None:
323
+ """Set internal resolution for paint shader (default = window size)."""
324
+ ...
325
+
326
+ def process_input(self) -> None:
327
+ """Process window input and camera controls (visual mode only)."""
328
+ ...
329
+
330
+ def should_close(self) -> bool:
331
+ """Check if window should close (visual mode only)."""
332
+ ...
333
+
334
+ # ========================================================================
335
+ # GRID CONTROL
336
+ # ========================================================================
337
+
338
+ def set_grid_enabled(self, enabled: bool) -> None:
339
+ """
340
+ Enable or disable grid/axis rendering.
341
+
342
+ Args:
343
+ enabled (bool): True to enable grid, False to disable
344
+ """
345
+ ...
346
+
347
+ def get_grid_enabled(self) -> bool:
348
+ """
349
+ Check if grid/axis rendering is enabled.
350
+
351
+ Returns:
352
+ bool: True if grid is enabled, False otherwise
353
+ """
354
+ ...
355
+
356
+ # ========================================================================
357
+ # CORE SIMULATION
358
+ # ========================================================================
359
+
360
+ def update(self, dt: float = 0.016) -> None:
361
+ """
362
+ Update physics simulation by dt seconds.
363
+
364
+ Args:
365
+ dt (float): Time step in seconds. Default: 0.016 (approx 60 FPS).
366
+
367
+ Example:
368
+ >>> sim.update(dt=0.01) # Update with 10ms time step
369
+ """
370
+ ...
371
+
372
+ def set_speed(self, speed: float) -> None:
373
+ """
374
+ Set speed multiplier (1.0 = normal).
375
+ Higher values make simulation faster without affecting stability.
376
+ """
377
+ ...
378
+
379
+ def get_speed(self) -> float:
380
+ """Get current speed multiplier."""
381
+ ...
382
+
383
+ # ========================================================================
384
+ # OBJECT MANAGEMENT
385
+ # ========================================================================
386
+
387
+ def add_object(
388
+ self,
389
+ x: float = 0.0,
390
+ y: float = 0.0,
391
+ vx: float = 0.0,
392
+ vy: float = 0.0,
393
+ mass: float = 1.0,
394
+ charge: float = 0.0,
395
+ rotation: float = 0.0,
396
+ angular_velocity: float = 0.0,
397
+ skin: SkinType = SkinType.CIRCLE,
398
+ size: float = 0.3,
399
+ width: float = 0.5,
400
+ height: float = 0.3,
401
+ r: float = 1.0,
402
+ g: float = 1.0,
403
+ b: float = 1.0,
404
+ a: float = 1.0,
405
+ polygon_sides: int = 6
406
+ ) -> int:
407
+ """
408
+ Add an object with full property control.
409
+
410
+ Args:
411
+ x,y (float): Initial position
412
+ vx,vy (float): Initial velocity
413
+ mass (float): Object mass. Default: 1.0
414
+ charge (float): Electric charge. Default: 0.0
415
+ rotation (float): Initial rotation in radians. Default: 0.0
416
+ angular_velocity (float): Angular velocity in rad/s. Default: 0.0
417
+ skin (SkinType): Visual type. Default: CIRCLE
418
+ size (float): General size. Default: 0.3
419
+ width,height (float): Dimensions for rectangles. Default: 0.5, 0.3
420
+ r,g,b,a (float): Color (0.0-1.0). Default: white (1,1,1,1)
421
+ polygon_sides (int): Polygon sides. Default: 6
422
+
423
+ Returns:
424
+ int: Object ID for future reference
425
+
426
+ Example:
427
+ >>> obj_id = sim.add_object(x=10, y=5, mass=50, skin=SkinType.CIRCLE)
428
+ """
429
+ ...
430
+
431
+ # Overload for full update (all positional args)
432
+ @overload
433
+ def update_object(
434
+ self,
435
+ index: int,
436
+ x: float, y: float,
437
+ vx: float, vy: float,
438
+ mass: float, charge: float,
439
+ rotation: float, angular_velocity: float,
440
+ size: float,
441
+ width: float, height: float,
442
+ r: float, g: float, b: float, a: float,
443
+ polygon_sides: int = 0
444
+ ) -> None: ...
445
+
446
+ # Overload for partial update with kwargs
447
+ @overload
448
+ def update_object(
449
+ self,
450
+ index: int,
451
+ *,
452
+ x: Optional[float] = None,
453
+ y: Optional[float] = None,
454
+ vx: Optional[float] = None,
455
+ vy: Optional[float] = None,
456
+ mass: Optional[float] = None,
457
+ charge: Optional[float] = None,
458
+ rotation: Optional[float] = None,
459
+ angular_velocity: Optional[float] = None,
460
+ size: Optional[float] = None,
461
+ width: Optional[float] = None,
462
+ height: Optional[float] = None,
463
+ r: Optional[float] = None,
464
+ g: Optional[float] = None,
465
+ b: Optional[float] = None,
466
+ a: Optional[float] = None,
467
+ polygon_sides: Optional[int] = None
468
+ ) -> None: ...
469
+
470
+ def update_object(self, index: int, *args, **kwargs) -> None:
471
+ """
472
+ Update all or partial properties of an existing object.
473
+
474
+ If called with all positional arguments, updates all properties.
475
+ If called with keyword arguments, only specified properties are updated.
476
+
477
+ Example:
478
+ # Full update
479
+ sim.update_object(0, 1.0, 2.0, 0.1, 0.2, 1.0, 0.0, 0.0, 0.0, 0.3, 0.5, 0.3, 1.0, 1.0, 1.0, 1.0)
480
+ # Partial update
481
+ sim.update_object(1, x=1.0, r=0.5)
482
+ """
483
+ ...
484
+
485
+ # ========================================================================
486
+ # BATCH OPERATIONS
487
+ # ========================================================================
488
+
489
+ def batch_get(self, indices: List[int]) -> List[BatchGetData]:
490
+ """
491
+ Get properties for multiple objects at once.
492
+
493
+ Args:
494
+ indices (list[int]): List of object indices to fetch
495
+
496
+ Returns:
497
+ list: List of BatchGetData objects for each index
498
+
499
+ Example:
500
+ >>> states = sim.batch_get([0, 1, 2, 3])
501
+ >>> for state in states:
502
+ >>> print(f"x={state.x}, y={state.y}")
503
+ """
504
+ ...
505
+
506
+ def batch_update(self, updates: List[BatchUpdateData]) -> None:
507
+ """
508
+ Update multiple objects at once.
509
+
510
+ Args:
511
+ updates (list[BatchUpdateData]): List of update data objects
512
+
513
+ Example:
514
+ >>> updates = [
515
+ >>> BatchUpdateData(index=0, x=1.0, y=2.0, ...),
516
+ >>> BatchUpdateData(index=1, x=3.0, y=4.0, ...)
517
+ >>> ]
518
+ >>> sim.batch_update(updates)
519
+ """
520
+ ...
521
+
522
+ def remove_object(self, index: int) -> None:
523
+ """Remove an object by ID."""
524
+ ...
525
+
526
+ def object_count(self) -> int:
527
+ """Get number of objects in simulation."""
528
+ ...
529
+
530
+ def get_object(self, index: int) -> ObjectState:
531
+ """
532
+ Get complete object state.
533
+
534
+ Args:
535
+ index (int): Object ID
536
+
537
+ Returns:
538
+ ObjectState: Complete object state
539
+ """
540
+ ...
541
+
542
+ # ========================================================================
543
+ # CONVENIENCE METHODS
544
+ # ========================================================================
545
+
546
+ def set_rotation(self, index: int, rotation: float) -> None:
547
+ """Set rotation angle in radians."""
548
+ ...
549
+
550
+ def set_angular_velocity(self, index: int, angular_velocity: float) -> None:
551
+ """Set angular velocity in rad/s."""
552
+ ...
553
+
554
+ def set_dimensions(self, index: int, width: float, height: float) -> None:
555
+ """Set width and height for rectangle objects."""
556
+ ...
557
+
558
+ def set_radius(self, index: int, radius: float) -> None:
559
+ """Set radius for circle/polygon objects."""
560
+ ...
561
+
562
+ def get_rotation(self, index: int) -> float:
563
+ """Get rotation angle in radians."""
564
+ ...
565
+
566
+ def get_angular_velocity(self, index: int) -> float:
567
+ """Get angular velocity in rad/s."""
568
+ ...
569
+
570
+ # ========================================================================
571
+ # EQUATIONS AND SCRIPTS
572
+ # ========================================================================
573
+
574
+ def set_equation(self, object_index: int, equation_string: str) -> None:
575
+ """
576
+ Set physics equation for object.
577
+
578
+ Args:
579
+ object_index (int): Object ID
580
+ equation_string (str): Physics equation
581
+
582
+ Equation syntax supports:
583
+ - Variables: x, y, vx, vy, mass, charge, time
584
+ - Object references: p[ID].x, p[ID].y, p[ID].mass
585
+ - Functions: sin, cos, tan, sqrt, exp, log
586
+ - Operators: +, -, *, /, ^ (power)
587
+
588
+ Example:
589
+ >>> sim.set_equation(0, "0.1*mass*(p[1].x - x)/distance^3")
590
+ """
591
+ ...
592
+
593
+ def register_script(self, source: str) -> int:
594
+ """Compile a Python script (source) and return script ID."""
595
+ ...
596
+
597
+ def set_script(self, object_index: int, script_id: int) -> None:
598
+ """
599
+ Assign a JIT script to an object (use -1 to revert to default DSL).
600
+ """
601
+ ...
602
+
603
+ # ========================================================================
604
+ # CONSTRAINTS
605
+ # ========================================================================
606
+
607
+ def add_distance_constraint(self, object_index: int, constraint: DistanceConstraint) -> None:
608
+ """Add distance constraint between objects."""
609
+ ...
610
+
611
+ def add_boundary_constraint(self, object_index: int, constraint: BoundaryConstraint) -> None:
612
+ """Add boundary constraint to object."""
613
+ ...
614
+
615
+ def clear_constraints(self, object_index: int) -> None:
616
+ """Clear all constraints from object."""
617
+ ...
618
+
619
+ def clear_all_constraints(self) -> None:
620
+ """Clear all constraints from all objects."""
621
+ ...
622
+
623
+ # ========================================================================
624
+ # COLLISION SYSTEM
625
+ # ========================================================================
626
+
627
+ def set_collision_enabled(self, index: int, enabled: bool) -> None:
628
+ """
629
+ Enable or disable collision detection for an object.
630
+
631
+ Args:
632
+ index (int): Object ID
633
+ enabled (bool): True to enable collisions, False to disable
634
+
635
+ Example:
636
+ >>> sim.set_collision_enabled(0, False) # Disable collisions for object 0
637
+ """
638
+ ...
639
+
640
+ def set_collision_shape(self, index: int, shape: CollisionShape) -> None:
641
+ """
642
+ Set collision shape for an object.
643
+
644
+ Args:
645
+ index (int): Object ID
646
+ shape (CollisionShape): Collision shape type
647
+
648
+ Note: Shape is automatically set based on visual skin when adding objects.
649
+
650
+ Example:
651
+ >>> sim.set_collision_shape(0, CollisionShape.CIRCLE)
652
+ """
653
+ ...
654
+
655
+ def set_collision_properties(self, index: int, restitution: float, friction: float) -> None:
656
+ """
657
+ Set collision physical properties.
658
+
659
+ Args:
660
+ index (int): Object ID
661
+ restitution (float): Bounciness (0.0-1.0)
662
+ 0.0 = no bounce (inelastic collision)
663
+ 1.0 = perfect bounce (elastic collision)
664
+ friction (float): Surface friction (0.0-1.0)
665
+ 0.0 = frictionless (ice)
666
+ 1.0 = maximum friction (rubber)
667
+
668
+ Example:
669
+ >>> sim.set_collision_properties(0, restitution=0.9, friction=0.1)
670
+ >>> # Makes object 0 very bouncy with low friction
671
+ """
672
+ ...
673
+
674
+ @overload
675
+ def set_collision(
676
+ self,
677
+ index: int,
678
+ *,
679
+ enabled: Optional[bool] = None,
680
+ shape: Optional[CollisionShape] = None,
681
+ restitution: Optional[float] = None,
682
+ friction: Optional[float] = None
683
+ ) -> None: ...
684
+
685
+ def set_collision(self, index: int, **kwargs) -> None:
686
+ """
687
+ Set collision properties for an object in a single call.
688
+
689
+ Args:
690
+ index (int): Object ID
691
+ enabled (bool, optional): Enable/disable collisions
692
+ shape (CollisionShape, optional): Collision shape type
693
+ restitution (float, optional): Bounciness (0.0-1.0)
694
+ friction (float, optional): Friction (0.0-1.0)
695
+
696
+ Example:
697
+ >>> sim.set_collision(0, shape=CollisionShape.CIRCLE, restitution=0.9, friction=0.1)
698
+ >>> sim.set_collision(1, enabled=False)
699
+ """
700
+ ...
701
+
702
+ def get_collision_config(self, index: int) -> CollisionConfig:
703
+ """
704
+ Get collision configuration for an object.
705
+
706
+ Args:
707
+ index (int): Object ID
708
+
709
+ Returns:
710
+ CollisionConfig: Current collision settings
711
+
712
+ Example:
713
+ >>> config = sim.get_collision_config(0)
714
+ >>> print(f"Restitution: {config.restitution}")
715
+ """
716
+ ...
717
+
718
+ def enable_collision_between(self, obj1: int, obj2: int, enable: bool) -> None:
719
+ """
720
+ Enable or disable collision detection between two specific objects.
721
+
722
+ Args:
723
+ obj1 (int): First object ID
724
+ obj2 (int): Second object ID
725
+ enable (bool): True to enable, False to disable
726
+
727
+ Useful for creating collision layers or groups.
728
+
729
+ Example:
730
+ >>> sim.enable_collision_between(0, 1, False)
731
+ >>> # Objects 0 and 1 will pass through each other
732
+ """
733
+ ...
734
+
735
+ def is_collision_enabled(self, index: int) -> bool:
736
+ """
737
+ Check if collision detection is enabled for an object.
738
+
739
+ Args:
740
+ index (int): Object ID
741
+
742
+ Returns:
743
+ bool: True if collisions are enabled
744
+ """
745
+ ...
746
+
747
+ def set_collision_parameters(self, enable_warm_start: bool, max_contact_iterations: int) -> None:
748
+ """
749
+ Set global collision parameters (warm start and iteration count).
750
+
751
+ Args:
752
+ enable_warm_start (bool): Enable warm starting for contacts
753
+ max_contact_iterations (int): Maximum iterations for contact resolution (1-20)
754
+ """
755
+ ...
756
+
757
+ def get_collision_parameters(self) -> Tuple[bool, int]:
758
+ """
759
+ Get global collision parameters.
760
+
761
+ Returns:
762
+ tuple: (enable_warm_start, max_contact_iterations)
763
+ """
764
+ ...
765
+
766
+ # ========================================================================
767
+ # BATCH PROCESSING
768
+ # ========================================================================
769
+
770
+ def run_batch(
771
+ self,
772
+ configs: List[BatchConfig],
773
+ callback: Optional[Callable[[int, List[ObjectState]], None]] = None
774
+ ) -> None:
775
+ """
776
+ Run multiple simulations in batch mode.
777
+
778
+ Args:
779
+ configs (list[BatchConfig]): List of simulation configurations
780
+ callback (callable): Optional callback for progress/results
781
+ Called as: callback(batch_index, results)
782
+
783
+ Note: Only works in headless mode.
784
+ """
785
+ ...
786
+
787
+ # ========================================================================
788
+ # PARAMETERS
789
+ # ========================================================================
790
+
791
+ def set_parameter(self, name: str, value: float) -> None:
792
+ """
793
+ Set global simulation parameter.
794
+
795
+ Args:
796
+ name (str): Parameter name
797
+ value (float): Parameter value
798
+
799
+ Available parameters:
800
+ - "gravity": Global gravity strength
801
+ - "damping": Velocity damping (0-1)
802
+ - "stiffness": Default constraint stiffness
803
+ """
804
+ ...
805
+
806
+ def get_parameter(self, name: str) -> float:
807
+ """Get global parameter value by name."""
808
+ ...
809
+
810
+ # ========================================================================
811
+ # SIMULATION CONTROL
812
+ # ========================================================================
813
+
814
+ def set_paused(self, paused: bool) -> None:
815
+ """Pause or resume simulation."""
816
+ ...
817
+
818
+ def is_paused(self) -> bool:
819
+ """Check if simulation is paused."""
820
+ ...
821
+
822
+ def update_shader_loading(self) -> None:
823
+ """Update shader loading status."""
824
+ ...
825
+
826
+ def are_all_shaders_ready(self) -> bool:
827
+ """Check if all shaders are loaded."""
828
+ ...
829
+
830
+ def get_shader_load_progress(self) -> float:
831
+ """Get shader loading progress (0.0 to 1.0)."""
832
+ ...
833
+
834
+ def get_shader_load_status(self) -> str:
835
+ """Get current shader loading status message."""
836
+ ...
837
+
838
+ def reset(self) -> None:
839
+ """Reset simulation to initial state (keeps objects)."""
840
+ ...
841
+
842
+ def cleanup(self) -> None:
843
+ """Explicitly cleanup resources."""
844
+ ...
845
+
846
+ # ========================================================================
847
+ # FILE I/O
848
+ # ========================================================================
849
+
850
+ def save_to_file(
851
+ self,
852
+ filename: str,
853
+ title: str = "",
854
+ author: str = "",
855
+ description: str = ""
856
+ ) -> None:
857
+ """
858
+ Save simulation state to .stellar file.
859
+
860
+ Args:
861
+ filename (str): Output file path
862
+ title (str): Simulation title
863
+ author (str): Author name
864
+ description (str): Simulation description
865
+ """
866
+ ...
867
+
868
+ def load_from_file(self, filename: str) -> None:
869
+ """
870
+ Load simulation state from .stellar file.
871
+
872
+ Args:
873
+ filename (str): Input file path
874
+ """
875
+ ...
876
+
877
+ # ========================================================================
878
+ # KEYBOARD AND CAMERA
879
+ # ========================================================================
880
+
881
+ @property
882
+ def keyboard(self) -> KeyboardMonitor:
883
+ """
884
+ Keyboard state monitor (e.g., sim.keyboard.Z.pressed, sim.keyboard.Space.released).
885
+ """
886
+ ...
887
+
888
+ def set_camera_position(self, x: float, y: float) -> None:
889
+ """Set the camera position in world coordinates."""
890
+ ...
891
+
892
+ def get_camera_position(self) -> Tuple[float, float]:
893
+ """Return the current camera position as a tuple (x, y)."""
894
+ ...
895
+
896
+ def set_camera_zoom(self, zoom: float) -> None:
897
+ """Set the camera zoom level (1.0 = default)."""
898
+ ...
899
+
900
+ def get_camera_zoom(self) -> float:
901
+ """Return the current camera zoom level."""
902
+ ...
903
+
904
+ # ========================================================================
905
+ # INPUT HELPERS
906
+ # ========================================================================
907
+
908
+ def default_input(self) -> None:
909
+ """
910
+ Default WASD + Q/E zoom + ESC close camera controls.
911
+ Call this in your loop for standard behavior.
912
+ """
913
+ ...
914
+
915
+ def get_mouse_position(self) -> Tuple[float, float]:
916
+ """
917
+ Returns the current mouse position in world coordinates.
918
+ """
919
+ ...
920
+
921
+ def get_mouse_delta(self) -> Tuple[float, float]:
922
+ """
923
+ Returns the mouse movement delta (in pixels) since the last call.
924
+ """
925
+ ...
926
+
927
+ # ========================================================================
928
+ # PROPERTIES
929
+ # ========================================================================
930
+
931
+ @property
932
+ def is_headless(self) -> bool:
933
+ """Check if simulation is running in headless mode."""
934
+ ...
935
+
936
+ @property
937
+ def is_initialized(self) -> bool:
938
+ """Check if simulation is fully initialized."""
939
+ ...
940
+
941
+ # ========================================================================
942
+ # SCRATCHPAD
943
+ # ========================================================================
944
+
945
+ def create_scratchpad(self, size: int) -> int:
946
+ """Create a scratchpad buffer with given number of floats."""
947
+ ...
948
+
949
+ def destroy_scratchpad(self, id: int) -> None:
950
+ """Destroy a scratchpad."""
951
+ ...
952
+
953
+ def upload_scratchpad(self, id: int, data: List[float]) -> None:
954
+ """Upload a list of floats to scratchpad."""
955
+ ...
956
+
957
+ def map_scratchpad(self, id: int) -> List[float]:
958
+ """Return a list of floats from scratchpad (CPU copy)."""
959
+ ...
960
+
961
+ def scratchpad_size(self, id: int) -> int:
962
+ """Get number of elements in scratchpad."""
963
+ ...
964
+
965
+ def is_valid_scratchpad(self, id: int) -> bool:
966
+ """Check if scratchpad ID is valid."""
967
+ ...
968
+
969
+ # ========================================================================
970
+ # SIGNAL QUEUE
971
+ # ========================================================================
972
+
973
+ def set_signal_queue_capacity(self, capacity: int) -> None:
974
+ """Set the maximum number of pending signals."""
975
+ ...
976
+
977
+ def set_signal_queue_overflow_policy(self, policy: int) -> None:
978
+ """Set overflow policy: 0=drop, 1=block."""
979
+ ...
980
+
981
+ def clear_signal_queue(self) -> None:
982
+ """Clear all pending signals."""
983
+ ...
984
+
985
+ def get_signal_queue_count(self) -> int:
986
+ """Get the number of pending signals."""
987
+ ...
988
+
989
+ # ========================================================================
990
+ # AGENT DISPATCH
991
+ # ========================================================================
992
+
993
+ def dispatch_agent(self, agent_id: int, clear_after: bool = True) -> None:
994
+ """
995
+ Dispatch a specific agent over all pending signals for that agent.
996
+ """
997
+ ...
998
+
999
+ def dispatch_all_agents(self, clear_after: bool = True) -> None:
1000
+ """
1001
+ Dispatch all registered agents over pending signals
1002
+ (each agent processes its own).
1003
+ """
1004
+ ...
1005
+
1006
+ def register_agent(self, source: str) -> int:
1007
+ """Compile an agent shader and return its ID."""
1008
+ ...
1009
+
1010
+ def get_agent_ids(self) -> List[int]:
1011
+ """Return a list of all registered agent IDs."""
1012
+ ...
1013
+
1014
+ # ============================================================================
1015
+ # MODULE-LEVEL EXPORTS
1016
+ # ============================================================================
1017
+
1018
+ # Version information
1019
+ __version__: str