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
            
            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?
            
        
        
            ## Python + p5.js
            [](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...
            
            - 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
            
            - [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