gummy-snake 0.5.0__tar.gz

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 (185) hide show
  1. gummy_snake-0.5.0/PKG-INFO +208 -0
  2. gummy_snake-0.5.0/README.md +186 -0
  3. gummy_snake-0.5.0/crates/gummy_canvas/Cargo.lock +2609 -0
  4. gummy_snake-0.5.0/crates/gummy_canvas/Cargo.toml +22 -0
  5. gummy_snake-0.5.0/crates/gummy_canvas/src/bindings.rs +353 -0
  6. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/curves.rs +191 -0
  7. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/gpu.rs +267 -0
  8. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/images/helpers.rs +212 -0
  9. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/images/mod.rs +142 -0
  10. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/lifecycle.rs +243 -0
  11. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/methods.rs +324 -0
  12. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/mod.rs +8 -0
  13. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/pixels.rs +212 -0
  14. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/primitives.rs +232 -0
  15. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/text/cache.rs +209 -0
  16. gummy_snake-0.5.0/crates/gummy_canvas/src/canvas/text/mod.rs +130 -0
  17. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/mod.rs +13 -0
  18. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/pipeline.rs +277 -0
  19. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/render.rs +223 -0
  20. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/setup.rs +183 -0
  21. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/shaders.rs +117 -0
  22. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/surface.rs +162 -0
  23. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/tests.rs +73 -0
  24. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/textures.rs +136 -0
  25. gummy_snake-0.5.0/crates/gummy_canvas/src/gpu/types.rs +96 -0
  26. gummy_snake-0.5.0/crates/gummy_canvas/src/images.rs +265 -0
  27. gummy_snake-0.5.0/crates/gummy_canvas/src/lib.rs +443 -0
  28. gummy_snake-0.5.0/crates/gummy_canvas/src/performance.rs +45 -0
  29. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/blend.rs +70 -0
  30. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/blit.rs +179 -0
  31. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/gpu.rs +29 -0
  32. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/mod.rs +22 -0
  33. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/queries.rs +91 -0
  34. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/shapes.rs +236 -0
  35. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/transform.rs +187 -0
  36. gummy_snake-0.5.0/crates/gummy_canvas/src/raster/types.rs +69 -0
  37. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/app/handler.rs +130 -0
  38. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/app.rs +236 -0
  39. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/desktop.rs +94 -0
  40. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/event.rs +138 -0
  41. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/input.rs +106 -0
  42. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/mod.rs +20 -0
  43. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/stub.rs +49 -0
  44. gummy_snake-0.5.0/crates/gummy_canvas/src/runtime/style.rs +229 -0
  45. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/lighting.rs +106 -0
  46. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/math.rs +97 -0
  47. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/mod.rs +389 -0
  48. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/obj.rs +411 -0
  49. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/payload.rs +178 -0
  50. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/primitives.rs +397 -0
  51. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/project.rs +176 -0
  52. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/rasterize.rs +211 -0
  53. gummy_snake-0.5.0/crates/gummy_canvas/src/software3d/types.rs +77 -0
  54. gummy_snake-0.5.0/crates/gummy_canvas/src/tests.rs +225 -0
  55. gummy_snake-0.5.0/crates/gummy_canvas/src/text.rs +139 -0
  56. gummy_snake-0.5.0/license.txt +458 -0
  57. gummy_snake-0.5.0/pyproject.toml +83 -0
  58. gummy_snake-0.5.0/src/gummysnake/__init__.py +745 -0
  59. gummy_snake-0.5.0/src/gummysnake/_async.py +81 -0
  60. gummy_snake-0.5.0/src/gummysnake/_context/__init__.py +1 -0
  61. gummy_snake-0.5.0/src/gummysnake/_context/_protocols.py +16 -0
  62. gummy_snake-0.5.0/src/gummysnake/_context/canvas.py +233 -0
  63. gummy_snake-0.5.0/src/gummysnake/_context/helpers.py +114 -0
  64. gummy_snake-0.5.0/src/gummysnake/_context/images.py +45 -0
  65. gummy_snake-0.5.0/src/gummysnake/_context/input.py +120 -0
  66. gummy_snake-0.5.0/src/gummysnake/_context/pixels.py +241 -0
  67. gummy_snake-0.5.0/src/gummysnake/_context/shapes.py +226 -0
  68. gummy_snake-0.5.0/src/gummysnake/_context/style.py +121 -0
  69. gummy_snake-0.5.0/src/gummysnake/_context/text.py +179 -0
  70. gummy_snake-0.5.0/src/gummysnake/_context/three_d/__init__.py +7 -0
  71. gummy_snake-0.5.0/src/gummysnake/_context/three_d/_protocols.py +34 -0
  72. gummy_snake-0.5.0/src/gummysnake/_context/three_d/camera.py +139 -0
  73. gummy_snake-0.5.0/src/gummysnake/_context/three_d/context.py +125 -0
  74. gummy_snake-0.5.0/src/gummysnake/_context/three_d/material.py +134 -0
  75. gummy_snake-0.5.0/src/gummysnake/_context/three_d/model.py +127 -0
  76. gummy_snake-0.5.0/src/gummysnake/_context/three_d/primitives.py +123 -0
  77. gummy_snake-0.5.0/src/gummysnake/_context/transform.py +81 -0
  78. gummy_snake-0.5.0/src/gummysnake/_fast_draw.py +105 -0
  79. gummy_snake-0.5.0/src/gummysnake/api/__init__.py +1 -0
  80. gummy_snake-0.5.0/src/gummysnake/api/_environment_input.py +126 -0
  81. gummy_snake-0.5.0/src/gummysnake/api/_facades.py +107 -0
  82. gummy_snake-0.5.0/src/gummysnake/api/_lifecycle.py +120 -0
  83. gummy_snake-0.5.0/src/gummysnake/api/_media_text_pixels.py +204 -0
  84. gummy_snake-0.5.0/src/gummysnake/api/advanced.py +267 -0
  85. gummy_snake-0.5.0/src/gummysnake/api/current.py +38 -0
  86. gummy_snake-0.5.0/src/gummysnake/api/global_mode/__init__.py +391 -0
  87. gummy_snake-0.5.0/src/gummysnake/api/global_mode/canvas.py +144 -0
  88. gummy_snake-0.5.0/src/gummysnake/api/global_mode/contexts.py +127 -0
  89. gummy_snake-0.5.0/src/gummysnake/api/global_mode/exports.py +192 -0
  90. gummy_snake-0.5.0/src/gummysnake/api/global_mode/helpers.py +28 -0
  91. gummy_snake-0.5.0/src/gummysnake/api/global_mode/shapes.py +124 -0
  92. gummy_snake-0.5.0/src/gummysnake/assets/__init__.py +40 -0
  93. gummy_snake-0.5.0/src/gummysnake/assets/_paths.py +47 -0
  94. gummy_snake-0.5.0/src/gummysnake/assets/data.py +96 -0
  95. gummy_snake-0.5.0/src/gummysnake/assets/image/__init__.py +9 -0
  96. gummy_snake-0.5.0/src/gummysnake/assets/image/canvas.py +56 -0
  97. gummy_snake-0.5.0/src/gummysnake/assets/image/deferred.py +57 -0
  98. gummy_snake-0.5.0/src/gummysnake/assets/image/loading.py +32 -0
  99. gummy_snake-0.5.0/src/gummysnake/assets/image/model.py +276 -0
  100. gummy_snake-0.5.0/src/gummysnake/assets/image/ops.py +125 -0
  101. gummy_snake-0.5.0/src/gummysnake/assets/image/source.py +58 -0
  102. gummy_snake-0.5.0/src/gummysnake/assets/media/__init__.py +21 -0
  103. gummy_snake-0.5.0/src/gummysnake/assets/media/cv2.py +52 -0
  104. gummy_snake-0.5.0/src/gummysnake/assets/media/frame.py +50 -0
  105. gummy_snake-0.5.0/src/gummysnake/assets/media/streams.py +303 -0
  106. gummy_snake-0.5.0/src/gummysnake/assets/model.py +73 -0
  107. gummy_snake-0.5.0/src/gummysnake/assets/shader.py +47 -0
  108. gummy_snake-0.5.0/src/gummysnake/assets/sound.py +270 -0
  109. gummy_snake-0.5.0/src/gummysnake/assets/text.py +59 -0
  110. gummy_snake-0.5.0/src/gummysnake/backend/__init__.py +14 -0
  111. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/__init__.py +1 -0
  112. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/backend/__init__.py +1 -0
  113. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/backend/_protocols.py +37 -0
  114. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/backend/events.py +199 -0
  115. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/backend/pacing.py +90 -0
  116. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/backend/runtime.py +166 -0
  117. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/events.py +132 -0
  118. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/__init__.py +1 -0
  119. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/_protocols.py +35 -0
  120. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/core.py +255 -0
  121. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/images.py +117 -0
  122. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/pixels.py +165 -0
  123. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/primitives.py +243 -0
  124. gummy_snake-0.5.0/src/gummysnake/backend/_canvas/renderer/text.py +59 -0
  125. gummy_snake-0.5.0/src/gummysnake/backend/base.py +68 -0
  126. gummy_snake-0.5.0/src/gummysnake/backend/canvas.py +160 -0
  127. gummy_snake-0.5.0/src/gummysnake/backend/canvas_renderer.py +56 -0
  128. gummy_snake-0.5.0/src/gummysnake/backend/registry.py +23 -0
  129. gummy_snake-0.5.0/src/gummysnake/constants/__init__.py +205 -0
  130. gummy_snake-0.5.0/src/gummysnake/constants/aliases.py +189 -0
  131. gummy_snake-0.5.0/src/gummysnake/constants/drawing.py +99 -0
  132. gummy_snake-0.5.0/src/gummysnake/constants/input.py +59 -0
  133. gummy_snake-0.5.0/src/gummysnake/constants/renderer.py +48 -0
  134. gummy_snake-0.5.0/src/gummysnake/context.py +71 -0
  135. gummy_snake-0.5.0/src/gummysnake/core/__init__.py +0 -0
  136. gummy_snake-0.5.0/src/gummysnake/core/color.py +249 -0
  137. gummy_snake-0.5.0/src/gummysnake/core/data.py +26 -0
  138. gummy_snake-0.5.0/src/gummysnake/core/geometry.py +133 -0
  139. gummy_snake-0.5.0/src/gummysnake/core/math.py +165 -0
  140. gummy_snake-0.5.0/src/gummysnake/core/random.py +91 -0
  141. gummy_snake-0.5.0/src/gummysnake/core/state.py +111 -0
  142. gummy_snake-0.5.0/src/gummysnake/core/transform.py +214 -0
  143. gummy_snake-0.5.0/src/gummysnake/core/vector/__init__.py +7 -0
  144. gummy_snake-0.5.0/src/gummysnake/core/vector/basic.py +175 -0
  145. gummy_snake-0.5.0/src/gummysnake/core/vector/common.py +81 -0
  146. gummy_snake-0.5.0/src/gummysnake/core/vector/model.py +37 -0
  147. gummy_snake-0.5.0/src/gummysnake/core/vector/ops.py +272 -0
  148. gummy_snake-0.5.0/src/gummysnake/drawing/__init__.py +0 -0
  149. gummy_snake-0.5.0/src/gummysnake/drawing/prototype3d.py +205 -0
  150. gummy_snake-0.5.0/src/gummysnake/drawing/renderer.py +173 -0
  151. gummy_snake-0.5.0/src/gummysnake/drawing/renderer3d.py +613 -0
  152. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/__init__.py +41 -0
  153. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/export.py +92 -0
  154. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/math3d.py +65 -0
  155. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/primitives.py +118 -0
  156. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/projection.py +95 -0
  157. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/raster.py +205 -0
  158. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/rust_bridge.py +167 -0
  159. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/shading.py +197 -0
  160. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/transform.py +42 -0
  161. gummy_snake-0.5.0/src/gummysnake/drawing/software3d/types.py +31 -0
  162. gummy_snake-0.5.0/src/gummysnake/events/__init__.py +0 -0
  163. gummy_snake-0.5.0/src/gummysnake/events/input_state.py +147 -0
  164. gummy_snake-0.5.0/src/gummysnake/exceptions.py +33 -0
  165. gummy_snake-0.5.0/src/gummysnake/pixels/__init__.py +0 -0
  166. gummy_snake-0.5.0/src/gummysnake/plugins/__init__.py +31 -0
  167. gummy_snake-0.5.0/src/gummysnake/plugins/base.py +105 -0
  168. gummy_snake-0.5.0/src/gummysnake/plugins/registry.py +216 -0
  169. gummy_snake-0.5.0/src/gummysnake/rust/__init__.py +39 -0
  170. gummy_snake-0.5.0/src/gummysnake/rust/_accelerated.pyi +19 -0
  171. gummy_snake-0.5.0/src/gummysnake/rust/_canvas.pyi +311 -0
  172. gummy_snake-0.5.0/src/gummysnake/rust/acceleration.py +74 -0
  173. gummy_snake-0.5.0/src/gummysnake/rust/animated.py +102 -0
  174. gummy_snake-0.5.0/src/gummysnake/rust/benchmarks.py +123 -0
  175. gummy_snake-0.5.0/src/gummysnake/rust/blend.py +40 -0
  176. gummy_snake-0.5.0/src/gummysnake/rust/canvas.py +302 -0
  177. gummy_snake-0.5.0/src/gummysnake/rust/noise.py +115 -0
  178. gummy_snake-0.5.0/src/gummysnake/rust/runtime.py +137 -0
  179. gummy_snake-0.5.0/src/gummysnake/rust/validation.py +20 -0
  180. gummy_snake-0.5.0/src/gummysnake/sketch/__init__.py +7 -0
  181. gummy_snake-0.5.0/src/gummysnake/sketch/facade.py +292 -0
  182. gummy_snake-0.5.0/src/gummysnake/sketch/runtime.py +208 -0
  183. gummy_snake-0.5.0/src/gummysnake/testing/__init__.py +0 -0
  184. gummy_snake-0.5.0/src/gummysnake/testing/resources/__init__.py +1 -0
  185. gummy_snake-0.5.0/src/gummysnake/testing/resources/triangle.obj +5 -0
