#Patterns for interfacing with event based JS

1 messages · Page 1 of 1 (latest)

jolly spruce
#

Hi lucyhappy friends!

I am pretty new to functional programming so please be kind ❤️

I've been playing around with p5.js and the Javascript interop that Gleam provides with @external and I've managed to get some pretty cool things running with an API that looks (probably incorrectly) very similar to the p5.js API:

pub fn gleam_draw(sketch: p5.P5) -> p5.P5 {
  let y = 205

  let setup_sketch = fn(sketch: p5.P5) -> p5.P5 {
    p5.create_canvas(sketch, 700, 410)
    p5.framerate(sketch, 10.0)
  }

  let draw_sketch = fn(sketch: p5.P5) -> p5.P5 {
    sketch
    |> p5.background(150)
    |> p5.ellipse(500, y, 50, 50)
  }

  sketch
  |> p5.setup(setup_sketch)
  |> p5.draw(draw_sketch)
}

However, I'm really having a hard time when it comes to animations. In p5.js you would typically use mutable values for things such as y like in the example above. As an example you might have something that looks like:

pub fn gleam_draw(sketch: p5.P5) -> p5.P5 {
  let y = 205
...
  let draw_sketch = fn(sketch: p5.P5) -> p5.P5 {
    y += 1 // invalid, because no mutability
    sketch
    |> p5.background(150)
    |> p5.ellipse(500, y, 50, 50)
  }
...
}

Where I am really struggling is trying to figure out how I can get p5.js to call the draw_sketch function as it would per frame. While keeping track of a changing value (such as y). Since I don't control the actual "loop" (because it comes from the js lib) is there a way I could implement this in pure Gleam?

Many thanks, ❤️

harsh swallow
#

You'll likely want to implement the TEA pattern or similar

#

See Lustre or Elm or Clojure's Quil's fun-mode for examples

#

Roughly it's splitting state updating from rendering, as they're two different things

#

You'd have a rendering function that renders, and an update function that updates the state on each event

#

Mimicing a mutable procedural API is going to result in getting stuck as you are now as they're designed for a different style of computation

#

Or you could use it 😁

jolly spruce
#

Aha! @hoary path has implemented a WorldState type to keep track of these things, very interesting! Thank you for the reference!

hoary path
#

Hey, happy to answer any questions you have on this but yeah the crux of it is an implementation of the patterns Louis described. Since p5js only provides procedural calls for rendering and expects mutation I ended up writing a wrapper that provides a more "functional" interface. So your world state update logic ends up being the normal fp/gleam style function applications and only the once per frame render/draw function actually deals with the procedural p5 "write pixels to screen" bits. The code in the examples should give you an idea of how that looks in practice

jolly spruce
#

Hey @harsh swallow and @hoary path ; You can mark this question in particular as solved now. I have successfully got my interop working appropriately 😄
Here's a rather boring still for you two to enjoy 😄

harsh swallow
#

I looooove computational art