Turtle Graphics#

Adding new turtle functions#

A step-by-step guide using the makeTurtle() and drawGreenScreen() examples to add new turtle functions.

gturtle.py#

Method 1#

Use this for functions that don’t require to be called sequentially.

Import the corresponding typescript function.

from js import ggPx_drawGreenScreen

Define the python function.

def drawGreenScreen():
    '''
    draw a green rectangle that covers the entire canvas, for testing 
    '''
    ggPx_drawGreenScreen()
    print("green")

Method 2#

Use this for functions that involve animations or require to be called sequentially. This is the prefered way.

Define the python fucntion by utilizing the shared array buffer as follows.

def makeTurtle():
    '''
    spawns a new turtle sprite
    '''
    return defaultrunner.callback('turtle', data = [MAKE, 0])

To minimize mistakes later on add the MAKE variable to the global scope.

MAKE = 'make'

pyodideworker.ts#

Three things must be adjusted in this file.

First define a CallableFunction variable right at the top of the file.

let pxGgMakeTurtle: CallableFunction;

Secondly define the callback function and add a layer of abstraction.

const setMakeTurtleCallback = pyodideExpose(async function (
  extras: any,
  makeTurtle: any
) {
  pxGgMakeTurtle = makeTurtle;
  self.ggPx_makeTurtle = ggPx_makeTurtle;
});

function ggPx_makeTurtle(container: any) {
  pxGgMakeTurtle();
}

Lastly, ensure that this callback is exposed at the end.

Comlink.expose({
  runCode,
  initPyodideRunner,
  setDrawGreenScreenCallback,
  setMakeTurtleCallback,
});

pyodideStore.ts#

First add the function to the comlink proxy.

async function initTurtleCallbacks() {
    await taskClient.call(
      taskClient.workerProxy.setDrawGreenScreenCallback,
      Comlink.proxy(drawGreenScreen)
    );
    await taskClient.call(
      taskClient.workerProxy.setMakeTurtleCallback,
      Comlink.proxy(makeTurtle)
    );
}

Then create the callback.

  function makeTurtle() {
    if (!pixiHandler) {
      throw new PixiHandlerNotInstantiatedError("pixiHandler not instantiated");
    }
    return pixiHandler.makeTurtle();
  }

If you went with Method 2 for gturtle.py you must additionally add the corresponding variable to the global scope.

MAKE = "make";

Also add an additional swith statement to the handleTurtle() function.

 async function handleTurtle(params: unknown, buffer: SharedArrayBuffer) {
    let promptObj = params as Object;
    if ("data" in promptObj) {
      let prompt = promptObj["data"];
      let promptArray = prompt as [string, number];
      switch (promptArray[0]) {
        case MAKE:
          makeTurtle();
          break;
        default:
          break;
      }
    }
  }

index.d.ts#

To prevent any typing mistakes add the PixiCallbacks to the index.d.ts file.

declare global {
  interface Window {
    // Turtle PixiCallbacks
    ggPx_drawGreenScreen: any;
    ggPx_makeTurtle: any;
  }
}

Debugging#

For debugging puposes there currently is a function implemented called drawGreenScreen(). This can be called at the different steps of the pipeline to check for errors.