Skip to content

comp110/spacepaint

Repository files navigation

Spacepaint

Spacepaint is turtle graphics reimagined for a 2026 introductory programming course. Instead of steering a turtle, students fly a small spacecraft through an origin-centered 3D scene and paint with sigma aura beams.

Run it

Install uv, then use Python 3.11:

uv sync --managed-python
uv run spacepaint

Spacepaint starts by running paint(ship) from student_code.py. That module records a program; the window then plays it from the beginning. Restart the app after editing student code.

Student coordinates

From the initial camera:

              +Y (up)
               |
               |
  -X ----------+---------- +X (right)
              /
             +Z (toward you)

The ship starts at (0, 0, 0), facing +X. Distances are world units and angles are degrees. The default ambient universe fills -100 through +100 on all three axes.

Student API

from spacepaint import Ship


def paint(ship: Ship) -> None:
    ship.beam_color("cyan")
    ship.beam_on()
    ship.forward(6)
    ship.turn_left(90)
    ship.forward(3)
    ship.beam_off()
    print(ship.state.position)

Movement methods:

  • forward(distance) and backward(distance) follow the ship's heading.
  • yaw_left(degrees) and yaw_right(degrees) point the nose left or right around the ship's own up axis. turn_left and turn_right are beginner-friendly aliases with the same ship-relative behavior.
  • pitch_up(degrees) and pitch_down(degrees) raise or lower the nose around the ship's own left-to-right axis.
  • roll_left(degrees) and roll_right(degrees) lower one wing and raise the other around the ship's own nose-to-tail axis.
  • arc(radius, degrees) follows a circular arc in the ship's current plane. Positive radii bend left and negative radii bend right, matching turtle graphics conventions.

Yaw, pitch, and roll rotate the craft in place around its center. Their axes move with the ship, matching standard aircraft controls.

Beam and playback methods:

  • beam_on() paints permanently; beam_on(fade_after=5) makes emitted beam samples remain for five seconds and then fade.
  • beam_off(), beam_color(name_or_hex), beam_width(width), and clear_beams() control the artwork.
  • fill_on(opacity=72/255) enables planar fills at an opacity from 0.0 to 1.0; zero disables fill and 1.0 is fully opaque. fill_off() disables fills, and fill_mode(enabled, opacity=72/255) is the boolean form. A fill takes the current beam color and opacity when it starts, including the default cyan or last selected color when the beam is off. Closing an outline or painting into a new plane makes the next filled motion start a new surface.
  • set_speed(multiplier) changes the speed of later movement and turns. set_speed(0) acts as a breakpoint and pauses before the following command. Left/right arrow keys can play next/previous commands.

Named colors are white, red, orange, yellow, green, cyan, blue, purple, magenta, and pink. Hex colors use #RRGGBB.

Window controls: left-drag orbits around the current camera target, the scroll wheel zooms, Space pauses, and Left/Right step backward or forward by one queued command while paused. R replays, A toggles labelled X/Y/Z axes, and V toggles between the default artwork view and a smoothly followed ship view. Artwork view tracks the center of the ship-and-beams bounding box and automatically zooms out with extra framing room to keep the whole drawing visible. 0 resets the current camera view, and H hides the HUD. The HUD also has view and axes toggle buttons.

Axis minor ticks mark each unit; numbered major ticks mark every five units. Opposite arrow presses cancel the most recently queued step.

Glow rendering

Spacepaint always renders a bright beam core plus additive halo geometry. When bloom is enabled, macOS uses a four-pass Panda3D FilterManager pipeline with GLSL 120 compatibility shaders; other platforms use Panda3D's CommonFilters bloom. If post-processing setup fails, Spacepaint keeps the layered geometry and continues without bloom.

The render configuration exposes enable_bloom, bloom_threshold, and bloom_intensity for testing and tuning. Geometry is antialiased with 4x MSAA by default, including the offscreen macOS bloom scene, and its final composite also uses FXAA to smooth any remaining high-contrast edges. Set antialias_samples to 0, 2, 4, or 8, and toggle enable_fxaa when testing. The HUD is composited separately so text remains crisp. No OpenGL/GLSL version PRC override is required or supported by this project.

Development

uv run pytest
uv run pyright

Rendering changes also require screenshots under artifacts/, as described in URSINA_PROJECT_SETUP.md and AGENTS.md.

License

Copyright (c) 2026 Kris Jordan kris@cs.unc.edu. Spacepaint is licensed under the MIT License.

Development Attribution

Development of this codebase was assisted by Codex using the 5.6 Sol model.

Assisted-by: Codex:5.6-Sol

About

No description, website, or topics provided.

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages