Skip to content

Commit

Permalink
Cleanup documentation, add processo usage
Browse files Browse the repository at this point in the history
  • Loading branch information
JohnEdChristensen committed Feb 5, 2024
1 parent 6f7619b commit 568aca0
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 41 deletions.
79 changes: 65 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@

## Examples

Live Examples:
- https://johnedchristensen.github.io/diver/src/?filename=sketches/impossible_object.py
- https://johnedchristensen.github.io/diver/src/?filename=sketches/rainbow.py
- https://johnedchristensen.github.io/diver/src/?filename=sketches/e_field.py
- https://johnedchristensen.github.io/diver/src/?filename=sketches/squares.py
### Interactive
- https://johnedchristensen.github.io/diver/src/?filename=sketches/string.py

Examples:
- [Using processo](https://johnedchristensen.github.io/diver/?filename=examples/processo_figure_8.py)
- [Impossible Triangle](https://johnedchristensen.github.io/diver/?filename=examples/impossible_object.py)
- [Rainbow Wave](https://johnedchristensen.github.io/diver/?filename=examples/rainbow.py)
- [Swirling Squares](https://johnedchristensen.github.io/diver/?filename=examples/squares.py)
- [Simulated String](https://johnedchristensen.github.io/diver/src/?filename=sketches/string.py)
## About
A simple python package that makes it easy to share interactive visuals on the web.
A python package that aimes to make it easy to share interactive visuals online.

Uses Pyodide to run python directly in the browser, meaning code can be shared with others without any need to download/install/configure python.

It also can be served from a static website server, meaning it is simple to embed visuals on personal websites/blogs.
Expand All @@ -20,7 +22,9 @@ It also can be served from a static website server, meaning it is simple to embe
- [x] Render static images to a canvas element
- [x] live reloading development server
- [x] Render animated canvas/WebGL
- [ ] pythonic drawing API (with beginner/user friendly documentation/examples)
- [x] pythonic drawing API (with beginner/user friendly documentation/examples)
- [x] [processo](https://github.com/nickmcintyre/proceso) offers a great python binding for p5js. It is now installed by default.
- Examples: https://proceso.cc/examples/creative_coding/simple_shapes
- [x] Write code in browser
- [-] in browser LSP features like inline docs, autocomplete, linting, type checking
- [ ] Human friendly documentation (with live running/editable examples of course)
Expand All @@ -31,16 +35,63 @@ It also can be served from a static website server, meaning it is simple to embe

## Usage
The current state of the library is in very active development. Expect breaking changes.
### Pixel level drawing
[This example (rainbow.py)](https://johnedchristensen.github.io/diver/src/?filename=rainbow.py) shows some basic usage. It specifies each pixel on the canvas, so you can draw anything you want directly this way. It isn't very performant this way, so the resolution needs to be pretty low to run smoothly.

### 2D Canvas API

[This example (squares.py)](https://johnedchristensen.github.io/diver/src/?filename=squares.py) draws to canvas using the JavaScript canvas API. This is much more performant, and can run at higher resolutions/frame rates. To use this mode you'll need to know (or learn) how to use the [canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)
## Basics
Use "Show Code" button to view/edit the code yourself!
After making changes click "Run" or use Ctrl-Enter to run your code.

[Get started](https://johnedchristensen.github.io/diver/?filename=examples/processo_simple_shapes.py) with a drawing example using p5js (via processo).
### p5.js
> p5.js is a JavaScript library for creative coding, with a focus on making coding accessible and inclusive for artists, designers, educators, beginners, and anyone else! p5.js is free and open-source because we believe software, and the tools to learn it, should be accessible to everyone.vascript library
https://p5js.org/

p5.js is a great project, but is limited to using javascipt. Using Pyodide, python code can now run alongisde javascript code in your browser, and use all the functionality that p5.js offers. An additional library needs to handle translations between p5.js and python, and processo does just that!
### processo
The [processo](https://github.com/nickmcintyre/proceso) lets you use [p5js](https://p5js.org/) from python.
#### Example
[Try it out](https://johnedchristensen.github.io/diver/?filename=examples/processo_simple_shapes.py)
```python
from proceso import Sketch


p5 = Sketch()
p5.describe("A rectangle, circle, triangle, and flower drawn in pink on a gray background.")

# Create the canvas
p5.create_canvas(720, 400)
p5.background(200)

# Set colors
p5.fill(204, 101, 192, 127)
p5.stroke(127, 63, 120)

# A rectangle
p5.rect(40, 120, 120, 40)
# A circle
p5.circle(240, 240, 80)
# A triangle
p5.triangle(300, 100, 320, 100, 310, 80)

# A design for a simple flower
p5.translate(580, 200)
p5.no_stroke()
for _ in range(10):
p5.ellipse(0, 30, 20, 80)
p5.rotate(p5.PI / 5)
```
From processo documentation:
Checkout more processo examples: https://proceso.cc/examples/creative_coding/

### Lower level APIs
These methods are a bit more complex, but can be useful if you want to work more directly with your visuals.
#### Pixel level drawing
[This example (rainbow.py)](https://johnedchristensen.github.io/diver/src/?filename=rainbow.py) shows some basic usage. It specifies each pixel on the canvas, so you can draw anything you want directly this way. It isn't very performant this way, so the resolution needs to be pretty low to run smoothly.


### Best of both worlds (for me)
#### 2D Canvas API

A more user friendly API is planned that will have better documentation integration to make it easier to find what functions are available straight from the editor.
[This example (squares.py)](https://johnedchristensen.github.io/diver/src/?filename=squares.py) draws to canvas using the JavaScript canvas API. This is much more performant than drawing pixel by pixel, and can run at higher resolutions/frame rates. To use this mode you'll need to know (or learn) how to use the [canvas API](https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API)


## Limitations
Expand Down
File renamed without changes.
72 changes: 53 additions & 19 deletions examples/helper_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ class SketchConfig(TypedDict, total=False):

@dataclass
class Sketch(pSketch):
# processo seems to not refresh self.window_width and height well
def debug_screen(self, desc):
print(f"{desc:20},js :{window.innerWidth:4},{window.innerHeight:4}")
print(f"{desc:20},p5 window:{self.window_width:4},{self.window_height:4}")
print(f"{desc:20},p5 canvas:{self.width:4},{self.height:4}")

def __init__(self, **options: Unpack[SketchConfig]):
super().__init__()
self.margin = options.get("margin", 50)
Expand All @@ -36,6 +30,12 @@ def __init__(self, **options: Unpack[SketchConfig]):

self._update_system_variables()

# processo seems to not refresh self.window_width and height well
def debug_screen(self, desc):
print(f"{desc:20},js :{window.innerWidth:4},{window.innerHeight:4}")
print(f"{desc:20},p5 window:{self.window_width:4},{self.window_height:4}")
print(f"{desc:20},p5 canvas:{self.width:4},{self.height:4}")

def square_draw_area(self):
"""set the width and height as large as possible while still square"""
figure_width = window.innerWidth - 2 * self.margin
Expand Down Expand Up @@ -68,6 +68,26 @@ def setup_screen(self):
self.translate(self.width // 2, self.height // 2)
self.scale(1, -1)

#
def text(
self,
txt: str,
x: float,
y: float,
x2: float | None = None,
y2: float | None = None,
) -> None:
"""Override p5js text to handle flipping y axis for text"""
self.push()
if self.origin == Origin.CENTER:
self.scale(1, -1)
y = -y
if y2 is not None:
y2 = -y2
pSketch.text(self, txt, x, y, x2, y2)
self.pop()
return

def diver_setup(self):
self.setup_screen()
self.user_setup()
Expand All @@ -93,48 +113,62 @@ def setup():

def draw():
p5.clear()
p5.push()

# grid lines
num_ticks = 20
# don't let tick's get too small

tick_size = p5.figure_width // num_ticks
major_tick_freq = 5

# start at 0, to make sure the grid goes through zero
for i, x in enumerate(range(0, p5.screen_right, tick_size)):
for i, y in enumerate(range(0, p5.screen_right, tick_size)):
if i % major_tick_freq == 0:
p5.stroke("lightgrey")
else:
p5.stroke("grey")
p5.line(x, p5.screen_top, x, p5.screen_bottom)
p5.line(-x, p5.screen_top, -x, p5.screen_bottom)
p5.line(y, p5.screen_top, y, p5.screen_bottom)
p5.line(-y, p5.screen_top, -y, p5.screen_bottom)

for i, x in enumerate(range(0, p5.screen_right, tick_size)):
for i, y in enumerate(range(0, p5.screen_top, tick_size)):
if i % major_tick_freq == 0:
p5.stroke("lightgrey")
else:
p5.stroke("grey")
p5.line(p5.screen_left, x, p5.screen_right, x)
p5.line(p5.screen_left, -x, p5.screen_right, -x)
p5.line(p5.screen_left, y, p5.screen_right, y)
p5.line(p5.screen_left, -y, p5.screen_right, -y)

# Axis
p5.stroke("white")
p5.line(0, p5.screen_top, 0, p5.screen_bottom)
p5.line(p5.screen_left, 0, p5.screen_right, 0)

# Big circle
p5.stroke_weight(2)
t = p5.millis() / 2000
r = sin(t) * p5.figure_width // 2
p5.fill("blue")
p5.circle(0, 0, 2 * r)
p5.scale(1, -1)
p5.fill("white")
p5.text_size(tick_size)
p5.text(f"{(r / tick_size):.1f}", r, 0)
p5.text(f"{(r / tick_size):.1f}", 0, r)

# moving labels

p5.text_size(tick_size * 2)
p5.text_descent

p5.stroke("black")
p5.fill("red")
p5.circle(0, r, tick_size / 4)
p5.fill("green")
p5.text(f"{(r / tick_size):.1f}", r, 0)
p5.no_stroke()
p5.circle(r, 0, tick_size / 4)

p5.stroke("black")
p5.fill("green")
p5.text(f"{(r / tick_size):.1f}", 0, r)
p5.no_stroke()
p5.circle(0, r, tick_size / 4)

p5.pop()


p5.start(setup, draw)
8 changes: 0 additions & 8 deletions examples/p5js.pyi

This file was deleted.

25 changes: 25 additions & 0 deletions examples/processo_figure_8.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# from https://proceso.cc/examples/creative_coding/
from proceso import Sketch


p5 = Sketch()
p5.describe("A purple circle moving in a figure eight on a light blue background.")


def setup():
p5.create_canvas(400, 400)
p5.background("dodgerblue")


def draw():
p5.translate(p5.width * 0.5, p5.height * 0.5)
x = 80 * p5.cos(0.1 * p5.frame_count)
y = 40 * p5.sin(0.2 * p5.frame_count)
p5.stroke("white")
p5.fill("orchid")
p5.circle(x, y, 20)
if p5.is_mouse_pressed:
p5.background("dodgerblue")


p5.run_sketch(setup=setup, draw=draw)
29 changes: 29 additions & 0 deletions examples/processo_simple_shapes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# from https://proceso.cc/examples/creative_coding/simple_shapes
# originally adapted from https://p5js.org/examples/hello-p5-simple-shapes.html
from proceso import Sketch


p5 = Sketch()
p5.describe("A rectangle, circle, triangle, and flower drawn in pink on a gray background.")

# Create the canvas
p5.create_canvas(720, 400)
p5.background(200)

# Set colors
p5.fill(204, 101, 192, 127)
p5.stroke(127, 63, 120)

# A rectangle
p5.rect(40, 120, 120, 40)
# A circle
p5.circle(240, 240, 80)
# A triangle
p5.triangle(300, 100, 320, 100, 310, 80)

# A design for a simple flower
p5.translate(580, 200)
p5.no_stroke()
for _ in range(10):
p5.ellipse(0, 30, 20, 80)
p5.rotate(p5.PI / 5)
8 changes: 8 additions & 0 deletions examples/string.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,12 @@ def onMouseUp(_: MouseEvent):
onMouseMove_proxy = create_proxy(onMouseMove)
onMouseUp_proxy = create_proxy(onMouseUp)

text = document.getElementById("simulation-description")
if text is None:
text = document.createElement("div")
text.id = "simulation-description"
text.textContent = "Click and drag string up/down"
document.body.appendChild(text) # type: ignore


cm.canvas.addEventListener("mousedown", create_proxy(onMouseDown))

0 comments on commit 568aca0

Please sign in to comment.