@@ -0,0 +1,208 @@
1
+ Metadata-Version: 2.4
2
+ Name: gummy-snake
3
+ Version: 0.5.0
4
+ Classifier: Development Status :: 3 - Alpha
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: Intended Audience :: Education
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.12
9
+ Classifier: Topic :: Artistic Software
10
+ Classifier: Topic :: Multimedia :: Graphics
11
+ Requires-Dist: opencv-python-headless>=4.13.0.92 ; extra == 'media'
12
+ Requires-Dist: numpy>=2.4.6 ; extra == 'numpy'
13
+ Provides-Extra: media
14
+ Provides-Extra: numpy
15
+ License-File: license.txt
16
+ Summary: A playful Python toolkit for creative coding and small games.
17
+ Keywords: creative-coding,games,graphics,python,sketches
18
+ License-Expression: LGPL-2.1-only
19
+ Requires-Python: >=3.12
20
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
21
+
22
+ # Gummy Snake
23
+
24
+ [![PyPI](https://img.shields.io/pypi/v/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
25
+ [![Python Versions](https://img.shields.io/pypi/pyversions/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
26
+ [![License: LGPL-2.1](https://img.shields.io/badge/License-LGPL--2.1-blue.svg)](license.txt)
27
+ [![Downloads](https://img.shields.io/pypi/dm/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
28
+
29
+ Gummy Snake is a playful Python toolkit for creative coding and small games. It
30
+ is for people who want to sketch with code: draw shapes, animate motion, react
31
+ to input, load sprites, play with pixels, and build visual toys without first
32
+ building a full app.
33
+
34
+ The public API is Python-first. Function names use `snake_case`, sketches are
35
+ ordinary Python files, and the renderer is powered by the packaged Rust canvas
36
+ runtime.
37
+
38
+ ## Install
39
+
40
+ ```sh
41
+ pip install gummy-snake
42
+ ```
43
+
44
+ Published wheels include the required Rust `gummy_canvas` canvas runtime. Source
45
+ or editable installs must build that PyO3 module; there is no Python renderer
46
+ fallback for canvas-owned behavior.
47
+
48
+ Install optional media helpers when you need camera, video, or sound-related
49
+ extras:
50
+
51
+ ```sh
52
+ pip install "gummy-snake[media]"
53
+ ```
54
+
55
+ ## First Sketch
56
+
57
+ Create a file named `circle_sketch.py`:
58
+
59
+ ```python
60
+ import gummysnake as gs
61
+
62
+
63
+ @gs.setup
64
+ def setup() -> None:
65
+ gs.create_canvas(400, 300)
66
+ gs.no_stroke()
67
+
68
+
69
+ @gs.draw
70
+ def draw() -> None:
71
+ gs.background(245)
72
+ gs.fill(255, 90, 90)
73
+ gs.circle(200, 150, 100)
74
+
75
+
76
+ gs.run()
77
+ ```
78
+
79
+ Run it:
80
+
81
+ ```sh
82
+ python circle_sketch.py
83
+ ```
84
+
85
+ For repeatable scripts, use a bounded headless render:
86
+
87
+ ```python
88
+ gs.run(headless=True, max_frames=1)
89
+ ```
90
+
91
+ Callbacks can also be `async def`, which is useful with async-compatible asset
92
+ helpers:
93
+
94
+ ```python
95
+ image = None
96
+
97
+
98
+ @gs.preload
99
+ async def preload() -> None:
100
+ global image
101
+ image = await gs.load_image_async("sprite.png")
102
+ ```
103
+
104
+ ## What You Can Make
105
+
106
+ - 2D drawings with shapes, curves, color, transforms, and blend modes.
107
+ - Animated sketches using the familiar `setup()` and `draw()` lifecycle.
108
+ - Decorator-based sketches, async-compatible callbacks, and object-oriented
109
+ `Sketch` subclasses.
110
+ - Image and pixel experiments, including canvas export.
111
+ - Text, font measurement, and accessibility descriptions.
112
+ - Interactive sketches with mouse, keyboard, and touch state when native window
113
+ support is available.
114
+ - Software 3D sketches with primitives, lights, materials, models, textures,
115
+ and shader objects on the current Rust-backed software 3D path.
116
+ - Small games and visual toys using the examples as starting points.
117
+
118
+ Loaded images, models/meshes, and sounds keep Rust-managed asset handles behind
119
+ friendly Python wrappers. This is intentional for performance: bulk asset bytes,
120
+ geometry arrays, parsing, export, and metadata extraction should stay in the
121
+ Rust canvas runtime so sketches avoid repeated Python object materialization and
122
+ per-element loops. Normal `load_image(); image(...)` sprite drawing can stay on
123
+ the fast renderer path, model projection/export can use Rust-owned geometry
124
+ without first creating Python `Vec3` objects, and loaded sounds keep their bytes
125
+ and duration metadata in `CanvasSound` until user code asks for Python bytes.
126
+ Image-local resize, mask, filter, crop/copy, and alpha compositing delegate
127
+ bulk byte work to the Rust canvas runtime while keeping the Python `Image`
128
+ API and version semantics.
129
+ For pixel effects, `load_pixels()` returns a list-based pixel buffer and
130
+ `load_pixel_bytes()` provides a bytes readback path; `update_pixels()` accepts
131
+ lists and buffer-like inputs such as `bytes`, `bytearray`, and `memoryview`.
132
+ Small canvas `get()` and `set()` region operations use Rust region calls instead
133
+ of reconstructing the full canvas as a Python image.
134
+ For dense drawing loops, `gs.fast()` returns a frame-local facade that keeps
135
+ public style/transform state while reducing global-mode dispatch overhead.
136
+ Opt-in `enable_performance_diagnostics()` counters can identify readback, pixel
137
+ conversion, upload, texture cache, and CPU compositing fallback paths.
138
+
139
+ ## Learn More
140
+
141
+ - [Getting started](docs/getting_started/index.md)
142
+ - [Examples](examples/README.md)
143
+ - [API reference](docs/reference/index.md)
144
+ - [Contributor docs](docs/contribute/index.md)
145
+
146
+ ## For Contributors
147
+
148
+ This repository uses `uv` for Python commands:
149
+
150
+ ```sh
151
+ uv sync --dev
152
+ uv run ruff check .
153
+ uv run mypy src
154
+ uv run pytest
155
+ ```
156
+
157
+ The canvas runtime is a required PyO3 module for development/source installs:
158
+
159
+ ```sh
160
+ uvx maturin develop --manifest-path crates/gummy_canvas/Cargo.toml --features extension-module
161
+ ```
162
+
163
+ The refactored Python package is split by responsibility: public API modules in
164
+ `src/gummysnake/api/`, `SketchContext` mixins in `src/gummysnake/_context/`,
165
+ lifecycle code in `src/gummysnake/sketch/`, enum-backed constants in
166
+ `src/gummysnake/constants/`, and thin canvas backend/renderer facades over the
167
+ implementation modules in `src/gummysnake/backend/_canvas/`.
168
+
169
+ The contributor documentation explains the architecture, lifecycle, testing
170
+ workflow, and release shape in more detail:
171
+
172
+ - [Contributor guide](docs/contribute/index.md)
173
+ - [Architecture](docs/contribute/architecture.md)
174
+ - [Backend and renderer boundaries](docs/contribute/backend_renderer.md)
175
+ - [Runtime model](docs/contribute/runtime.md)
176
+ - [Runtime diagnostics](docs/contribute/runtime_diagnostics.md)
177
+ - [Build capabilities](docs/contribute/build_capabilities.md)
178
+ - [API performance policy](docs/contribute/api_performance_policy.md)
179
+ - [Testing and CI](docs/contribute/testing.md)
180
+
181
+ Performance benchmarks are opt-in:
182
+
183
+ ```sh
184
+ uv run pytest tests/benchmark/test_canvas_backend_perf.py --run-benchmarks
185
+ uv run pytest tests/benchmark/test_api_overhead_perf.py --run-benchmarks
186
+ uv run pytest tests/benchmark/test_image_pipeline_perf.py --run-benchmarks
187
+ uv run pytest tests/benchmark/test_model_export_perf.py --run-benchmarks
188
+ uv run pytest tests/benchmark/test_webgl_3d_perf.py --run-benchmarks
189
+ ```
190
+
191
+ Canvas benchmark scenarios are expected to average at least 120 FPS. Failures
192
+ below that floor are intentional optimization signals. Model export benchmarks
193
+ use a memory budget for streaming OBJ/STL output. Machine-specific baseline
194
+ snapshots live in `tests/benchmark/baselines/`.
195
+
196
+ Long-running resource lifecycle checks are also opt-in:
197
+
198
+ ```sh
199
+ uv run pytest tests/stress --run-stress -q -s
200
+ ```
201
+
202
+ ## Compatibility
203
+
204
+ Gummy Snake keeps the sketch lifecycle familiar, but it is not a browser port.
205
+ It does not include DOM helpers, browser-only APIs, JavaScript aliases, or a
206
+ Pillow/Pyglet/Python renderer fallback. Unsupported features raise explicit
207
+ package errors so sketches fail clearly.
208
+
@@ -0,0 +1,186 @@
1
+ # Gummy Snake
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
4
+ [![Python Versions](https://img.shields.io/pypi/pyversions/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
5
+ [![License: LGPL-2.1](https://img.shields.io/badge/License-LGPL--2.1-blue.svg)](license.txt)
6
+ [![Downloads](https://img.shields.io/pypi/dm/gummy-snake.svg)](https://pypi.org/project/gummy-snake/)
7
+
8
+ Gummy Snake is a playful Python toolkit for creative coding and small games. It
9
+ is for people who want to sketch with code: draw shapes, animate motion, react
10
+ to input, load sprites, play with pixels, and build visual toys without first
11
+ building a full app.
12
+
13
+ The public API is Python-first. Function names use `snake_case`, sketches are
14
+ ordinary Python files, and the renderer is powered by the packaged Rust canvas
15
+ runtime.
16
+
17
+ ## Install
18
+
19
+ ```sh
20
+ pip install gummy-snake
21
+ ```
22
+
23
+ Published wheels include the required Rust `gummy_canvas` canvas runtime. Source
24
+ or editable installs must build that PyO3 module; there is no Python renderer
25
+ fallback for canvas-owned behavior.
26
+
27
+ Install optional media helpers when you need camera, video, or sound-related
28
+ extras:
29
+
30
+ ```sh
31
+ pip install "gummy-snake[media]"
32
+ ```
33
+
34
+ ## First Sketch
35
+
36
+ Create a file named `circle_sketch.py`:
37
+
38
+ ```python
39
+ import gummysnake as gs
40
+
41
+
42
+ @gs.setup
43
+ def setup() -> None:
44
+ gs.create_canvas(400, 300)
45
+ gs.no_stroke()
46
+
47
+
48
+ @gs.draw
49
+ def draw() -> None:
50
+ gs.background(245)
51
+ gs.fill(255, 90, 90)
52
+ gs.circle(200, 150, 100)
53
+
54
+
55
+ gs.run()
56
+ ```
57
+
58
+ Run it:
59
+
60
+ ```sh
61
+ python circle_sketch.py
62
+ ```
63
+
64
+ For repeatable scripts, use a bounded headless render:
65
+
66
+ ```python
67
+ gs.run(headless=True, max_frames=1)
68
+ ```
69
+
70
+ Callbacks can also be `async def`, which is useful with async-compatible asset
71
+ helpers:
72
+
73
+ ```python
74
+ image = None
75
+
76
+
77
+ @gs.preload
78
+ async def preload() -> None:
79
+ global image
80
+ image = await gs.load_image_async("sprite.png")
81
+ ```
82
+
83
+ ## What You Can Make
84
+
85
+ - 2D drawings with shapes, curves, color, transforms, and blend modes.
86
+ - Animated sketches using the familiar `setup()` and `draw()` lifecycle.
87
+ - Decorator-based sketches, async-compatible callbacks, and object-oriented
88
+ `Sketch` subclasses.
89
+ - Image and pixel experiments, including canvas export.
90
+ - Text, font measurement, and accessibility descriptions.
91
+ - Interactive sketches with mouse, keyboard, and touch state when native window
92
+ support is available.
93
+ - Software 3D sketches with primitives, lights, materials, models, textures,
94
+ and shader objects on the current Rust-backed software 3D path.
95
+ - Small games and visual toys using the examples as starting points.
96
+
97
+ Loaded images, models/meshes, and sounds keep Rust-managed asset handles behind
98
+ friendly Python wrappers. This is intentional for performance: bulk asset bytes,
99
+ geometry arrays, parsing, export, and metadata extraction should stay in the
100
+ Rust canvas runtime so sketches avoid repeated Python object materialization and
101
+ per-element loops. Normal `load_image(); image(...)` sprite drawing can stay on
102
+ the fast renderer path, model projection/export can use Rust-owned geometry
103
+ without first creating Python `Vec3` objects, and loaded sounds keep their bytes
104
+ and duration metadata in `CanvasSound` until user code asks for Python bytes.
105
+ Image-local resize, mask, filter, crop/copy, and alpha compositing delegate
106
+ bulk byte work to the Rust canvas runtime while keeping the Python `Image`
107
+ API and version semantics.
108
+ For pixel effects, `load_pixels()` returns a list-based pixel buffer and
109
+ `load_pixel_bytes()` provides a bytes readback path; `update_pixels()` accepts
110
+ lists and buffer-like inputs such as `bytes`, `bytearray`, and `memoryview`.
111
+ Small canvas `get()` and `set()` region operations use Rust region calls instead
112
+ of reconstructing the full canvas as a Python image.
113
+ For dense drawing loops, `gs.fast()` returns a frame-local facade that keeps
114
+ public style/transform state while reducing global-mode dispatch overhead.
115
+ Opt-in `enable_performance_diagnostics()` counters can identify readback, pixel
116
+ conversion, upload, texture cache, and CPU compositing fallback paths.
117
+
118
+ ## Learn More
119
+
120
+ - [Getting started](docs/getting_started/index.md)
121
+ - [Examples](examples/README.md)
122
+ - [API reference](docs/reference/index.md)
123
+ - [Contributor docs](docs/contribute/index.md)
124
+
125
+ ## For Contributors
126
+
127
+ This repository uses `uv` for Python commands:
128
+
129
+ ```sh
130
+ uv sync --dev
131
+ uv run ruff check .
132
+ uv run mypy src
133
+ uv run pytest
134
+ ```
135
+
136
+ The canvas runtime is a required PyO3 module for development/source installs:
137
+
138
+ ```sh
139
+ uvx maturin develop --manifest-path crates/gummy_canvas/Cargo.toml --features extension-module
140
+ ```
141
+
142
+ The refactored Python package is split by responsibility: public API modules in
143
+ `src/gummysnake/api/`, `SketchContext` mixins in `src/gummysnake/_context/`,
144
+ lifecycle code in `src/gummysnake/sketch/`, enum-backed constants in
145
+ `src/gummysnake/constants/`, and thin canvas backend/renderer facades over the
146
+ implementation modules in `src/gummysnake/backend/_canvas/`.
147
+
148
+ The contributor documentation explains the architecture, lifecycle, testing
149
+ workflow, and release shape in more detail:
150
+
151
+ - [Contributor guide](docs/contribute/index.md)
152
+ - [Architecture](docs/contribute/architecture.md)
153
+ - [Backend and renderer boundaries](docs/contribute/backend_renderer.md)
154
+ - [Runtime model](docs/contribute/runtime.md)
155
+ - [Runtime diagnostics](docs/contribute/runtime_diagnostics.md)
156
+ - [Build capabilities](docs/contribute/build_capabilities.md)
157
+ - [API performance policy](docs/contribute/api_performance_policy.md)
158
+ - [Testing and CI](docs/contribute/testing.md)
159
+
160
+ Performance benchmarks are opt-in:
161
+
162
+ ```sh
163
+ uv run pytest tests/benchmark/test_canvas_backend_perf.py --run-benchmarks
164
+ uv run pytest tests/benchmark/test_api_overhead_perf.py --run-benchmarks
165
+ uv run pytest tests/benchmark/test_image_pipeline_perf.py --run-benchmarks
166
+ uv run pytest tests/benchmark/test_model_export_perf.py --run-benchmarks
167
+ uv run pytest tests/benchmark/test_webgl_3d_perf.py --run-benchmarks
168
+ ```
169
+
170
+ Canvas benchmark scenarios are expected to average at least 120 FPS. Failures
171
+ below that floor are intentional optimization signals. Model export benchmarks
172
+ use a memory budget for streaming OBJ/STL output. Machine-specific baseline
173
+ snapshots live in `tests/benchmark/baselines/`.
174
+
175
+ Long-running resource lifecycle checks are also opt-in:
176
+
177
+ ```sh
178
+ uv run pytest tests/stress --run-stress -q -s
179
+ ```
180
+
181
+ ## Compatibility
182
+
183
+ Gummy Snake keeps the sketch lifecycle familiar, but it is not a browser port.
184
+ It does not include DOM helpers, browser-only APIs, JavaScript aliases, or a
185
+ Pillow/Pyglet/Python renderer fallback. Unsupported features raise explicit
186
+ package errors so sketches fail clearly.