# Turtle Graphics

**URL:** <https://discourse.processing.org/t/turtle-graphics/45672>\
**Category:** p5.js\
**Created:** [January 27, 2025, 5:23pm UTC](https://discourse.processing.org/t/turtle-graphics/45672 "2025-01-27T17:23:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 27, 2025, 5:23pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/1 "2025-01-27T17:23:31Z")

</div>

I have been working on a library to perform Turtle Graphics with animation so the user can see the image being ‘developed’ rather than just the final result. Here are a few examples.

https://editor.p5js.org/quark-js/full/nzb0wOULjhttps://editor.p5js.org/quark-js/full/C1HSqSCjghttps://editor.p5js.org/quark-js/full/rkNqcc-zw

These sketches have been embedded from the [p5js Web Editor](https://editor.p5js.org/quark-js/sketches). The first two are looped but you can use the keyboard to pause the animation and change the turtle cursor in the last one.

I have created a detailed user guide explaining the library API that can see at  
[http://www.lagers.org.uk/tg/guide/guide.html](http://www.lagers.org.uk/tg/guide/guide.html)

The library repository can be found on [github](https://github.com/quarks/turtle-graphics). I will be publishing more information and further examples on github and the web editor.

If you create any interesting graphics with this library then post links here. I will be fascinated to see what you can do with it. 😄

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 27, 2025, 5:49pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/2 "2025-01-27T17:49:20Z")

</div>

It’s not intuitively obvious how to install this library so we can use it.

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 27, 2025, 6:04pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/3 "2025-01-27T18:04:48Z")

</div>

Sorry about that. I will be putting more information on github and “how to install the library” will be a priority but in the meantime the easiest way is to create a p5js Web Editor account (if you don’t have one already) and then save the example into your account. After that simply edit the code in `sketch.js` to do your own thing. The library (minified) is in the file `tg.min.js` located in the example.

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 27, 2025, 6:15pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/4 "2025-01-27T18:15:02Z")

</div>

> [@quark](#):
>
> save the example into your account

Sorry to be dense, but where’s the ‘example’? I found the library on github, _tg.min.js_; is there any way for me to directly install it?

**Addendum:**

I tried adding library directly to my sketch but got this:

 ![err](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/0/f0cb2bd02322b96d1d04969ba0ed5413a34d9536.png)

**Addendum2:**  
I forgot to hook it up in index.html.

```auto
    <script src="sketch.js"></script>
    <script src="tg.min.js"></script>

```

After doing that I now get this:

 ![err2](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/f/2/f2d270ded23bf34f816cfbb5d20829b447de6b09.png)

Looks like p5.js got to Arrow first: [ARROW](https://p5js.org/reference/p5/ARROW/)  
Maybe change it to ‘Arrw’?

**Addedum3:**  
If I ‘fix’ ARROW then I got a problem with SQUARE and ROUND

> **[SQUARE](https://p5js.org/reference/p5/SQUARE/)**
>
> SQUARE

After I ‘fix’ both of those I’m still left with this:  
 ![TG](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/c/d/cd034b94d8c71148c760233281fcf5fff6b7c842.png)

And I don’t know how to get around that one.

---

<div class="post-metadata">

**Author:** ![davepagurek](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/davepagurek/32/17535_2.png) [@davepagurek](https://discourse.processing.org/u/davepagurek)\
**Post date:** [January 27, 2025, 9:07pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/5 "2025-01-27T21:07:42Z")

</div>

Maybe try loading the addon script tag above your sketch script tag? Otherwise your sketch is trying to access the addon’s code before it has been loaded.

@quark: any interest in adding your addon to the list of community addons on [p5js.org](http://p5js.org)? [Libraries](https://p5js.org/libraries/directory/)

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 27, 2025, 9:43pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/6 "2025-01-27T21:43:44Z")

</div>

> [@davepagurek](#):
>
> Maybe try loading the addon script tag above your sketch script tag?

Good idea; no more errors.

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 27, 2025, 10:07pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/7 "2025-01-27T22:07:19Z")

</div>

> [@svan](#):
>
> ```auto
> <script src="sketch.js"></script>
> <script src="tg.min.js"></script>
> 
> ```

Yes switch these round. Always load the library before the sketch that uses it.

TG ‘hides’ the p5js reference to ARROW but this is a warning so will not stop the library from working. Since I am using instance mode you can use `p.ARROW` to access the p5js ARROW variable whereas `ARROW` accesses the TG arrow cursor.

> [@davepagurek](#):
>
> any interest in adding your addon to the list of community addons

Yes but I still have a few things to do first

1. document the setup / installation process to enable using the library
2. more documentation on the basic syntax of using TG for the first time user
3. some simpler examples with p5js, probably using global mode. The examples here all use instance mode and some of the advanced features of the library, I created them to test different features of the library as I created it.
4. finally I need to create a hires image for the library when I submit it 😄 - for me that will be the hardest part LOL.

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 27, 2025, 10:14pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/8 "2025-01-27T22:14:36Z")

</div>

I’m unable to get the following to show any output. Did I leave something out?

```auto
let turtle = TG.getTurtle(400, 400);

function setup() {
  createCanvas(400, 400);
  background(220);
  turtle.pencolor("black");
  turtle.pensize(width = 2);
  turtle.turtle(DART);
  console.log(turtle);
}

function draw() {
  turtle.pd();
  turtle.forward(20).right(25).forward(55).start();
  turtle.showturtle();
}

```

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 27, 2025, 10:35pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/9 "2025-01-27T22:35:11Z")

</div>

Try this

```auto
let turtle = TG.getTurtle(400, 400);

function setup() {
  createCanvas(400, 400);
  turtle.pencolor("blue"); // balck is default so changed to blue
  turtle.turtle(DART); // could skip this because DART is the default
  turtle.xy(20, -180); // start the turtle near the top centre so we can see the whole graphic
  addTasks(turtle);
}

// Add some tasks to the turtle
function addTasks(t) {
  t.forward(20)
    .right(25)
    .forward(55)
    .start() // tell the turtle to start performing the tasks
    // showturtle() and st() do the same thing so I have used the shorter option
    .st()
    // Once these tasks ahve been completed the next line will add them
    // again. This will be repeated for ever since there is nothing to stop
    // the animation.
    .do(addTasks);
}

function draw() {
  background(220);
  // Draw the turtle graphic so its centre is at 200,200 on the screen
  turtle.draw(drawingContext, 200, 200);
}

```

Do not add tasks in the draw method because that is executed ~60 times per second so there is a risk means the tasks li

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 27, 2025, 10:57pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/10 "2025-01-27T22:57:29Z")

</div>

That works. Looks like you’re initially drawing offscreen and then need to bring it over to user’s canvas.  
**Output:**

 ![out](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/6/0/606bc842bf515fc519e1f1723d41fae4d8ead3e3.png)

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 28, 2025, 1:42am UTC](https://discourse.processing.org/t/turtle-graphics/45672/11 "2025-01-28T01:42:03Z")

</div>

One of the down sides to turtle graphics the way that we are using it is that the loop just keeps drawing. In the case of your demo the ‘DART’ never stops. That is not unique to your code but Natalie Freed’s example code published February 2013 had the same problem. The example starts out as a polygon and ‘morphs’ into a circle over time (see below). One way around this is to use noLoop() (Java mode) along with recursion so that the drawing routine iterates a certain number of times and then stops.

**Natalie Freed example, immediate and delayed:**  
Immediate output:

 ![nfi](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/1/b/1b1be86ff98c35e01deaf6cb916bd72f943a4469.png)

Delayed output:

 ![nfd](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/f/4f5c85acabc56389b92ebf70d7cf4bed97a44eb4.png)

**Quark Library Output Immediate vs. Delayed:**  
Immediate output (start of second pass):

 ![qi](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/b/c/bce86b1176f232a2d83c116466736b2eab3bb78f.png)

Delayed output:

 ![qd](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/0/9/09a628755d8ed50e0e3762b9beecd9c1c9d1486c.png)

**Alternate p5.js technique** based on Natalie Freed’s work which adds recursion with noLoop() to avoid over drawing (not all of drawing functions were added to this demo):

```auto
//https://gist.githubusercontent.com/nataliefreed/8483050/raw/9e3f1d0f44bcb0c872762e4b984358d375e7b5fa/turtle.pde

let loc;
let orientation;

function drawPolygon(sideLength, degrees, numSides) {
  if (numSides > 0) {
    numSides -= 1;
    forward(sideLength);
    left(radians(degrees));
    drawPolygon(sideLength, degrees, numSides);
  }
}

function setup() {
  createCanvas(400, 400);
  strokeWeight(3);
  loc = createVector(width / 2 + 100, height / 2 + 50);
  orientation = radians(90);
  noLoop();
}

function draw() {
  background(220);
  drawPolygon(100, 360 / 8, 8);
}

// Turtle Utility Functions by Natalie Freed
function forward(pixels) {
  start = loc;
  end = p5.Vector.add(loc, polar(pixels, orientation));
  line(start.x, start.y, end.x, end.y);
  loc = end;
}

//calculate new orientation
function left(theta) {
  orientation += theta;
}

//converts an angle and radius into a vector
//negative y for left handed coordinate system
function polar(r, theta) {
  return new p5.Vector(r * cos(theta), r * sin(-theta)); 
}

```

**Output:**

 ![nfpfjs](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/4/f/4f71d5c9dd854b375a66517722ba0d07befcc5a0.png)

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 28, 2025, 3:17am UTC](https://discourse.processing.org/t/turtle-graphics/45672/12 "2025-01-28T03:17:59Z")

</div>

> [@quark](#):
>
> Since I am using instance mode you can use `p.ARROW` to access the p5js ARROW variable whereas `ARROW` accesses the TG arrow cursor.

“Global Mode” is p5js’ standard; and therefore the absolute majority code using that mode, including p5js tutorials!

As a workaround, you could simply re-use p5js’ ARROW constant instead of defining your own.

Or rename it in order to avoid crashing w/ p5js’ ARROW.

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 28, 2025, 10:36am UTC](https://discourse.processing.org/t/turtle-graphics/45672/13 "2025-01-28T10:36:44Z")

</div>

> [@svan](#):
>
> One of the down sides to turtle graphics the way that we are using it is that the loop just keeps drawing. In the case of your demo the ‘DART’ never stops.

Not surprising since there is nothing in the code to stop the turtle. I have modified the sketch (see below) so the turtle stops after 10 seconds.

Using noLoop() to stop the turtle will not work as expected. In TG the turtle processes the tasks independently of drawing the graphic to the display. So although `noLoop()` halts the display is does not stop the turtle from updating itself behind the scenes. TG provides the `stop()` task which halts the turtle update but allows the draw method to loop.

> [@GoToLoop](#):
>
> As a workaround, you could simply re-use p5js’ ARROW constant instead of defining your own.
> 
> Or rename it in order to avoid crashing w/ p5js’ ARROW.

No need it seems that Processing can distiinguish between the two ARROWs. In the sketch below the turtle now uses its own ARROW cursor and we can change the sketch mouse cursor between the p5js ARROW and CROSS cursor with the `a` and `c` keys.

NOTE: TG is written in pure Javascript and is not dependent on any other library including p5js. I am using p5js because it provides a simple framework to create examples.

> [@GoToLoop](#):
>
> “Global Mode” is p5js’ standard; and therefore the absolute majority code using that mode, including p5js tutorials!

Good point I will change the examples to use global mode 😄

```javascript
let turtle = TG.getTurtle(400, 400);
const DURATION = 10000;

function setup() {
  createCanvas(400, 400);
  cursor(CROSS);
  turtle.pencolor("blue"); // balck is default so changed to blue
  turtle.turtle(ARROW); // could skip this because DART is the default
  turtle.xy(20, -180); // start the turtle near the top centre so we can see the whole graphic
  addTasks(turtle);
  console.log(millis());
}

// Add some tasks to the turtle
function addTasks(t) {
  if(millis() > DURATION){
    t.stop();
  }
  else {
  t.forward(20)
    .right(25)
    .forward(55)
    .start() // tell the turtle to start performing the tasks
    // showturtle() and st() do the same thing so I have used the shorter option
    .st()
    // Once these tasks ahve been completed the next line will add them
    // again. This will be repeated for ever since there is nothing to stop
    // the animation.
    .do(addTasks);
  }
}

function draw() {
  background(220);
  // Draw the turtle graphic so its centre is at 200,200 on the screen
  turtle.draw(drawingContext, 200, 200);
}

function keyTyped() {
  if (key == "a") cursor(ARROW);
  if (key == "c") cursor(CROSS);
}

```

---

<div class="post-metadata">

**Author:** ![GoToLoop](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/gotoloop/32/86_2.png) [@GoToLoop](https://discourse.processing.org/u/GoToLoop)\
**Post date:** [January 28, 2025, 10:50am UTC](https://discourse.processing.org/t/turtle-graphics/45672/14 "2025-01-28T10:50:36Z")

</div>

> [@quark](#):
>
> `let turtle = TG.getTurtle(400, 400);`

Just a little peeve of mine:

If we don’t intend a variable to be re-assigned later, prefer keyword `const` over `let` or `var`:  
`const turtle = TG.getTurtle(400, 400);`

JS’ keyword `const` is very similar to Java’s `final` btW. ☕

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 28, 2025, 12:01pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/15 "2025-01-28T12:01:45Z")

</div>

> [@GoToLoop](#):
>
> JS’ keyword `const` is very similar to Java’s `final` btW

Yes I know after all TG uses `const` 63 times 😁

> [@GoToLoop](#):
>
> If we don’t intend a variable to be re-assigned later, prefer keyword `const` over `let` or `var`:  
> `const turtle = TG.getTurtle(400, 400);`

I agree in principle but I am not the original author, my post was an edit of code posted by another.

BTW `let` should _always_ be used in preference to `var` where possible - a pet peeve of mine 😀

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 28, 2025, 12:26pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/16 "2025-01-28T12:26:32Z")

</div>

> [@quark](#):
>
> my post was an edit of code posted by another.

It’s a moot point, but the code came from _guide.html_:

 ![turtle](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/3X/7/d/7d031bca1bc3731f87b36c2140f9c3444160fc46.png)

If it’s really that critical the guide should be edited.

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 28, 2025, 12:48pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/17 "2025-01-28T12:48:28Z")

</div>

> [@svan](#):
>
> It’s a mute point, but the code came from _guide.html_:

Sorry about that, the code was mine so if anyone is at fault it was me. 😇

When and where to use `const` versus `let` is not important in this discussion or in these example sketches. The choice depends on the code context and is outside the scope of this discussion so we should leave it there.

I have taken onboard @GoToLoop’s point about instance mode and have changed the examples to use global mode.

---

<div class="post-metadata">

**Author:** ![svan](https://avatars.discourse-cdn.com/v4/letter/s/82dd89/32.png) [@svan](https://discourse.processing.org/u/svan)\
**Post date:** [January 28, 2025, 12:51pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/18 "2025-01-28T12:51:44Z")

</div>

I’m curious why you chose to use offscreen drawing vs. drawing directly on to the user’s canvas?

---

<div class="post-metadata">

**Author:** ![quark](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/quark/32/26_2.png) [@quark](https://discourse.processing.org/u/quark)\
**Post date:** [January 28, 2025, 3:51pm UTC](https://discourse.processing.org/t/turtle-graphics/45672/19 "2025-01-28T15:51:51Z")

</div>

In Processing and p5js one of the big choices is whether to use `background` inside the `draw()` function. If you are creating a single static image over a period of time then you can get away without `background`. I have seen some lovely images created over multiple frames because the background has not been erased.

The only problem with this it is restrictive especially when trying to do animation. The alternative is to use `background()` to clear the display but then recreate a new frame image from scratch.

If I did this in TG then I would have to redo all the turtle’s previous tasks before drawing the update. This is too much processing so what I do is store the results of every _completed_ task on an offscreen buffer then on each frame copy this to the main display. Tasks such as `forward(100)` that are only partly completed i.e. being animated are _ **then** _ drawn on the main screen.

The benefits are

1. it is a less CPU intensive algorithm
2. the turtle graphic can be positioned anywhere on the display and even be changed during program exhibition
3. makes it easier to manipulate multiple turtles independently
4. more compatible with other libraries that require the display to be cleared each frame. This is the case with all the libraries I have ever used.

---

<div class="post-metadata">

**Author:** ![glv](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/glv/32/18785_2.png) [@glv](https://discourse.processing.org/u/glv)\
**Post date:** [January 29, 2025, 1:10am UTC](https://discourse.processing.org/t/turtle-graphics/45672/20 "2025-01-29T01:10:32Z")

</div>

> [@svan](#):
>
> **Alternate p5.js technique** based on Natalie Freed’s work which adds recursion

This recursion:

> [@svan](#):
>
> ```auto
> function drawPolygon(sideLength, degrees, numSides) {
> if (numSides > 0) {
> numSides -= 1;
> forward(sideLength);
> left(radians(degrees));
> drawPolygon(sideLength, degrees, numSides);
> }
> }
> 
> ```

Can be replaced with a simple _for() loop_:

```auto
function drawPolygon(sideLength, degrees, numSides) 
  {
  for(let i = 0; i<numSides; i++) 
    {
    forward(sideLength);
    left(radians(degrees));
    }
  }

```

`:)`

[Next page](https://discourse.processing.org/t/turtle-graphics/45672.md?page=2)
