Visual live-coding proof-of-concept

maia_tae

Maia Taewana

Posted on February 27, 2021

Visual live-coding proof-of-concept

This is a proof-of-concept for the API.

The goals for this tiny visual live-coding library is to:

  1. Avoid bundlers.
  2. Native JS module (dynamic "import").
  3. No runtime overhead.

Here is the current experiment:

Alt Text

Concepts

In order to achieve the zero overhead goal, to link between connected "blocks" in the render-tree, we need:

  1. A context propagation phase going from top to bottom.
  2. A linking phase returning children update functions from bottom to top.
  3. A call or update phase with the result.

Render tree

Here is the tree for this example:

[ main ]
[ anim.Loop ]
[ three.WebGLRenderer ]
[ three.Scene ]
[ three.Mesh -----------------------------------]
[ three.Rotation.x ] [ three.Rotation.y ] [ ... ]
[ time.Now ]         [ time.Now ]         [ ... ]
Enter fullscreen mode Exit fullscreen mode

three.Mesh

import { Context, Node } from './context'

// Context phase (1)
// The 'object3D' received here is the three.Scene
export function init({ THREE, object3D, cache, detached }: Context): Node {
  const mesh = cache('object3D', () => {
    const dim = 1
    const geometry = new THREE.BoxGeometry(dim, dim, dim)
    const material = new THREE.MeshPhongMaterial({
      color: 0x156289,
      emissive: 0x072534,
      side: THREE.DoubleSide,
      flatShading: true,
    })

    const mesh = new THREE.Mesh(geometry, material)
    object3D.add(mesh)
    return mesh
  })

  if (detached) {
    if (mesh.parent) {
      mesh.parent.remove(mesh)
    }
  }
  // Context update. Now 'object3D' for children is the
  // cube mesh.
  return { object3D: mesh }
}
Enter fullscreen mode Exit fullscreen mode

three.Rotate.x

import { Context, Node } from './context'

// Context phase (1)
// The 'object3D' object is the cube from three.Mesh
export function init({ object3D, detached }: Context): Node {
  const rotation = object3D.rotation
  rotation.x = 0
  if (detached) {
    return {}
  }

  return {
    // Link phase (2)
    // Arguments are the linked children.
    link({ number: rotateX }) {
      const x = rotateX || () => 0
      return {
        // Update phase (3)
        update() {
          rotation.x = x()
        },
      }
    },
  }
}
Enter fullscreen mode Exit fullscreen mode

time.Now

import { Context, Node } from './context'

// Context phase (1)
// Receives the "time" object from anim.Loop far up
// in the tree.
export function init({ time }: Context): Node {
  return {
    // Link phase (2)
    // Does not have children
    link: () => ({
      // Update phase (3)
      // Returns a number. This is the function called by
      // three.Rotation.x on update.
      number: () => time.now,
    }),
  }
}
Enter fullscreen mode Exit fullscreen mode

Full code on github: https://github.com/tuist-org/tuist

If you read this far, please leave a comment :-)

💖 💪 🙅 🚩
maia_tae
Maia Taewana

Posted on February 27, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Visual live-coding proof-of-concept
livecoding Visual live-coding proof-of-concept

February 27, 2021