Am I allowed to use PGraphics in html?

so i’m trying to embed some pdes in html and i’m running into trouble using the PGraphics buffer. it seems to be compiling and running, but it doesn’t actually draw my PGraphics canvas when i try to use image(). the console errors are really confusing. here’s my code so far

main.pde

int time;

void setup(){
  size(1024,512);
  noSmooth();
  
  background(255,0,0);
  
  time = 0;
  initGraphics();
}
void draw(){
  time ++;
  
  renderGame();
}

graphics.pde

color c_black = color(0,25,32);
color c_white = color(0,67,87);
color c_light = color(255,200,0);
color c_accent = color(179,51,124);

int[][] sand;

void initGraphics(){
  sand = new int[50][2];
  for(int i = 0;i < 50;i ++){
    sand[i][0]=floor(random(0,256));
    sand[i][1]=floor(random(0,90));
  }
}
  
void renderGame(){
  PGraphics canvas = createGraphics(256,128);
  canvas.beginDraw();
  canvas.noSmooth();
  
  canvas.background(c_black);
  
  for(int x = 0;x < 256;x ++){
    canvas.set(x,round(96+sin(x*0.2+time*0.1)+sin(x*-0.1+time*-0.2)+sin((x+time)*0.02)*3),c_white);
    canvas.set(x,round(96+sin(x*-0.2+time*-0.05)+sin(x*0.1+time*0.1)+sin((x+time)*0.02)*3),c_white);
  }
  
  for(int i = 0;i < 50;i ++){
    canvas.set(sand[i][0],sand[i][1],c_white);
  }
  
  canvas.endDraw();
  image(canvas,0,0,1024,512); //this is the line that should be doing something, but isn't
}

index.html

<!doctype html>
<html>
<head>
<meta charset="utf-8">
	<title>html game</title>
	<script type="text/javascript" src="processing.js"></script>
</head>

<body style="margin: 0px;">
	<canvas data-processing-sources="classes/main.pde classes/graphics.pde"></canvas>
</body>
</html>

the processing code works fine locally, but when i run it on a browser i only get the red background, so the image() line seems to not be working. or maybe the graphics.pde file isn’t being loaded at all? here’s the relevant console output

processing.js:4076  Uncaught TypeError: Cannot read properties of undefined (reading 'width')
    at getCanvasData (processing.js:6661:26)
    at Drawing2D.image (processing.js:7102:32)
    at renderGame (eval at attach (processing.js:10083:21), <anonymous>:58:6)
    at Processing.Processing.draw (eval at attach (processing.js:10083:21), <anonymous>:21:3)
    at Drawing2D.redraw (processing.js:4028:9)
    at processing.js:4072:13

UPDATE
okay it seems like it actually has something to do with the canvas.set() function. when i remove those it draws the canvas properly. am i not allowed to envoke set() in html? what am i meant to do instead?

I did some experiments and indeed method set() w/ a 3rd color parameter breaks PGraphics on Pjs.

However, set() w/ a 3rd PImage parameter signature still works:

Although slightly less performant, point() is a very valid replacement:

But for best performance, faster than both set() & point(), is directly manipulate pixels[]:

Here’s your sketch refactored to use pixels[] in place of set():


index.html:

<script defer src=https://Unpkg.com/processing-js></script>
<canvas data-processing-sources=Star_Waves.pde></canvas>

run.bat:

set /a port = %random% * 40000 / 32768 + 10000
start serve -l %port%
start http://localhost:%port%

Star_Waves.pde

/**
 * Star Waves (v1.1.4)
 * by canslp
 * mod GoToLoop (2023/Jul/07)
 *
 * Discourse.Processing.org/t/am-i-allowed-to-use-pgraphics-in-html/42375/2
 *
 * OpenProcessing.org/sketch/1968681
 */

static final color
  C_BLACK = #001920, 
  C_WHITE = #004357, 
  C_LIGHT = #FFC800, 
  C_ACCENT = #B3337C;

static final int
  STARS = 50, 
  W = 256, H = 128, 
  HH = H * 3 >> 2;

PGraphics pg;
PImage im;

boolean paused;

void setup() {
  size(640, 384);
  noSmooth();
  initGraphics();
}

void draw() {
  renderGame();
}

void mousePressed() {
  if (paused ^= true) noLoop();
  else                loop();
}

void initGraphics() {
  pg = createGraphics(W, H);

  pg.beginDraw();

  pg.noSmooth();
  pg.stroke(C_WHITE);

  pg.endDraw();

  im = createImage(W, HH - 10, RGB);

  for (int i = 0; i < im.pixels.length; im.pixels[i++] = C_BLACK);

  for (int i = 0; i < STARS; ++i)
    im.pixels[(int) random(im.pixels.length)] = C_WHITE;

  im.updatePixels();
}

void renderGame() {
  final int c = frameCount;

  pg.beginDraw();

  pg.background(C_BLACK);
  pg.set(0, 0, im);

  pg.endDraw();

  pg.loadPixels();

  for (int x = 0; x < W; ++x) {
    final int
      y1 = round(sin(.2*x + .1*c) + sin(-.1*x - .2*c) + 3*sin(.02*(x+c))), 
      y2 = round(sin(-.2*x - .05*c) + sin(.1*x + .1*c) + 3*sin(.02*(x+c))), 

      idx1 = (y1 + HH) * W + x, 
      idx2 = (y2 + HH) * W + x;

    pg.pixels[idx1] = C_WHITE;
    pg.pixels[idx2] = C_WHITE;
  }

  pg.updatePixels();

  image(pg, 0, 0, width, height);
}

1 Like