Animation not visible after converting code to typescript

Hello,
I took an example from codingtrain and rewrote it to typescritpt. Unfortunately, it does not show any animation in the browser. Here is the code:

src/sketch.ts:

import 'p5';
import { Bubble } from "./Bubble";

let sketch = (p: p5) => {
  let bubble1;
  let bubble2;

  p.setup = () => {
    p.createCanvas(600, 400);
    bubble1 = new Bubble(200, 200, 40);
    bubble2 = new Bubble(400, 200, 20);
  }

  p.draw = () => {
    p.background(0);
    bubble1.move(p);
    bubble1.show(p);
    bubble2.move(p);
    bubble2.show(p);
  }

}

var sketchP = new p5(sketch);

src/Bubble.ts:

export class Bubble {

  constructor(
    public x: number,
    public y: number,
    public r: number) {

  }

  move(p: p5) {
    this.x = this.x + p.random(-5, 5);
    this.y = this.y + p.random(-5, 5);
  }

  show(p: p5) {
    p.stroke(255);
    p.strokeWeight(4);
    p.noFill();
    p.ellipse(this.x, this.y, this.r * 2);
  }
}

fuse.js:

const {FuseBox, WebIndexPlugin} = require('fuse-box');

const fuse = FuseBox.init({
  homeDir: 'src',
  output: 'dist/$name.js',
  sourceMaps: true,
  globals: { "p5": "p5" },
  plugins: [
      WebIndexPlugin(),
  ]
});

fuse.dev({open : true});

fuse.bundle('app')
  .instructions('> sketch.ts +p5')
  .hmr({reload: true})
  .watch()

fuse.run();

package.json:

{
  "name": "p5-typescript-starter",
  "version": "1.0.1",
  "description": "Project to quickly get something working in [p5.js](https://p5js.org/) and [typescript](https://www.typescriptlang.org/)",
  "scripts": {
    "compile": "tsc",
    "sketch": "node fuse.js"
  },
  "homepage": "https://github.com/mictadlo/p5-typescript-fuse-box-starter",
  "repository": {
    "type": "git",
    "url": "git@github.com:mictadlo/p5-typescript-fuse-box-starter.git"
  },
  "dependencies": {
    "p5": "^0.6.1"
  },
  "devDependencies": {
    "@types/node": "^10.1.3",
    "fuse-box": "^3.2.2",
    "typescript": "^2.8.3",
    "uglify-es": "^3.3.9",
    "uglify-js": "^3.3.27"
  }
}

What did I miss?

Thank you in advance.

Michal

If you’ve got a runnable code already, why haven’t you posted or linked to it yet?! :roll_eyes:

My guess the error lies in these 2 statements: p.setup = () => { & p.draw = () => {

You’re attaching 2 methods to an instance of class p5 on those statements.

However, you’re using the fat arrow lambda structure: () =>. :cold_sweat:

We shouldn’t use fat arrow lambdas when creating methods, b/c they permanently binds its this at creation time to the current this.

In this case, that this is the global window, not the sketch’s parameter p, which holds the instance of class p5 created by new p5(sketch);! :skull_and_crossbones:

In order to fix that bug, replace lambda () => w/ vanilla function () for both p.setup = & p.draw = . :face_with_monocle:

P.S.: Maybe my guess about blaming the fat arrow lambda expression is misguided… :face_with_hand_over_mouth:

Due to the fact the keyword this is never actually used inside both your setup() & draw() methods, it doesn’t matter which object it points to. :flushed:

Therefore, I dunno whether there’s an actual bug in your sketch or perhaps there’s some incompatibility between p5js and your FuseBox, which I dunno anything about btW! :robot:

1 Like

Some tips for your class Bubble: :sunglasses:

  • Rather than requesting the p5 instance as a parameter for its methods move() & show() all the time, why not request it once at Bubble’s constructor(), and store it as 1 of its properties? :innocent:

  • And rather than a trio of singled props x, y & r, you can replace them all w/ an instance of p5.Vector: :money_mouth_face:
    https://p5js.org/reference/#/p5/createVector

export class Bubble {
  constructor(public p: p5, public v: p5.Vector) { }

  move() {
    this.v.add(this.p.random(-5, 5), this.p.random(-5, 5));
  }

  show() {
    this.p.ellipse(this.v.x, this.v.y, this.v.z << 1);
  }
}
1 Like

Here’s some p5js sketch written in TS: :cowboy_hat_face:
https://GoSubRoutine.GitHub.io/Ball-in-the-Chamber/instance/
https://github.com/GoSubRoutine/Ball-in-the-Chamber/tree/master/instance

1 Like

Thank you and you were right about big fat lamda. After I remove p from move and show of p.draw which led that the animation stop to work again.

src/sketch.ts:

import 'p5';
import { Bubble } from "./Bubble";

let sketch = (p: p5) => {
  let bubble1;
  let bubble2;

  p.setup = function() {
    p.createCanvas(600, 400);
    bubble1 = new Bubble(p, new p5.Vector(200, 200, 40));
    bubble2 = new Bubble(p, new p5.Vector(400, 200, 20));
  }

  p.draw = function() {
    p.background(0);
    bubble1.move();
    bubble1.show();
    bubble2.move();
    bubble2.show();
  }

}

var sketchP = new p5(sketch);

src/Bubble.ts

export class Bubble {

  constructor(public p: p5, public v: p5.Vector) { }

  move() {
    this.v.add(this.p.random(-5, 5), this.p.random(-5, 5));
  }

  show() {
    this.p.stroke(255);
    this.p.strokeWeight(4);
    this.p.noFill();
    this.p.ellipse(this.v.x, this.v.y, this.v.z << 1);
  }
}

What did I miss?

Thank you in advance.

Michal

Solution is to change p to this in bubble1 = new Bubble(this, new p5.Vector(200, 200, 40));

AFAIK, inside setup(), the parameter p should be equal to this. :thinking:

When I’ve tipped you about using p5.Vector in place of those 3 properties, I’ve given you a link to method p5::createVector(), which acts as builder for that class btW. :face_with_monocle:

As soon as I replaced p with this I got Uncaught TypeError: Cannot read property 'background' of undefined. Please find below the updated code:

import 'p5';
import { Bubble } from "./Bubble";

let sketch = (p: p5) => {
  let bubble1;
  let bubble2;

  p.setup = function() {
    this.createCanvas(600, 400);
    bubble1 = new Bubble(this, this.createVector(200, 200, 40));
    bubble2 = new Bubble(this, this.createVector(400, 200, 20));
  }

  p.draw = function() {
    this.background(0);
    bubble1.move();
    bubble1.show();
    bubble2.move();
    bubble2.show();
  }

}

var sketchP = new p5(sketch);

What did I miss?

Thank you in advance.

Michal

  • I’ve mentioned that p is equal to this in setup():roll_eyes:
  • However, b/c p5js is fulla inconsistencies, it seems draw() is the only exception. :poop:
  • So, if we prefer to use this in place of p inside draw(), we’re gonna need to bind() it to p: :face_with_head_bandage:
p.draw = function () {
  this.background(0);

  // blah, blah, blah...
}.bind(p);
  • Just like I did to my own draw() here: :smile_cat:

Thank you. it works.