p5py-vibe 0.1.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.
- p5py_vibe-0.1.0/.github/workflows/ci.yml +41 -0
- p5py_vibe-0.1.0/.github/workflows/publish.yml +105 -0
- p5py_vibe-0.1.0/.gitignore +226 -0
- p5py_vibe-0.1.0/.python-version +1 -0
- p5py_vibe-0.1.0/AGENTS.md +349 -0
- p5py_vibe-0.1.0/CHANGELOG.md +16 -0
- p5py_vibe-0.1.0/Makefile +25 -0
- p5py_vibe-0.1.0/PKG-INFO +162 -0
- p5py_vibe-0.1.0/README.md +143 -0
- p5py_vibe-0.1.0/backlog/010_foundation_runtime/backend_protocols.toml +40 -0
- p5py_vibe-0.1.0/backlog/010_foundation_runtime/context_state.toml +33 -0
- p5py_vibe-0.1.0/backlog/010_foundation_runtime/package_scaffold.toml +40 -0
- p5py_vibe-0.1.0/backlog/010_foundation_runtime/sketch_lifecycle.toml +40 -0
- p5py_vibe-0.1.0/backlog/020_api_compatibility/compatibility_matrix.toml +33 -0
- p5py_vibe-0.1.0/backlog/020_api_compatibility/errors_and_overloads.toml +33 -0
- p5py_vibe-0.1.0/backlog/020_api_compatibility/global_mode_api.toml +33 -0
- p5py_vibe-0.1.0/backlog/020_api_compatibility/pythonic_aliases.toml +33 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/basic_primitives.toml +33 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/canvas_management.toml +33 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/headless_pillow_renderer.toml +33 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/hidpi_pixel_density.toml +68 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/interactive_backend.toml +40 -0
- p5py_vibe-0.1.0/backlog/030_rendering_2d/paths_and_curves.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/basic_native_primitives.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/hidpi_native_rendering.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/migration_and_cleanup.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/pixels_export_fallbacks.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/renderer_architecture.toml +40 -0
- p5py_vibe-0.1.0/backlog/031_native_pyglet_renderer/transforms_paths_curves.toml +40 -0
- p5py_vibe-0.1.0/backlog/040_color_style_transform/color_system.toml +33 -0
- p5py_vibe-0.1.0/backlog/040_color_style_transform/constants_modes.toml +33 -0
- p5py_vibe-0.1.0/backlog/040_color_style_transform/style_stack.toml +33 -0
- p5py_vibe-0.1.0/backlog/040_color_style_transform/transform_stack.toml +33 -0
- p5py_vibe-0.1.0/backlog/050_math_vector_noise/math_helpers.toml +33 -0
- p5py_vibe-0.1.0/backlog/050_math_vector_noise/random_noise.toml +40 -0
- p5py_vibe-0.1.0/backlog/050_math_vector_noise/vector_class.toml +40 -0
- p5py_vibe-0.1.0/backlog/060_assets_images_text/data_loading_saving.toml +33 -0
- p5py_vibe-0.1.0/backlog/060_assets_images_text/image_loading_drawing.toml +40 -0
- p5py_vibe-0.1.0/backlog/060_assets_images_text/image_manipulation.toml +40 -0
- p5py_vibe-0.1.0/backlog/060_assets_images_text/text_fonts.toml +33 -0
- p5py_vibe-0.1.0/backlog/061_native_pyglet_assets_text_export/docs_examples_capabilities.toml +33 -0
- p5py_vibe-0.1.0/backlog/061_native_pyglet_assets_text_export/native_image_drawing.toml +40 -0
- p5py_vibe-0.1.0/backlog/061_native_pyglet_assets_text_export/native_save_canvas_pixels.toml +47 -0
- p5py_vibe-0.1.0/backlog/061_native_pyglet_assets_text_export/native_text_fonts.toml +40 -0
- p5py_vibe-0.1.0/backlog/061_native_pyglet_assets_text_export/renderer_capability_cleanup.toml +33 -0
- p5py_vibe-0.1.0/backlog/062_transformed_image_rendering/image_transform_semantics.toml +54 -0
- p5py_vibe-0.1.0/backlog/070_input_events/keyboard_events.toml +40 -0
- p5py_vibe-0.1.0/backlog/070_input_events/mouse_events.toml +40 -0
- p5py_vibe-0.1.0/backlog/070_input_events/touch_events.toml +33 -0
- p5py_vibe-0.1.0/backlog/080_pixels_compositing/blend_modes.toml +40 -0
- p5py_vibe-0.1.0/backlog/080_pixels_compositing/pixel_buffer.toml +40 -0
- p5py_vibe-0.1.0/backlog/080_pixels_compositing/save_export.toml +33 -0
- p5py_vibe-0.1.0/backlog/081_native_pyglet_rendering_parity/native_pixels_compositing_parity.toml +75 -0
- p5py_vibe-0.1.0/backlog/090_rust_acceleration/accelerated_noise_pixels.toml +40 -0
- p5py_vibe-0.1.0/backlog/090_rust_acceleration/maturin_pipeline.toml +40 -0
- p5py_vibe-0.1.0/backlog/100_3d_advanced_media/model_shader_strategy.toml +33 -0
- p5py_vibe-0.1.0/backlog/100_3d_advanced_media/sound_media_strategy.toml +33 -0
- p5py_vibe-0.1.0/backlog/100_3d_advanced_media/webgl_like_renderer.toml +40 -0
- p5py_vibe-0.1.0/backlog/101_native_3d_media_implementation/model_loading.toml +40 -0
- p5py_vibe-0.1.0/backlog/101_native_3d_media_implementation/sound_playback_analysis.toml +40 -0
- p5py_vibe-0.1.0/backlog/101_native_3d_media_implementation/webgl_public_api_primitives.toml +40 -0
- p5py_vibe-0.1.0/backlog/101_native_3d_media_implementation/webgl_renderer_activation.toml +40 -0
- p5py_vibe-0.1.0/backlog/102_native_gpu_webgl_follow_on/native_pyglet_depth_renderer.toml +33 -0
- p5py_vibe-0.1.0/backlog/102_native_gpu_webgl_follow_on/shader_pipeline.toml +40 -0
- p5py_vibe-0.1.0/backlog/103_native_media_video_capture/native_media_capture.toml +40 -0
- p5py_vibe-0.1.0/backlog/110_quality_docs_release/plugin_architecture.toml +33 -0
- p5py_vibe-0.1.0/backlog/110_quality_docs_release/release_packaging.toml +33 -0
- p5py_vibe-0.1.0/backlog/110_quality_docs_release/testing_tooling.toml +40 -0
- p5py_vibe-0.1.0/backlog/110_quality_docs_release/user_documentation.toml +33 -0
- p5py_vibe-0.1.0/crates/p5_accel/Cargo.toml +16 -0
- p5py_vibe-0.1.0/crates/p5_accel/src/lib.rs +163 -0
- p5py_vibe-0.1.0/docs/README.md +28 -0
- p5py_vibe-0.1.0/docs/technical/README.md +12 -0
- p5py_vibe-0.1.0/docs/technical/advanced_3d_media_strategy.md +276 -0
- p5py_vibe-0.1.0/docs/technical/epic_101_kt.md +126 -0
- p5py_vibe-0.1.0/docs/technical/hidpi_rendering.md +62 -0
- p5py_vibe-0.1.0/docs/technical/native_pyglet_renderer.md +213 -0
- p5py_vibe-0.1.0/docs/technical/project_plan.md +446 -0
- p5py_vibe-0.1.0/docs/technical/releasing.md +82 -0
- p5py_vibe-0.1.0/docs/technical/rust_acceleration.md +108 -0
- p5py_vibe-0.1.0/docs/technical/testing.md +86 -0
- p5py_vibe-0.1.0/docs/user/README.md +11 -0
- p5py_vibe-0.1.0/docs/user/backends.md +61 -0
- p5py_vibe-0.1.0/docs/user/compatibility.md +54 -0
- p5py_vibe-0.1.0/docs/user/events.md +61 -0
- p5py_vibe-0.1.0/docs/user/getting_started.md +73 -0
- p5py_vibe-0.1.0/docs/user/images_and_pixels.md +49 -0
- p5py_vibe-0.1.0/docs/user/lifecycle.md +83 -0
- p5py_vibe-0.1.0/docs/user/plugins.md +73 -0
- p5py_vibe-0.1.0/examples/README.md +41 -0
- p5py_vibe-0.1.0/examples/accelerated_noise_pixels.py +135 -0
- p5py_vibe-0.1.0/examples/assets/Effects/fire17.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Effects/shield3.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Lasers/laserBlue01.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Meteors/meteorGrey_big1.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Meteors/meteorGrey_med1.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Meteors/meteorGrey_small1.png +0 -0
- p5py_vibe-0.1.0/examples/assets/Power-ups/powerupBlue_shield.png +0 -0
- p5py_vibe-0.1.0/examples/assets/coin-drop-4.wav +0 -0
- p5py_vibe-0.1.0/examples/assets/playerShip1_blue.png +0 -0
- p5py_vibe-0.1.0/examples/assets/playerShip3_green.png +0 -0
- p5py_vibe-0.1.0/examples/assets/teapot.obj +9965 -0
- p5py_vibe-0.1.0/examples/assets/ufoBlue.png +0 -0
- p5py_vibe-0.1.0/examples/asteroids.py +458 -0
- p5py_vibe-0.1.0/examples/audio_controls.py +126 -0
- p5py_vibe-0.1.0/examples/basic_shapes.py +67 -0
- p5py_vibe-0.1.0/examples/bouncing_ball.py +78 -0
- p5py_vibe-0.1.0/examples/color_style_filters.py +143 -0
- p5py_vibe-0.1.0/examples/custom_shape.py +61 -0
- p5py_vibe-0.1.0/examples/image_text_data.py +121 -0
- p5py_vibe-0.1.0/examples/pixels_blend_export.py +194 -0
- p5py_vibe-0.1.0/examples/plugin_hooks.py +52 -0
- p5py_vibe-0.1.0/examples/transforms.py +62 -0
- p5py_vibe-0.1.0/examples/vector_noise_flow.py +104 -0
- p5py_vibe-0.1.0/examples/video_capture.py +68 -0
- p5py_vibe-0.1.0/examples/video_playback.py +102 -0
- p5py_vibe-0.1.0/examples/webgl_native_shader.py +117 -0
- p5py_vibe-0.1.0/examples/webgl_obj_sound.py +72 -0
- p5py_vibe-0.1.0/examples/webgl_primitives_gallery.py +122 -0
- p5py_vibe-0.1.0/examples/webgl_texture_orbit.py +78 -0
- p5py_vibe-0.1.0/examples/webgl_wireframe_prototype.py +151 -0
- p5py_vibe-0.1.0/license.txt +458 -0
- p5py_vibe-0.1.0/main.py +6 -0
- p5py_vibe-0.1.0/pyproject.toml +70 -0
- p5py_vibe-0.1.0/src/p5_py/__init__.py +664 -0
- p5py_vibe-0.1.0/src/p5_py/api/__init__.py +1 -0
- p5py_vibe-0.1.0/src/p5_py/api/advanced.py +192 -0
- p5py_vibe-0.1.0/src/p5_py/api/aliases.py +202 -0
- p5py_vibe-0.1.0/src/p5_py/api/compatibility.py +269 -0
- p5py_vibe-0.1.0/src/p5_py/api/current.py +38 -0
- p5py_vibe-0.1.0/src/p5_py/api/global_mode.py +558 -0
- p5py_vibe-0.1.0/src/p5_py/assets/__init__.py +23 -0
- p5py_vibe-0.1.0/src/p5_py/assets/data.py +28 -0
- p5py_vibe-0.1.0/src/p5_py/assets/image.py +159 -0
- p5py_vibe-0.1.0/src/p5_py/assets/media.py +351 -0
- p5py_vibe-0.1.0/src/p5_py/assets/model.py +242 -0
- p5py_vibe-0.1.0/src/p5_py/assets/shader.py +46 -0
- p5py_vibe-0.1.0/src/p5_py/assets/sound.py +149 -0
- p5py_vibe-0.1.0/src/p5_py/assets/text.py +37 -0
- p5py_vibe-0.1.0/src/p5_py/backends/__init__.py +18 -0
- p5py_vibe-0.1.0/src/p5_py/backends/base.py +65 -0
- p5py_vibe-0.1.0/src/p5_py/backends/headless.py +75 -0
- p5py_vibe-0.1.0/src/p5_py/backends/pillow.py +587 -0
- p5py_vibe-0.1.0/src/p5_py/backends/pyglet.py +368 -0
- p5py_vibe-0.1.0/src/p5_py/backends/pyglet_renderer.py +579 -0
- p5py_vibe-0.1.0/src/p5_py/backends/pyglet_webgl_renderer.py +623 -0
- p5py_vibe-0.1.0/src/p5_py/backends/registry.py +49 -0
- p5py_vibe-0.1.0/src/p5_py/constants.py +176 -0
- p5py_vibe-0.1.0/src/p5_py/context.py +1144 -0
- p5py_vibe-0.1.0/src/p5_py/core/__init__.py +0 -0
- p5py_vibe-0.1.0/src/p5_py/core/color.py +135 -0
- p5py_vibe-0.1.0/src/p5_py/core/geometry.py +88 -0
- p5py_vibe-0.1.0/src/p5_py/core/math.py +166 -0
- p5py_vibe-0.1.0/src/p5_py/core/random.py +75 -0
- p5py_vibe-0.1.0/src/p5_py/core/state.py +101 -0
- p5py_vibe-0.1.0/src/p5_py/core/transform.py +71 -0
- p5py_vibe-0.1.0/src/p5_py/core/vector.py +308 -0
- p5py_vibe-0.1.0/src/p5_py/drawing/__init__.py +0 -0
- p5py_vibe-0.1.0/src/p5_py/drawing/prototype3d.py +205 -0
- p5py_vibe-0.1.0/src/p5_py/drawing/renderer.py +116 -0
- p5py_vibe-0.1.0/src/p5_py/drawing/renderer3d.py +186 -0
- p5py_vibe-0.1.0/src/p5_py/drawing/software3d.py +646 -0
- p5py_vibe-0.1.0/src/p5_py/events/__init__.py +0 -0
- p5py_vibe-0.1.0/src/p5_py/events/input_state.py +104 -0
- p5py_vibe-0.1.0/src/p5_py/exceptions.py +33 -0
- p5py_vibe-0.1.0/src/p5_py/pixels/__init__.py +0 -0
- p5py_vibe-0.1.0/src/p5_py/plugins/__init__.py +25 -0
- p5py_vibe-0.1.0/src/p5_py/plugins/base.py +108 -0
- p5py_vibe-0.1.0/src/p5_py/plugins/registry.py +214 -0
- p5py_vibe-0.1.0/src/p5_py/rust/__init__.py +222 -0
- p5py_vibe-0.1.0/src/p5_py/rust/_accelerated.pyi +10 -0
- p5py_vibe-0.1.0/src/p5_py/rust/benchmarks.py +123 -0
- p5py_vibe-0.1.0/src/p5_py/sketch.py +347 -0
- p5py_vibe-0.1.0/src/p5_py/testing/__init__.py +0 -0
- p5py_vibe-0.1.0/src/p5_py/testing/resources/__init__.py +1 -0
- p5py_vibe-0.1.0/src/p5_py/testing/resources/triangle.obj +5 -0
- p5py_vibe-0.1.0/tests/contracts/test_backends.py +14 -0
- p5py_vibe-0.1.0/tests/golden/test_basic_shapes_golden.py +24 -0
- p5py_vibe-0.1.0/tests/integration/test_drawing.py +46 -0
- p5py_vibe-0.1.0/tests/integration/test_webgl_3d.py +82 -0
- p5py_vibe-0.1.0/tests/parity/test_backend_alias_parity.py +21 -0
- p5py_vibe-0.1.0/tests/unit/test_3d_prototype.py +77 -0
- p5py_vibe-0.1.0/tests/unit/test_color_transform.py +19 -0
- p5py_vibe-0.1.0/tests/unit/test_compatibility.py +49 -0
- p5py_vibe-0.1.0/tests/unit/test_global_api.py +36 -0
- p5py_vibe-0.1.0/tests/unit/test_image_transform_semantics.py +75 -0
- p5py_vibe-0.1.0/tests/unit/test_input_events.py +79 -0
- p5py_vibe-0.1.0/tests/unit/test_lifecycle.py +44 -0
- p5py_vibe-0.1.0/tests/unit/test_math_vector_random_assets.py +98 -0
- p5py_vibe-0.1.0/tests/unit/test_media_capture.py +150 -0
- p5py_vibe-0.1.0/tests/unit/test_model_loading.py +42 -0
- p5py_vibe-0.1.0/tests/unit/test_pixel_density.py +65 -0
- p5py_vibe-0.1.0/tests/unit/test_pixels_export_blend.py +104 -0
- p5py_vibe-0.1.0/tests/unit/test_plugins.py +184 -0
- p5py_vibe-0.1.0/tests/unit/test_pyglet_backend.py +245 -0
- p5py_vibe-0.1.0/tests/unit/test_pyglet_renderer.py +383 -0
- p5py_vibe-0.1.0/tests/unit/test_rust_acceleration.py +128 -0
- p5py_vibe-0.1.0/tests/unit/test_sound_playback.py +81 -0
- p5py_vibe-0.1.0/tests/unit/test_webgl_api.py +268 -0
- p5py_vibe-0.1.0/uv.lock +482 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
quality:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
- uses: actions/checkout@v4
|
|
12
|
+
- uses: astral-sh/setup-uv@v6
|
|
13
|
+
- uses: actions/setup-python@v5
|
|
14
|
+
with:
|
|
15
|
+
python-version-file: .python-version
|
|
16
|
+
- run: uv sync --dev
|
|
17
|
+
- run: uv run ruff check .
|
|
18
|
+
- run: uv run mypy src
|
|
19
|
+
- run: uv run pytest
|
|
20
|
+
- run: uv run python examples/basic_shapes.py --backend headless --frames 1
|
|
21
|
+
|
|
22
|
+
build-python:
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: astral-sh/setup-uv@v6
|
|
27
|
+
- uses: actions/setup-python@v5
|
|
28
|
+
with:
|
|
29
|
+
python-version-file: .python-version
|
|
30
|
+
- run: uv build
|
|
31
|
+
|
|
32
|
+
build-rust:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
steps:
|
|
35
|
+
- uses: actions/checkout@v4
|
|
36
|
+
- uses: astral-sh/setup-uv@v6
|
|
37
|
+
- uses: actions/setup-python@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version-file: .python-version
|
|
40
|
+
- uses: dtolnay/rust-toolchain@stable
|
|
41
|
+
- run: uvx maturin build --release
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
inputs:
|
|
6
|
+
repository:
|
|
7
|
+
description: Package index to publish to
|
|
8
|
+
required: true
|
|
9
|
+
type: choice
|
|
10
|
+
options:
|
|
11
|
+
- testpypi
|
|
12
|
+
- pypi
|
|
13
|
+
default: testpypi
|
|
14
|
+
push:
|
|
15
|
+
tags:
|
|
16
|
+
- "v*"
|
|
17
|
+
|
|
18
|
+
permissions: {}
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
name: Build distributions
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
|
|
29
|
+
- uses: astral-sh/setup-uv@v6
|
|
30
|
+
|
|
31
|
+
- uses: actions/setup-python@v5
|
|
32
|
+
with:
|
|
33
|
+
python-version-file: .python-version
|
|
34
|
+
|
|
35
|
+
- name: Install dev dependencies
|
|
36
|
+
run: uv sync --dev
|
|
37
|
+
|
|
38
|
+
- name: Lint
|
|
39
|
+
run: uv run ruff check .
|
|
40
|
+
|
|
41
|
+
- name: Type check
|
|
42
|
+
run: uv run mypy src
|
|
43
|
+
|
|
44
|
+
- name: Run tests
|
|
45
|
+
run: uv run pytest
|
|
46
|
+
|
|
47
|
+
- name: Smoke test headless example
|
|
48
|
+
run: uv run python examples/basic_shapes.py --backend headless --frames 1
|
|
49
|
+
|
|
50
|
+
- name: Build sdist and wheel
|
|
51
|
+
run: uv build
|
|
52
|
+
|
|
53
|
+
- name: Verify distribution metadata
|
|
54
|
+
run: uv tool run twine check dist/*
|
|
55
|
+
|
|
56
|
+
- name: Upload distributions
|
|
57
|
+
uses: actions/upload-artifact@v4
|
|
58
|
+
with:
|
|
59
|
+
name: python-dist
|
|
60
|
+
path: dist/
|
|
61
|
+
|
|
62
|
+
publish-testpypi:
|
|
63
|
+
name: Publish to TestPyPI
|
|
64
|
+
if: github.event_name == 'workflow_dispatch' && inputs.repository == 'testpypi'
|
|
65
|
+
needs: build
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
environment:
|
|
68
|
+
name: testpypi
|
|
69
|
+
url: https://test.pypi.org/p/p5-py
|
|
70
|
+
permissions:
|
|
71
|
+
id-token: write
|
|
72
|
+
steps:
|
|
73
|
+
- name: Download distributions
|
|
74
|
+
uses: actions/download-artifact@v4
|
|
75
|
+
with:
|
|
76
|
+
name: python-dist
|
|
77
|
+
path: dist/
|
|
78
|
+
|
|
79
|
+
- name: Publish package distributions to TestPyPI
|
|
80
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
81
|
+
with:
|
|
82
|
+
repository-url: https://test.pypi.org/legacy/
|
|
83
|
+
packages-dir: dist/
|
|
84
|
+
|
|
85
|
+
publish-pypi:
|
|
86
|
+
name: Publish to PyPI
|
|
87
|
+
if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && inputs.repository == 'pypi')
|
|
88
|
+
needs: build
|
|
89
|
+
runs-on: ubuntu-latest
|
|
90
|
+
environment:
|
|
91
|
+
name: pypi
|
|
92
|
+
url: https://pypi.org/p/p5-py
|
|
93
|
+
permissions:
|
|
94
|
+
id-token: write
|
|
95
|
+
steps:
|
|
96
|
+
- name: Download distributions
|
|
97
|
+
uses: actions/download-artifact@v4
|
|
98
|
+
with:
|
|
99
|
+
name: python-dist
|
|
100
|
+
path: dist/
|
|
101
|
+
|
|
102
|
+
- name: Publish package distributions to PyPI
|
|
103
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
104
|
+
with:
|
|
105
|
+
packages-dir: dist/
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
examples/output/
|
|
2
|
+
|
|
3
|
+
# Created by https://www.toptal.com/developers/gitignore/api/python,macos,rust
|
|
4
|
+
# Edit at https://www.toptal.com/developers/gitignore?templates=python,macos,rust
|
|
5
|
+
|
|
6
|
+
### macOS ###
|
|
7
|
+
# General
|
|
8
|
+
.DS_Store
|
|
9
|
+
.AppleDouble
|
|
10
|
+
.LSOverride
|
|
11
|
+
|
|
12
|
+
# Icon must end with two \r
|
|
13
|
+
Icon
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Thumbnails
|
|
17
|
+
._*
|
|
18
|
+
|
|
19
|
+
# Files that might appear in the root of a volume
|
|
20
|
+
.DocumentRevisions-V100
|
|
21
|
+
.fseventsd
|
|
22
|
+
.Spotlight-V100
|
|
23
|
+
.TemporaryItems
|
|
24
|
+
.Trashes
|
|
25
|
+
.VolumeIcon.icns
|
|
26
|
+
.com.apple.timemachine.donotpresent
|
|
27
|
+
|
|
28
|
+
# Directories potentially created on remote AFP share
|
|
29
|
+
.AppleDB
|
|
30
|
+
.AppleDesktop
|
|
31
|
+
Network Trash Folder
|
|
32
|
+
Temporary Items
|
|
33
|
+
.apdisk
|
|
34
|
+
|
|
35
|
+
### macOS Patch ###
|
|
36
|
+
# iCloud generated files
|
|
37
|
+
*.icloud
|
|
38
|
+
|
|
39
|
+
### Python ###
|
|
40
|
+
# Byte-compiled / optimized / DLL files
|
|
41
|
+
__pycache__/
|
|
42
|
+
*.py[cod]
|
|
43
|
+
*$py.class
|
|
44
|
+
|
|
45
|
+
# C extensions
|
|
46
|
+
*.so
|
|
47
|
+
|
|
48
|
+
# Distribution / packaging
|
|
49
|
+
.Python
|
|
50
|
+
build/
|
|
51
|
+
develop-eggs/
|
|
52
|
+
dist/
|
|
53
|
+
downloads/
|
|
54
|
+
eggs/
|
|
55
|
+
.eggs/
|
|
56
|
+
lib/
|
|
57
|
+
lib64/
|
|
58
|
+
parts/
|
|
59
|
+
sdist/
|
|
60
|
+
var/
|
|
61
|
+
wheels/
|
|
62
|
+
share/python-wheels/
|
|
63
|
+
*.egg-info/
|
|
64
|
+
.installed.cfg
|
|
65
|
+
*.egg
|
|
66
|
+
MANIFEST
|
|
67
|
+
|
|
68
|
+
# PyInstaller
|
|
69
|
+
# Usually these files are written by a python script from a template
|
|
70
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
71
|
+
*.manifest
|
|
72
|
+
*.spec
|
|
73
|
+
|
|
74
|
+
# Installer logs
|
|
75
|
+
pip-log.txt
|
|
76
|
+
pip-delete-this-directory.txt
|
|
77
|
+
|
|
78
|
+
# Unit test / coverage reports
|
|
79
|
+
htmlcov/
|
|
80
|
+
.tox/
|
|
81
|
+
.nox/
|
|
82
|
+
.coverage
|
|
83
|
+
.coverage.*
|
|
84
|
+
.cache
|
|
85
|
+
nosetests.xml
|
|
86
|
+
coverage.xml
|
|
87
|
+
*.cover
|
|
88
|
+
*.py,cover
|
|
89
|
+
.hypothesis/
|
|
90
|
+
.pytest_cache/
|
|
91
|
+
cover/
|
|
92
|
+
|
|
93
|
+
# Translations
|
|
94
|
+
*.mo
|
|
95
|
+
*.pot
|
|
96
|
+
|
|
97
|
+
# Django stuff:
|
|
98
|
+
*.log
|
|
99
|
+
local_settings.py
|
|
100
|
+
db.sqlite3
|
|
101
|
+
db.sqlite3-journal
|
|
102
|
+
|
|
103
|
+
# Flask stuff:
|
|
104
|
+
instance/
|
|
105
|
+
.webassets-cache
|
|
106
|
+
|
|
107
|
+
# Scrapy stuff:
|
|
108
|
+
.scrapy
|
|
109
|
+
|
|
110
|
+
# Sphinx documentation
|
|
111
|
+
docs/_build/
|
|
112
|
+
|
|
113
|
+
# PyBuilder
|
|
114
|
+
.pybuilder/
|
|
115
|
+
target/
|
|
116
|
+
|
|
117
|
+
# Jupyter Notebook
|
|
118
|
+
.ipynb_checkpoints
|
|
119
|
+
|
|
120
|
+
# IPython
|
|
121
|
+
profile_default/
|
|
122
|
+
ipython_config.py
|
|
123
|
+
|
|
124
|
+
# pyenv
|
|
125
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
126
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
127
|
+
# .python-version
|
|
128
|
+
|
|
129
|
+
# pipenv
|
|
130
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
131
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
132
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
133
|
+
# install all needed dependencies.
|
|
134
|
+
#Pipfile.lock
|
|
135
|
+
|
|
136
|
+
# poetry
|
|
137
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
138
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
139
|
+
# commonly ignored for libraries.
|
|
140
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
141
|
+
#poetry.lock
|
|
142
|
+
|
|
143
|
+
# pdm
|
|
144
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
145
|
+
#pdm.lock
|
|
146
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
147
|
+
# in version control.
|
|
148
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
149
|
+
.pdm.toml
|
|
150
|
+
|
|
151
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
152
|
+
__pypackages__/
|
|
153
|
+
|
|
154
|
+
# Celery stuff
|
|
155
|
+
celerybeat-schedule
|
|
156
|
+
celerybeat.pid
|
|
157
|
+
|
|
158
|
+
# SageMath parsed files
|
|
159
|
+
*.sage.py
|
|
160
|
+
|
|
161
|
+
# Environments
|
|
162
|
+
.env
|
|
163
|
+
.venv
|
|
164
|
+
env/
|
|
165
|
+
venv/
|
|
166
|
+
ENV/
|
|
167
|
+
env.bak/
|
|
168
|
+
venv.bak/
|
|
169
|
+
|
|
170
|
+
# Spyder project settings
|
|
171
|
+
.spyderproject
|
|
172
|
+
.spyproject
|
|
173
|
+
|
|
174
|
+
# Rope project settings
|
|
175
|
+
.ropeproject
|
|
176
|
+
|
|
177
|
+
# mkdocs documentation
|
|
178
|
+
/site
|
|
179
|
+
|
|
180
|
+
# mypy
|
|
181
|
+
.mypy_cache/
|
|
182
|
+
.dmypy.json
|
|
183
|
+
dmypy.json
|
|
184
|
+
|
|
185
|
+
# Pyre type checker
|
|
186
|
+
.pyre/
|
|
187
|
+
|
|
188
|
+
# pytype static type analyzer
|
|
189
|
+
.pytype/
|
|
190
|
+
|
|
191
|
+
# Cython debug symbols
|
|
192
|
+
cython_debug/
|
|
193
|
+
|
|
194
|
+
# PyCharm
|
|
195
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
196
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
197
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
198
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
199
|
+
#.idea/
|
|
200
|
+
|
|
201
|
+
### Python Patch ###
|
|
202
|
+
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
|
203
|
+
poetry.toml
|
|
204
|
+
|
|
205
|
+
# ruff
|
|
206
|
+
.ruff_cache/
|
|
207
|
+
|
|
208
|
+
# LSP config files
|
|
209
|
+
pyrightconfig.json
|
|
210
|
+
|
|
211
|
+
### Rust ###
|
|
212
|
+
# Generated by Cargo
|
|
213
|
+
# will have compiled files and executables
|
|
214
|
+
debug/
|
|
215
|
+
|
|
216
|
+
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
|
217
|
+
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
|
218
|
+
Cargo.lock
|
|
219
|
+
|
|
220
|
+
# These are backup files generated by rustfmt
|
|
221
|
+
**/*.rs.bk
|
|
222
|
+
|
|
223
|
+
# MSVC Windows builds of rustc generate these, which store debugging information
|
|
224
|
+
*.pdb
|
|
225
|
+
|
|
226
|
+
# End of https://www.toptal.com/developers/gitignore/api/python,macos,rust
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guidance for AI coding agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## Project overview
|
|
6
|
+
|
|
7
|
+
This repository contains `p5-py`, a Pythonic creative-coding package inspired by p5.js.
|
|
8
|
+
|
|
9
|
+
The goal is to provide a familiar p5-style sketching model for Python while keeping the implementation idiomatic, maintainable, typed, testable, and backend-agnostic.
|
|
10
|
+
|
|
11
|
+
The package must remain native Python. Do not add JavaScript or HTML code.
|
|
12
|
+
|
|
13
|
+
## Package workflow
|
|
14
|
+
|
|
15
|
+
This project uses `uv`.
|
|
16
|
+
|
|
17
|
+
Use `uv` for dependency and command execution:
|
|
18
|
+
|
|
19
|
+
```sh
|
|
20
|
+
uv sync --dev
|
|
21
|
+
uv run pytest
|
|
22
|
+
uv run ruff check .
|
|
23
|
+
uv run ruff format .
|
|
24
|
+
uv run python examples/basic_shapes.py --backend headless --frames 1
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Do not use raw `pip install` or unmanaged virtual environments unless explicitly requested.
|
|
28
|
+
|
|
29
|
+
The active Python version is defined by `.python-version` and `pyproject.toml`.
|
|
30
|
+
|
|
31
|
+
## Source layout
|
|
32
|
+
|
|
33
|
+
Primary package code lives under:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
src/p5_py/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Important areas:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
src/p5_py/api/ global-mode API, p5.js aliases, compatibility stubs
|
|
43
|
+
src/p5_py/backends/ backend implementations and backend registry
|
|
44
|
+
src/p5_py/core/ color, geometry, state, transforms, math-like core systems
|
|
45
|
+
src/p5_py/drawing/ renderer protocol and drawing abstractions
|
|
46
|
+
src/p5_py/events/ normalized input/event state
|
|
47
|
+
src/p5_py/pixels/ future pixel-buffer functionality
|
|
48
|
+
src/p5_py/plugins/ future plugin architecture
|
|
49
|
+
src/p5_py/rust/ future Rust acceleration integration
|
|
50
|
+
src/p5_py/testing/ future testing helpers
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Tests live under:
|
|
54
|
+
|
|
55
|
+
```text
|
|
56
|
+
tests/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Examples live under:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
examples/
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Docs live under:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
docs/
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Backlog items live under:
|
|
72
|
+
|
|
73
|
+
```text
|
|
74
|
+
backlog/<three_digit_epic_name>/<pbi_name>.toml
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Architecture principles
|
|
78
|
+
|
|
79
|
+
### Keep public API backend-agnostic
|
|
80
|
+
|
|
81
|
+
The public p5-py API must not directly depend on Pillow, Pyglet, or any future renderer.
|
|
82
|
+
|
|
83
|
+
The intended layering is:
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
user sketch
|
|
87
|
+
↓
|
|
88
|
+
p5_py public API
|
|
89
|
+
↓
|
|
90
|
+
Sketch / SketchContext
|
|
91
|
+
↓
|
|
92
|
+
Renderer + Backend protocols
|
|
93
|
+
↓
|
|
94
|
+
Concrete backend / renderer
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Separate backend responsibilities from renderer responsibilities
|
|
98
|
+
|
|
99
|
+
Backends own platform/window/runtime concerns.
|
|
100
|
+
|
|
101
|
+
Renderers own drawing.
|
|
102
|
+
|
|
103
|
+
For example:
|
|
104
|
+
|
|
105
|
+
- `PygletBackend` should own window creation, the event loop, input normalization, frame scheduling, and shutdown.
|
|
106
|
+
- A future `PygletRenderer` should own native Pyglet drawing.
|
|
107
|
+
- `PillowRenderer` should remain the deterministic headless/export renderer.
|
|
108
|
+
|
|
109
|
+
Do not push sketch lifecycle, p5.js aliasing, or argument parsing into backend-specific code.
|
|
110
|
+
|
|
111
|
+
### Preserve custom backend support
|
|
112
|
+
|
|
113
|
+
Future custom backends should be able to integrate by implementing the backend and renderer protocols and registering themselves through the backend registry.
|
|
114
|
+
|
|
115
|
+
Avoid hardcoding backend classes outside `p5_py.backends.registry` and backend selection logic.
|
|
116
|
+
|
|
117
|
+
### Keep p5 compatibility and Pythonic API together
|
|
118
|
+
|
|
119
|
+
Canonical Python APIs should use `snake_case`, for example:
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
create_canvas()
|
|
123
|
+
frame_rate()
|
|
124
|
+
no_loop()
|
|
125
|
+
pixel_density()
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
p5.js-style aliases may be provided where useful:
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
createCanvas()
|
|
132
|
+
frameRate()
|
|
133
|
+
noLoop()
|
|
134
|
+
pixelDensity()
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Aliases must delegate to the same implementation. Do not duplicate behavior.
|
|
138
|
+
|
|
139
|
+
### Keep exports type-checker friendly
|
|
140
|
+
|
|
141
|
+
`src/p5_py/__init__.py` should use explicit imports for public APIs. Avoid dynamic wildcard export machinery that makes Zed/Pyright unable to see package attributes.
|
|
142
|
+
|
|
143
|
+
## Rendering guidance
|
|
144
|
+
|
|
145
|
+
### Current rendering state
|
|
146
|
+
|
|
147
|
+
The current Pyglet backend is a bridge backend:
|
|
148
|
+
|
|
149
|
+
```text
|
|
150
|
+
PillowRenderer renders the frame
|
|
151
|
+
PygletBackend presents that image in a native Pyglet window
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
This is intentional for now. See:
|
|
155
|
+
|
|
156
|
+
```text
|
|
157
|
+
docs/technical/native_pyglet_renderer.md
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
The planned next rendering milestone is a native `PygletRenderer`.
|
|
161
|
+
|
|
162
|
+
### HiDPI and pixel density
|
|
163
|
+
|
|
164
|
+
p5-py distinguishes logical canvas dimensions from physical backing-buffer dimensions.
|
|
165
|
+
|
|
166
|
+
- `width()` and `height()` are logical p5 dimensions.
|
|
167
|
+
- `pixel_density()` controls physical backing scale.
|
|
168
|
+
- `display_density()` reports native display scale when the backend supports it.
|
|
169
|
+
- `load_pixels()` and `update_pixels()` currently operate on physical RGBA buffers.
|
|
170
|
+
|
|
171
|
+
See:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
docs/technical/hidpi_rendering.md
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Do not regress Retina/HiDPI behavior when changing renderers or backends.
|
|
178
|
+
|
|
179
|
+
## Exclusions
|
|
180
|
+
|
|
181
|
+
Do not add:
|
|
182
|
+
|
|
183
|
+
- JavaScript code
|
|
184
|
+
- HTML code
|
|
185
|
+
- DOM APIs
|
|
186
|
+
- browser-only APIs
|
|
187
|
+
- `p5.XML`
|
|
188
|
+
- `p5.Table`
|
|
189
|
+
- `p5.TableRow`
|
|
190
|
+
|
|
191
|
+
Excluded APIs should raise clear package-specific errors when exposed as compatibility stubs.
|
|
192
|
+
|
|
193
|
+
## Backlog conventions
|
|
194
|
+
|
|
195
|
+
Backlog epics use a three-digit prefix to allow insertion between epics, for example:
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
010_foundation_runtime
|
|
199
|
+
020_api_compatibility
|
|
200
|
+
030_rendering_2d
|
|
201
|
+
031_native_pyglet_renderer
|
|
202
|
+
040_color_style_transform
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Each PBI file must use this TOML layout:
|
|
206
|
+
|
|
207
|
+
```toml
|
|
208
|
+
[my_pbi]
|
|
209
|
+
title = "..."
|
|
210
|
+
description = '''
|
|
211
|
+
As a ...,
|
|
212
|
+
I want ...,
|
|
213
|
+
So that ...
|
|
214
|
+
'''
|
|
215
|
+
acceptance_criteria = '''
|
|
216
|
+
...
|
|
217
|
+
'''
|
|
218
|
+
priotity = 'high|medium|low'
|
|
219
|
+
status = 'TODO|IN_PROGRESS|DONE'
|
|
220
|
+
|
|
221
|
+
[my_pbi.task_1]
|
|
222
|
+
order = 1
|
|
223
|
+
status = 'TODO|IN_PROGRESS|DONE'
|
|
224
|
+
description = '''
|
|
225
|
+
...
|
|
226
|
+
'''
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Note: the existing schema intentionally uses the misspelled key `priotity`. Preserve it unless the user explicitly requests a schema migration.
|
|
230
|
+
|
|
231
|
+
When completing work that corresponds to backlog items, update both PBI and task statuses.
|
|
232
|
+
|
|
233
|
+
Allowed status values are:
|
|
234
|
+
|
|
235
|
+
```text
|
|
236
|
+
TODO
|
|
237
|
+
IN_PROGRESS
|
|
238
|
+
DONE
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Validate backlog TOML after edits:
|
|
242
|
+
|
|
243
|
+
```sh
|
|
244
|
+
python - <<'PY'
|
|
245
|
+
from pathlib import Path
|
|
246
|
+
import tomllib
|
|
247
|
+
for path in sorted(Path('backlog').glob('**/*.toml')):
|
|
248
|
+
with path.open('rb') as f:
|
|
249
|
+
tomllib.load(f)
|
|
250
|
+
print('Backlog TOML parsed successfully')
|
|
251
|
+
PY
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Testing and validation
|
|
255
|
+
|
|
256
|
+
Before finishing code changes, run:
|
|
257
|
+
|
|
258
|
+
```sh
|
|
259
|
+
uv run ruff check .
|
|
260
|
+
uv run pytest
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
If formatting changes are needed, run:
|
|
264
|
+
|
|
265
|
+
```sh
|
|
266
|
+
uv run ruff format .
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Also check Zed diagnostics when practical.
|
|
270
|
+
|
|
271
|
+
For rendering changes, run at least one headless example smoke test, such as:
|
|
272
|
+
|
|
273
|
+
```sh
|
|
274
|
+
uv run python examples/basic_shapes.py --backend headless --frames 1
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
If examples generate output files, do not accidentally commit generated artifacts unless the user explicitly wants them tracked.
|
|
278
|
+
|
|
279
|
+
## Test expectations
|
|
280
|
+
|
|
281
|
+
Add or update tests when changing behavior.
|
|
282
|
+
|
|
283
|
+
Current useful test areas:
|
|
284
|
+
|
|
285
|
+
```text
|
|
286
|
+
tests/contracts/ backend and renderer contract behavior
|
|
287
|
+
tests/integration/ end-to-end sketch rendering behavior
|
|
288
|
+
tests/unit/ API, lifecycle, color, transforms, density, backend details
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Prefer deterministic headless tests for renderer behavior where possible.
|
|
292
|
+
|
|
293
|
+
For interactive Pyglet behavior, use focused unit tests with fake window/module objects when possible, and document any manual smoke tests.
|
|
294
|
+
|
|
295
|
+
## Documentation expectations
|
|
296
|
+
|
|
297
|
+
Update docs when changing architecture, public APIs, rendering behavior, backend behavior, or compatibility status.
|
|
298
|
+
|
|
299
|
+
Relevant docs include:
|
|
300
|
+
|
|
301
|
+
```text
|
|
302
|
+
docs/technical/project_plan.md
|
|
303
|
+
docs/technical/hidpi_rendering.md
|
|
304
|
+
docs/technical/native_pyglet_renderer.md
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
## Rust guidance
|
|
308
|
+
|
|
309
|
+
Rust acceleration is planned but should remain optional and contained.
|
|
310
|
+
|
|
311
|
+
Future Rust code should live under:
|
|
312
|
+
|
|
313
|
+
```text
|
|
314
|
+
crates/
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
Rust should be used only for pure computational hot paths such as:
|
|
318
|
+
|
|
319
|
+
- noise generation
|
|
320
|
+
- pixel filters
|
|
321
|
+
- blend modes
|
|
322
|
+
- color conversion
|
|
323
|
+
- geometry tessellation
|
|
324
|
+
- path flattening
|
|
325
|
+
|
|
326
|
+
Every Rust-accelerated feature must have a Python fallback unless the user explicitly changes this requirement.
|
|
327
|
+
|
|
328
|
+
## Dependency guidance
|
|
329
|
+
|
|
330
|
+
Prefer existing dependencies already in `pyproject.toml`.
|
|
331
|
+
|
|
332
|
+
Current core dependencies include:
|
|
333
|
+
|
|
334
|
+
- Pillow
|
|
335
|
+
- Pyglet
|
|
336
|
+
|
|
337
|
+
Current dev dependencies include:
|
|
338
|
+
|
|
339
|
+
- pytest
|
|
340
|
+
- ruff
|
|
341
|
+
|
|
342
|
+
Add new dependencies only when justified by the task, and use `uv add` or `uv add --dev` so `pyproject.toml` and `uv.lock` stay in sync.
|
|
343
|
+
|
|
344
|
+
## Safety notes
|
|
345
|
+
|
|
346
|
+
- Do not modify the sibling `p5.js` repository unless the user explicitly asks.
|
|
347
|
+
- Do not commit changes unless the user explicitly asks.
|
|
348
|
+
- Do not remove or overwrite generated/user files unless you are sure they are artifacts from your own validation commands.
|
|
349
|
+
- Keep changes focused on the requested task.
|