Desenhando com Python no Navegador
Bernardo Fontes
Ribeirão Preto / SP
25 de Outubro de 2019
## Programação Criativa
- Programar para a **expressão** ao invés de resolução de problemas
- A **experimentação** precedendo a funcionalidade ou assertividade
- Tem com música, vídeo, desenho, fotografia...
## Generative Art
- Objetos **criados com código**
- O **algoritmo como sistema autônomo** determina o comportamento da composição
- A pessoa controlando a máquina cria e programa os algoritmos e **controla sua randomicidade**
- Programação + **técnicas**
Saskia Freeke
Frederik Vanhoutte
## O que tem em comum?
- Todos usam [Processing](https://processing.org/)
## Processing
- Uma IDE que usa Java para servir como um **sketchbook**
- Ideal para estudantes e artistas visuais por conta de sua **API simples e versátil**
- Possui um **modo Python** ([Jython](http://www.jython.org/) por baixo dos panos)
## Um exemplo
```python
# Author: Berin
# Sketches repo: https://github.com/berinhard/sketches
from random import choice
WHITE = color(228, 228, 228, 200)
RED = color(228, 12, 10, 200)
BLACK = color(17, 17, 17)
def setup():
size(900, 900)
noFill()
background(BLACK)
def draw():
radius = random(20, 300)
x_positions = range(0, width, 20)
y_positions = range(0, height, 20)
x, y = choice(x_positions), choice(y_positions)
if random(1) < 0.5:
c = WHITE
else:
c = RED
stroke(c)
while radius > 20:
ellipse(x, y, radius, radius)
radius -= 20
if frameCount > 100:
noLoop()
```
## Incríve né!?
- Mas.....
## Problemas do Modo Python
- É necessário **ativá-lo manualmente** pela IDE do Processing
- Praticamente **preso à IDE** do Processing
- Não tem acesso as **libs Python instaladas no sistema**
- Ainda está no **Python 2.7**
- O Jython não possui **nenhum** roadmap para migrar pra Python 3
### Python 2.7 "acaba" em 2 meses
![clock](images/clock.gif)
Será que temos alternativas?
### 2 principais alternativas com limitações
- [Pesquisa](https://github.com/villares/Resources-for-teaching-programming/blob/master/README.md) do Alexandre Villares
- [p5py](https://github.com/p5py/p5)
- Python 3 puro
- Reescrita ainda incompleta
- API bastante diferente da API do Processing
- [BrythonIDE](https://esperanc.github.io/brythonide/) - Prof. Esperança - COPPE/UFRJ
- Roda no navegador
- Utiliza [Brython](https://brython.info/)
- Tem questões de performance
### Quem poderá nos ajudar?
![clock](images/chapolin.gif)
## Python + p5.js
[![clock](images/pyp5js.png)](https://berinhard.github.io/pyp5js/)
`$ pip install pyp5js`
`$ pyp5js serve`
## API Básica
```python
from pyp5js import *
from random import choice
colors = [
(235, 235, 0),
(235, 0, 235),
(0, 235, 235),
]
def setup():
createCanvas(900, 900)
background(27)
rectMode(CENTER)
def draw():
size = 20
for x in range(0, width + size, size): # itera por colunas
for y in range(0, height + size, size): # itera por linhas
fill(choice(colors)) # escolhe uma cor randomicamente
if random(1) > 0.5: # condição para desenhar um retângulo ou círculo
ellipse(x, y, size, size)
else:
rect(x, y, size, size)
noLoop()
```
### O que acontece embaixo dos panos?
- A interface web é uma abstração para a CLI
- A criação do sketch via form equivale ao comando `$ pyp5js new sketch_name`
- O diretório `~/sketchbook-pyp5js/sketch_name/` é criado com todo o código e arquivos necessários
- Ao acessar `/sketch/pybr_001/` a lib "compila" o código Python para código JS
- A compilação é através do comando `$ pyp5js transcrypt pybr_001`
- Dentro do diretório do sketch, os JS finais são colocados dentro do diretório `target`
## API de Eventos
```python
from pyp5js import *
from random import choice
shape_type = 'RECT'
shape_size = 30
live_shapes = []
def add_shape():
x, y = mouseX, mouseY
colors = [
(235, 235, 0),
(235, 0, 235),
(0, 235, 235),
]
live_shapes.append((
shape_type,
x,
y,
shape_size,
choice(colors))
)
def keyPressed():
global shape_type, shape_size
if key == 'c':
shape_type = 'CIRCLE'
elif key == 'r':
shape_type = 'RECT'
elif key == 'a':
shape_size += 5
elif key == 'x':
shape_size -= 5
def mouseClicked():
add_shape()
def mouseDragged():
add_shape()
def setup():
createCanvas(900, 900)
rectMode(CENTER)
def draw():
background(27)
for format, x, y, size, c in live_shapes:
noStroke()
fill(c)
if format == 'RECT':
rect(x, y, size, size)
elif format == 'CIRCLE':
ellipse(x, y, size, size)
x, y = mouseX, mouseY
noFill()
stroke(240)
if shape_type == 'RECT':
rect(x, y, shape_size, shape_size)
elif shape_type == 'CIRCLE':
ellipse(x, y, shape_size, shape_size)
```
## Manipulando o DOM
```python
from pyp5js import *
add_library("p5.dom.js")
rect_base_size = 30
positions = []
w_size, h_size = None, None
def setup():
global w_size, h_size
createP("Hi! This is an example of how to use p5.dom.js with pyp5js")
# creates a container div
slider_div = createDiv()
slider_div.style("display", "block")
# creates the sliders
w_size = createSlider(0, 600, 100)
w_size.style('width', '50%')
h_size = createSlider(0, 600, 100)
h_size.style('width', '50%')
# adds the slider to the container div
slider_div.child(h_size)
slider_div.child(w_size)
createCanvas(600, 600)
# fixes initial grid positions
for x in range(-rect_base_size, width + rect_base_size, rect_base_size):
for y in range(-rect_base_size, height + rect_base_size, rect_base_size):
positions.append((x, y))
noFill()
strokeWeight(2)
rectMode(CENTER)
def draw():
background(255)
for x, y in positions:
rect(x, y, w_size.value(), h_size.value())
```
## Mas nem tudo são flores...
![](images/chapolin_2.gif)
- No fundo, estamos usando JS e isso traz algumas questões
- As vezes o uso de memória não é otimizado
- Não ter toda a standard lib do Python
- Algumas [outras diferenças](https://transcrypt.org/docs/html/differences_cpython.html) do CPython
## Já vivemos no futuro
![](images/astucia.gif)
- [Pyodide](https://github.com/iodide-project/pyodide): The Python scientific stack, compiled to [WebAssembly](https://webassembly.org/)
- Já existe uma [issue aberta](https://github.com/berinhard/pyp5js/issues/73) para migrar o pyp5js
## Call to Action!
- Usem, quebrem, desmontem o `pyp5js`
- Ajudem a melhorar a documentação
- Criem novos exemplos e abram PRs com eles
- Estarei presente nos Sprints
No Garoa (São Paulo) toda última terça-feira do mês
Em Recife toda última quarta-feira do mês