ludus/turtle-graphics.md

5.8 KiB

Turtle Graphics protocol

name: "turtle-graphics"

version: 0.1.0

Description

Turtle graphics describe the movements and drawing behaviours of screen, robot, and print "turtles."

  • proto: ["turtle-graphics", "{version number}"]
  • data: an array of arrays; each array represents a turtle command; the first element of a command array is the verb; any subsequent items are the arguments to the verbs.
  • Valid arguments are numbers, strings, and booleans.
  • Depending on what we end up doing, we may add arrays of these, representing tuples or lists, and/or objects with string keys whose text are well-formed keywords in Ludus. For now, however, arguments must be atomic values.
  • E.g., ["forward", 100]
  • Each turtle has its own stream.
  • At current, this protocol describes the behaviour of turtle-like objects, all of which "live" in the same "world"; there is not yet a provision for multiple canvases/worlds. That said, an additional field for "world" in at the top level may well be added in the future to allow for multiple worlds to unfold at the same time.

Verbs and arguments

  • forward, steps: number
    • Moves the turtle forward by the number of steps/pixels.
  • back, steps: number
    • Moves the turtle backwards by the number of steps/pixels.
  • right, turns: number
    • Turns the turtle right by the number of turns. (1 turn = 360 degrees.)
  • left, turns: number
    • Turns the turtle to the left by the number of turns. (1 turn = 360 degrees.)
  • penup, no arguments
    • "Lifts" the turtle's pen, keeping it from drawing.
  • pendown, no arguments
    • "Lowers" the turtle's pen, starting it drawing a path.
  • pencolor, red: number, green: number, blue: number, alpha: number, OR: color: string
    • Sets the turtle's pen's color to the specified RGBA color.
  • penwidth, width: number
    • Sets the width of the turtle's pen, in pixels (or some other metric).
  • home, no arguments
    • Sends the turtle back to its starting point, with a heading of 0.
  • goto, x: number, y: number
    • Sends the turtle to the specified Cartesian coordinates, where the origin is the turtle's starting position.
  • setheading, heading: number
    • Sets the turtle's heading. 0 is the turtle's starting heading, with increasing numbers turning to the right.
  • show, no arguments
    • Shows the turtle.
  • hide, no arguments
    • Hides the turtle.
  • loadstate, x: number, y: number, heading: number, visible: boolean, pendown: boolean, width: number, color: string OR r: number, g: number, b: number, a: number
    • Loads a turtle state.
  • clear, no arguments
    • Erases any paths drawn and sets the background color to the default.
  • background, red: number, green: number, blue: number, alpha: number
    • Sets the background color to the specified RGBA color, OR: color: string

These last two feel a little weird to me, since the background color is more the property of the world the turtle is in, not the turtle itself. Worlds with multiple turtles will be set up so that any turtle will be able to change the background, and erase all paths.

That said, since we don't yet have a world abstraction/entity, then there's no other place to put them. This will likely be shifted around in later versions of the protocol.

Other considerations

Not all turtles will know how to do all these things. The idea is that this single abstraction will talk to all the turtle-like things we eventually use. That means that some turtles won't be able to do all the things; that's fine! They just won't do things they can't do; but warnings should go to stderr.

Errors are not passed back to Ludus. These are fire-off commands. Errors should be reported to stderr or equivalent. But Ludus sending things to its output streams should only cause Ludus panics when there's an issue in Ludus.

Colors aren't always RGBA. For pen-and-paper turtles, we don't have RGBA colors. Colors should also be specifiable with strings corresponding to CSS basic colors: black, silver, gray, white, maroon, red, purple, fuchsia, green, lime, olive, yellow, navy, blue, teal, and aqua.

Turtles should communicate states. Ludus should have access to turtle states. This is important for push/pop situations that we use for L-systems. There are two ways to do this: Ludus does its own bookkeeping for turtle states, or it has a way to get the state from a turtle.

The latter has the value of being instantaneous, and gives us an expected state of the turtle after the commands are all processed. In particular, this will be necessary for the recursive L-systems that require pushing and popping turtle state. The latter has the drawback of potentially allowing the turtle state and expected turtle state to fall out of synch.

The former has the value of always giving us the correct, actual state of the turtle. It has the drawback of requiring such state reporting to be asynchronous, and perhaps wildly asynchronous, as things like moving robots and plotters will take quite some time to actually draw what Ludus tells it to. (Being able to wait until eq? (expected, actual) to do anything else may well be extremely useful.)

That suggests, then, that both forms of turtle state are desirable and necessary. Thus: turtles should communicate states (and thus there ought to be a protocol for communicating state back to Ludus) and Ludus should always do the bookkeeping of calculating the expected state.

Turtles use Cartesian, rather than screen, coordinates. The starting position of the turtle is (0, 0), which is the origin, and centred in the field of view. Increasing the x-coordinate moves the turtle to the right; increasing the y-coordinate moves the turtle up.

Turtles use compass headings, not mathematical angles. Turtles start pointing vertially, at heading 0. Turning right increases the heading; pointing due "east" is 0.25; south 0.5, and west, 0.75.