Solar System Simulation

This Solar System simulation features the ability to add orbiting moons to the planets, a few of which are already defined. It is not entirely to scale (the planets are larger than they are in reality).

Use the scrollwheel or finger-scroll to zoom in and out, and drag the mouse to rotate around the sun!

TO solarsystem
  
  reset
  penup
  hideturtle
  
  cam:pullin 100
  ;pull in the camera turtle
  
  ;---------------------------------
  ;make a starfield in the distance:
  ;---------------------------------
  
  setfillcolor 5
  repeat 200 [
    home randomvectors
    forward 2500 + random 100
    up 90
    spot 1 + random 5
  ]
  
  ;---------------------------------
  ;define planetary parameter lists:
  ;---------------------------------
  
  make "distance [0 39 72 100 152 520 953 1918 3006 3953]
  ;the distance of the planets from the sun in 100ths of an AU
  ;The first value is the sun itself, which is at the home position
  
  make "size [100 3 7.5 7.9 4.2 88.7 74.6 32.6 30.2 1.41]
  ;the planets are in scale relative to each other but not the sun,
  ;which is much larger than the value we have given it here
  
  make "color [13 8 9 7 1 14 11 7 2 10]
  ;each planet's color (and the sun)
  
  make "tilt [0 7 3.3 0 1.85 1.31 2.49 0.77 1.77 17.14]
  ;ecliptical tilt
  
  make "speed [0 4.1 1.62 1 0.53 0.084 0.034 0.011 0.006 0.004]
  ;speed of orbit
  
  ;-------------
  ;define moons:
  ;-------------
  
  make "moon [0 0 0 1 2 0 0 0 0 0]
  ;how many moons?
  
  make "mooncolor [[][][][5][8 9][][][][][]]
  make "moondistance [[][][][3][2 3][][][][][]]
  make "moonsize [[][][][2.1][1.12 0.62][][][][][]]
  make "moontilt [[][][][0][1 2][][][][][]]
  make "moonspeed [[][][][30][40 30][][][][][]]
  ;moon parameters, similar to planets
  ;only earth and mars are populated here,
  ;add the others as you like!
  
  ;---------------------------
  ;create the sun and planets:
  ;---------------------------
  
  repeat 10 [
    home
    
    make "planet repcount
    ;store the current planet for use inside hatch
    
    newmodel repcount {"setfc item :planet :color "ico 0.1 * item :planet :size}
    ;create a new turtle model using the data from the :color and :size lists
    ;we use a 'soft list' {} to create 'hard data' for use by newmodel
    ;as the turtle model is rendered each frame
    
    hatch [
      ;create a new hatchling
      
      setmodel :planet
      ;set the turtle model
      
      penup
      dropanchor
      ;set the orbit (anchor) point to the current position
      
      pullout 0.5 * item :planet :distance
      ;pull away from the anchor the distance specified in the :distance list
      
      orbitright random 360
      ;orbit around a random amount
      
      orbitup item :planet :tilt
      ;orbit up (tilt) the amount specified in the :tilt list
      
      showturtle
      ;hatchlings are not visible by default
      
      if 0 < item :planet :moon [ ;are there any moons? foreach "moon item :planet :mooncolor [ ;for each moon, let's create it the same way we did planets: make "moonnumber loopcount make "moonmodel word :planet loopcount newmodel :moonmodel {"setfc :moon "ico 0.1 * item :moonnumber item :planet :moonsize} make "parent turtle ;define the 'parent' turtle for use by the moon hatchling hatch [ ;hatch the moon setmodel :moonmodel dropanchor right random 360 pullout item :moonnumber item :planet :moondistance orbitup item :moonnumber item :planet :moontilt showturtle forever [ fixate query :parent [position] ;keep 'fixated' (look at and set the anchor point to) ;the parent turtle's position. if orbitdistance > item :moonnumber item :planet :moondistance [
                pullin orbitdistance - (item :moonnumber item :planet :moondistance)
              ]
              ;if it's getting away from us, try and catch up!
              
              orbitright 0.1 * item :moonnumber item :planet :moonspeed
              ;orbit the planet based on the :moonspeed
              
              sleep 6.25
              ;take a little nap
            ]
          ]
        ]
      ]
      forever [
        orbitright 0.05 * item :planet :speed
        sleep 25
      ]
      ;orbit the sun (we're back to the planet now) based on the value
      ;from the :speed list. Then take a little nap (wait 1)
      
    ]
  ]
  hideturtle
  ;hide Myrtle, although she would be sitting in the sun
  
END

One-a-Day: Space Tube Ride using TUBE and TUBEARC

Myrtle creates a 3D space tube ride for her to fly through…

Sometimes Myrtle needs to take a break and have a little fun! One of the things she can do is make a space tube and fly through it, using the TUBE and TUBEARC primitives:

TUBE makes a straight tube, and takes the parameters <radius> <depth> and <sides>. So, tube 20 10 10 makes a tube with a radius of 20 turtle units, a depth of 10 turtle units and 10 sides.

TUBEARC creates a curved tube, and takes the parameters <thickness> (the radius of the tube itself) <radius> (the radius of the arc itself) <sides> <totalsegments> and <arcsegments> – the last two are the total segments that would make up a complete torus, or donut, and the number of segments we actually want to create. So values of 20 and 10 will create a half-donut: tubearc 10 20 20 20 10

There are four procedures to our space tube program: createcourse, drawcourse, followcourse and spacetube.

createcourse generates the data that represents the tube’s course. It creates a course made up of 100 segments, represented by a word made up of a series of numbers between 0 and 4, where 0 represents a straight section of tube, and 1 to 4 represent four directions of turn. We use dountil to ensure we don’t repeat the same direction of turn more than once and end up looping back on ourself. Although, createcourse is not perfect and it is still possible for the course to cross over itself – but it’s a good thing tube walls aren’t solid!

drawcourse creates the graphical representation of the contents of the :course container we generated using createcourse. We use the twosided primitive to generate reflective “normals” on both sides of the shapes we generate from that point forward, and we use randfc to set a random ‘fill color’ or shape color for each segment as we create them.

We use foreach to step through each segment listed in the :course container, creating either a tube or a tubearc where appropriate.

While tubes are created directly under Myrtle, tubearcs are created around her, and so this means we need to do a bit of calisthenics to position the tubearcs where they need to go. Follow them through one command at a time to see how they work! We wait 2 / 60ths of a second between each segment creation so we can follow it.

followcourse causes Myrtle to fly through the created course, once again iterating through the :course container using foreach. fluid causes Myrtle to move forward smoothly, and to turn through the arcs we use a repeat. sleep is another form of wait, which takes milliseconds as a parameter instead of wait‘s 60ths of a second.

setpremodel allows us to ‘prepend’ commands to the turtle’s model, allowing us to make Myrtle look like she’s turning the appropriate way as she moves through the course.

Finally, spacetube puts it all together and is the procedure we execute to create the maze and fly through it. spacetube performs a reset, turns off the text layer, tells Snappy (the camera turtle) to pull away from Myrtle 1000 turtle units, tells Snappy to ‘follow’ Myrtle (turn to face her when she disappears from his view), then executes the createcourse procedure, the drawcourse procedure, sets the view (camera) turtle to Myrtle, turns Myrtle’s ‘light’ on (so we can see properly inside the tubes), turns Snappy’s light off, sets the camera ‘view point’ of Myrtle a bit up and behind her, and then executes followcourse.

TO spacetube
  reset
  fullscreen
  snappy:pullout 1000
  snappy:follow "myrtle
  createcourse
  drawcourse
  setview "myrtle
  setlight 1
  snappy:setlight 0
  setviewpoint [0 10 -30]
  followcourse
END

TO createcourse
  make "course empty
  make "last 5
  repeat 100 [
    
    dountil :last != :segment [make "segment random 5]
    
    make "course word :course :segment
    if :segment != 0 [make "last :segment]
  ]
END

TO drawcourse
  nofluid
  cs
  pu twosided
  foreach "segment :course [
    randfc
    if :segment = 0 [tube 50 200 20 lo 200]
    else [rt :segment * 90
      dn 90 rr 90 sl 100 tubearc 50 100 20 20 5 fd 100 rr 90 lt 180 + :segment * 90]
    wait 2
  ]
  home
END

TO followcourse
  dn 90
  fluid
  foreach "segment :course [
    if :segment = 0 [fd 200]
    if :segment = 1 [setpremodel [rt 22.5] repeat 90 [fd 1.75 rt 1 sleep 1] setpremodel []]
    if :segment = 2 [setpremodel [dn 22.5] repeat 90 [fd 1.75 dn 1 sleep 1] setpremodel []]
    if :segment = 3 [setpremodel [lt 22.5] repeat 90 [fd 1.75 lt 1 sleep 1] setpremodel []]
    if :segment = 4 [setpremodel [up 22.5] repeat 90 [fd 1.75 up 1 sleep 1] setpremodel []]
  ]
END

One-a-Day: Amiga Ball Bounce


The Commodore Amiga computer had a famous ‘bouncing ball’ demonstration program, a checkered bouncing ball. It was a bit different than this, but this is certainly reminiscent of it.

We love the Amiga demo so much that we created a special checkered ball primitive, AMIGABALL, and a second ‘oid’ primitive, AMIGABALLOID, which is used to create the ‘compressed’ ball.

Rather than turning the turtle into a ball (one method), this method ‘cleans’ the ‘turtle track’ after rendering each frame of the animation (which we wait for using the NEXTFRAME primitive).

The background voxel is actually an ‘inverted’ voxel, a voxel that is created using a negative size value. Due to the nature of OpenGL, only the insides of negative voxels are visible, which is why we can see inside it, and not see the face directly in front of us. Because we clean the ball each frame, we need to use a HATCHLING to create and hold the voxel in place. The hatchling just sleeps while the program runs.

The CAM: prefix directs the current view turtle (usually ‘Snappy’) to do things. You could also use SNAPPY: in this case but CAM: is shorter.

DOUNTIL PENCOLOR != FILLCOLOR [RANDFC] ensures that the ball has two different colors. The Amigaball(oid) uses both the pen and the fill colors in its construction, the only 3D primitive to do so.

To stop the ball from bouncing, press the Escape key.

TO bounce
  reset fs
  penup lower 120 slideright 120 fd 120
  
  hatch [randomfillcolor voxel -240 forever [wait 10]]
  ;create the cube, using a hatchling so it persists
  
  cam:run [oup 10 ra 5]
  
  home
  setspheroidaxis 1
  ;stretch the spheroid on the vertical, default is horizontal
  dn 90 rr 10
  randpc dountil pencolor != fillcolor [randfc]
  ;set random pen and fill colors
  
  forever [
    
    repeat 14 [
      amigaball 50 10 20
      setx xpos - 1 lo 4 lt 2
      nextframe clean
    ]
    ;move down
    
    repeat 11 [
      amigaballoid 50 10 20 1 - repcount / 20
      lo 2 lt 2 nextframe clean
    ]
    ;compress ball
    
    randpc dountil pencolor != fillcolor [randfc]
    ;change colors
    
    repeat 11 [
      amigaballoid 50 10 20 0.375 + repcount / 20
      ra 2 lt 2 nextframe clean
    ]
    ;expand ball
    
    repeat 28 [
      amigaball 50 10 20
      setx xpos + 1 ra 4 lt 2
      nextframe clean
    ]
    ;move up
    
    repeat 11 [
      amigaballoid 50 10 20 1 - repcount / 20
      ra 2 lt 2 nextframe clean
    ]
    ;compress ball
    
    randpc dountil pencolor != fillcolor [randfc]
    ;change colors
    
    repeat 11 [
      amigaballoid 50 10 20 0.375 + repcount / 20
      lo 2 lt 2 nextframe clean
    ]
    ;expand ball
    
    repeat 14 [
      amigaball 50 10 20 setx xpos - 1
      lo 4 lt 2 nextframe clean
    ]
    ;move back to center
  ]
END

 

 

One-a-Day: FRAG

The FRAG primitive creates a filled shape out of the current turtle position and her last two positions. For example:

FD 100 RT 90 FD 100 FRAG

will create a triangle.

While turtleSpaces has a variety of shape primitives, sometimes you need to create an arbitrary shape, and FRAG aids you in this.

Take this example, which draws a star:

TO star
  repeat 4 [
    forward 100
    right 170
    forward 86
    frag
    left 70
    forward 86
    right 170
    forward 100
    frag
    right 180
  ]

We can change the number of sides the star has by changing the number of repeats and fiddling with the values a bit:

TO star2
  repeat 5 [
    fd 100 rt 170
    fd 86 frag
    lt 88 fd 86
    rt 170 fd 100
    frag rt 180
  ]
END

First, let’s change our star procedures so they can take a :size parameter, like so:

TO star1 :size
  repeat 4 [
    fd 100 * :size
    rt 170
    fd 86 * :size
    frag
    lt 70
    fd 86 * :size
    rt 170
    fd 100 * :size
    frag
    rt 180
  ]
END

In this case, :size is a ratio, that is, 0.5 will make a star half the size, and 2 will make a star twice the size of the default.

You can change the color of the star using the SETFILLCOLOR primitive, or set a random fill color with RANDFC.

The following procedures create a sky full of stars:

TO star1 :size
  repeat 4 [
    fd 100 * :size
    rt 170
    fd 86 * :size
    frag
    lt 70
    fd 86 * :size
    rt 170
    fd 100 * :size
    frag
    rt 180
  ]
END

TO star2 :size
  repeat 5 [fd 100 * :size rt 170 fd 86 * :size frag lt 88 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star3 :size
  repeat 6 [fd 100 * :size rt 170 fd 86 * :size frag lt 100 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star4 :size
  repeat 7 [fd 100 * :size rt 170 fd 86 * :size frag lt 108.625 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO star5 :size
  repeat 8 [fd 100 * :size rt 170 fd 86 * :size frag lt 115 fd 86 * :size rt 170 fd 100 * :size frag rt 180]
END

TO stars
  reset cam:setposition [0 0 0]
  cam:fixate [0 0 0]
  cam:setviewpoint [0 0 0]
  cam:newworker [forever [up 0.1 lt 0.1 rr 0.1 wait 1]]
  repeat 200 [
    pu home randori fd 400 + random 1000 up 90
    lt random 60 pd randpc randfc randfs randps
    make "size (10 + random 90) / 100
    run {pick [star1 star2 star3 star4 star5] :size}
  ]
  
END

Type STARS and press Enter to see the stars!

FRAG’s sister, SHARD creates a three-dimensional FRAG with depth beneath it. This depth is supplied as a parameter, in turtle-units, eg. SHARD 5. Try replacing FRAG with SHARD 5 in one of your star procedures and see what happens! (You’ll need to drag the camera around to see the sides of the star)

Quick Play: Warped Logo Spirals

One of the best things about turtleSpaces is its capacity for discovery through play.

Today I was playing with spirals:

I started off by creating a simple spiral using the RARC primitive and a simple REPEAT loop. This loop uses REPCOUNT (the current repeat loop iteration) to define the radius of the arc, resulting in an ever-growing spiral.

I clicked and dragged on the window to rotate the camera around the spiral. But let’s make the spiral itself three-dimensional:

I’ve ‘warped’ the spiral by placing three rarcs inside of the repeat loop, along with a ROLLLEFT (rl) and a ROLLRIGHT (rr). With the twisting and turning, the turtle ends up roughly halfway around a somewhat distorted circle, which you can see if you type:

cs rarc 90 20 rr 90 rarc 90 20 rl 90 rarc 90 20

cs repeat 2 [rarc 90 20 rr 90 rarc 90 20 rl 90 rarc 90 20]

If we orbit the camera (by clicking and dragging) around our spiral, we can see just how warped it is!

What else can we do with it?

Whoa! What happened there? I added a dn (down) 10 to the end of the loop. Let’s take a look from another vantage point:

That’s pretty distorted. Let’s try a smaller value, say 2:

And what about 5?

What about down (dn) instead of up?

Okay, pretty neat. How about if at the end of each loop we also roll left (rl) a little?

Another angle:

Let’s play around with the values of down (dn) and rollleft (rl) a bit:

What if we do a right turn (rt) instead of a roll right (rr)?

And what if we add the roll back in?

Let’s play around with the values a bit:

All right, that’s enough from me! But you can play around with the different values and see what happens. That’s all part of the fun of turtleSpaces!

 

Make it Rain!

TO rain

  reset

  penup hideturtle
  fullscreen
  setbackgroundcolor blue setbackgroundshade 12
  make "count 0

  forever [

    inc "count
    setposition {-300 + random 600 300 -300 + random 600}
    make "size 0.25 + ((1 + random 20) / 20)
    
    begintag "teardrop
    setfillcolor pick [2 3 6 7 14]
    setfillshade -10 + random 20
    
    up 90
    cutsphere 10 * :size 20 20 1 13
    lower 4.5 * :size
    cone 8.9 * :size 18 * :size 20
    down 90
    ;raindrop
        
    endtag
    
    newmodel :count "teardrop
    clean
    
    hatch [
      setmodel :count
      showturtle
      make "speed (5 + random 10) / 10
      while ypos > -300 [
        back :speed rollright 0.25
      ]
    ]
    
    wait 5 + random 25
  ]

END

‘Snake’ written in turtleSpaces Logo

TO snake
  
    
  ;setup:
  
  reset
  ;empties (erases) all containers (variables),
  ;returns the turtles to their default positions,
  ;restores their states to defaults
  
  release
  ;sets all the turtles, except for the default ones
  ;(myrtle, snappy, libby) 'free' - erasing them
  
  penup
  ;don't draw
  
  setbackgroundcolor lightblue
  
  hideturtle
  ;don't show the executing turtle (typically myrtle)
  
  stealth
  ;don't show up in output from the near primitive
  
  noaudiowait
  ;don't delay when playing sounds (the default)
  
  print |Use keys J and K to turn snake, eat apples!|
  ;print instructions to the screen
  
  ;create the 'ground'
  setfillcolor brown
  setpos [-185 -115]
  lower 5
  quad 185 * 2 115 * 2
  
  make "score 0
  make "length 8
  ;the default snake length, in segments
  
  make "queue empty
  ;this snake implementation uses a push / pull queue
  ;to keep track of the snake's turns
  
  repeat :length [push "fd "queue]
  ;all segments start moving forward
  
  newmodel "ball [setfillcolor 12 icosphere 5]
  newmodel "head [setfillcolor 4 icosphere 6]
  newmodel "apple [setfillcolor red icosphere 4]
  ;create turtle models, where ball is a non-head segment
  
  ;create the turtles that make up the starting snake:
  repeat :length [
    nameturtle repcount
    ;create a new turtle
    ;each segment has the number of its segment as its name
    
    control repcount {"wrap "penup "back repcount "* 10 "showturtle}
    ;initialize the new turtle and move it into position
    ;{} denotes a 'softlist', a list whose contents are evaluated
    ;at execution
    
    control repcount [
      setbounds [-185 -115 185 115]
    ]
    ;sets the bounds used for wrapping. [] denotes a 'hardlist', a
    ;list whose contents are fixed and not evaluated
    
    if repcount = 1 [control 1 [setmodel "head]]
    ;if this is the first segment, give it the 'head' model
    else [control repcount [setmodel "ball]]
    ;otherwise, give it the 'ball' (segment) model
  ]
  
  ;set up the 'apple' turtle:
  nameturtle "apple
  control "apple [
    penup setmodel "apple showturtle
    
    dountil (count near position 5) = 1 [
      setpos {-180 + (10 * random 36) -100 + (10 * random 20)}
    ]
  ]
  ;set a random position until such times as the apple is not near
  ;any snake segments (turtles)
  
  ;leading parameters used in comparison operators (=, >, < etc)
  ;must be enclosed in {}'s if more than a single value or primitive
  ;because the parser evaluates right to left
  
  ;the main loop:
  
  forever [
    norender
    ;don't render while we shuffle the snake forward
    
    for {"i 1 :length} [
      make "move item :i :queue
      ;set the move variable to the :i item in the :queue
      
      switch "move
      case "fd [ask :i [forward 10]]
      case "rt [ask :i [right 90 forward 10]]
      case "lt [ask :i [left 90 forward 10]]
      ;switch / case statements execute instructions based on the
      ;contents of the container (variable) provided to switch
      
      ;ask creates a new worker that executes the commands using
      ;the specified turtle (the turtle named by :i)
      ;so, in this for loop we are iterating through the :queue,
      ;moving the turtle segments based on the item present in
      ;each space in the queue (fd, rt or lt)
    ]
    while workers != [] [sleep 1]
    ;sleep execution until the ask workers finish moving their
    ;turtles (the snake). This way, when we enable the render,
    ;we won't catch the snake mid-move.
    
    render
    ;enable rendering again
    
    wait 40 - :score
    ;wait units are 60ths of a second. The higher the score, the
    ;shorter the wait will be
    
    ;user control:
    if keyp [
      ;did the user press a key? If so, do this stuff:
      
      make "input readchar
      ;take the output from the readchar primitive and place it
      ;into the input container. keyp indicates if there is a character
      ;already in the keyboard buffer. If readchar is called when there
      ;is no character in the buffer, it waits.
      
      switch "input
      case "j [push "lt "queue]
      ;if the user pressed the j key, push lt to the front of the queue
      case "k [push "rt "queue]
      ;if the user pressed the k key, push rt to the front of the queue
      otherwise [push "fd "queue]
      ;if no case has been satisfied since switch (the user pressed a key
      ;other than j or k), push fd to the front of the queue
    ]
    else [push "fd "queue]
    ;similarly, if the user hasn't pressed any key, push fd to the front
    ;of the queue
    
    ignore dequeue "queue
    ;ignore (drop) the last value off the end of the :queue
    ;dequeue would ordinarily return this value, ignore sends it into
    ;the ether
    
    ;is there something occupying the same space as the head of the snake?
    if (count (near 1:position 5)) > 1 [
      ;near returns the names of the turtles within the specified distance (5)
      ;count returns the count of the number of turtles returned by near
      ;if there is more than one (the head itself), we will execute the following:
      
      if memberp "apple near 1:position 5 [
        ;is it an apple?
        
        playsound "chomp
        inc "score
        ;increment the value in the score container by one
        
        (print |Yum! Score:| :score)
        ;to pass more than the default number of parameters to a primitive, wrap
        ;it in parentheses (round brackets)
        
        dountil (count near apple:position 5) = 1 [
          control "apple [setpos {-180 + (10 * random 36) -100 + (10 * random 20)}]
        ]
        ;place a new apple
        
        repeat 2 + int (:score / 10) [
          
          queue "pa "queue
          ;a pa or 'pass' will cause these new segments not to move on the next
          ;iteration, until movement commands are 'shuffled' on to their places
          ;in the queue
          
          inc "length
          ;increment the value of the length container by one
          
          nameturtle :length
          ;create a new turtle with the name contained in :length (the new length)
          
          (control :length {"hideturtle "setmodel ""ball "wrap "penup "setpos
          "query :length - 1 leftbracket "position rightbracket "setvectors
          "query :length - 1 leftbracket "vectors rightbracket})
          ;set up the new turtle and make sure it's positioned next to the
          ;previously last turtle, and is facing in the same direction
          
          control :length [setbounds [-185 -115 185 115] showturtle]
          ;set the bounds of the new turtle and show it
          
          wait 10
        ]
        ;add new segment to the snake
        
      ]
      
      ;and if it's not an apple?
      else [
        print "crash! playsound "crash finish
      ]
      ;game over, man! game over!
    ]
  ]
END

Example: Spiral Tunnels

TO spiraltunnelanimation
  reset fullscreen
  setbackgroundcolor 0
  dropanchor penup
  raise 190 pullout 50
  
  repeat 2100 [
    setfillshade -15 + int (repcount / 65)
    
    setfillcolor (item 1 + remainder int (repcount / 2.35) 8
    {red orange yellow green lightgreen cyan blue magenta})
    
    voxeloid 7 12 20
    
    orbitleft 10.1 lower 0.6
  ]
  
  home lower 3000
  setmodelscale 2.5
  down 90 right 180
  make "dir 0
  snappy:setanchor [0 0 -1050]
  
  forever [
    forward 2 rollright 0.1
    if zpos > 1500 [setz -3000]
    snappy:rollleft 0.05 snappy:pullin 0.1
    
    if and :dir = 0 snappy:orbitdistance = 0 [
      make "dir 1
      snappy:right 180
      setbackgroundcolor 15
      snappy:setanchor [0 0 180]
    ]
    
    if and :dir = 1 snappy:orbitdistance = 0 [
      make "dir 0
      snappy:right 180
      setbackgroundcolor 0
      snappy:setanchor [0 0 -1050]
    ]
  ]
END

Examples: Turtle Art

Logo is great for creating art! And 3D Logo makes it even better.

Many of these Logo artworks were inspired by examples created by Seymour Papert’s daughter Artemis Papert using the two-dimensional block-based TurtleArt application developed by LCSI Logo developer Brian Silverman. We’re grateful for both of their efforts in advancing Logo over the past several decades!

TO adobo
  reset setpenwidth 5 definecolor 16 [0 0 0]
  setpc 16 setbg 1 setbs 12 pu
  repeat 9 [
    repeat 10 [
      setpos {-120 + 20 * repcount -120 + 20 * repabove 1}
      setz -2 + 0.01 * random 400
      setfc pick [8 9 13]
      setfs -13 + random 10
      setheading -5 + random 11
      square 40 box 40
    ]
  ]
END

TO brush
  reset setbg 8
  setpenwidth 5 setbs 11
  
  repeat 300 [
    setpc pick [1 8 9 11]
    setps -10 + random 20
    pu
    setpos {-200 + random 400 -100 + random 200}
    rt random 360 pd
    repeat 20 + random 50 [
      make "stroke 30 + random 150
      fd :stroke rt -0.5 + 0.1 * random 10
      bk :stroke + random 2 lt -0.5 + 0.1 * random 10
    ]
    ra 0.01
  ]
END




TO bundles
  reset randbg
  repeat 40 [
    pu setpos {-200 + random 400 -100 + random 200}
    setpenwidth 4  pd
    lt random 360
    make "head heading
    repeat 2 [
      randpc
      repeat 90 [
        make "stroke 50 + random 5
        setps -10 + random 20
        fd :stroke
        bk 2 * :stroke
        fd :stroke
        rt 0.1 * random 20
        up -2 + (0.1 * random 40)]
      setheading :head
    ]
  ]
END



TO burst
  reset  pu
  make "colors {yellow orange red magenta blue}
  repeat 5 [
    setpc item repcount :colors
    setmarkerwidth repcount
    make "count repcount
    repeat 50 [
      rt random 360 mark :count * (20 + random 10)
      setpos [0 0]] lo repcount
  ]
END

TO caduceus
  reset  setpenwidth 5 pu
  repeat 4 [
    setpc item repcount [13 9 1 8]
    ra repcount * 2
    bk 120 pd
    repeat 100 [
      fd 1.4 + 0.1 * repabove 1
      rt 7.5 * sin 270 + 10 * repcount
    ]
    repeat 75 [
      fd 2.5 + 0.5 * repabove 1
      lt 0.5 * repcount
    ]
    pu home rr 180 * repcount
  ]
END

TO cards
  reset  pu
  repeat 1000 [
    setpos {-200 + random 400 -100 + random 200}
    rt random 360
    make "sizex 10 + random 20
    make "sizey 10 + random 20
    setfc 2 setfs 13
    quad :sizex + 2 :sizey + 2
    sr 1 fd 1 ra 0.01
    setfc pick [2 3 7 14]
    setfs -5 + random 10
    quad :sizex :sizey
    ra 0.01
  ]
END


TO citylights
  reset pu  setbg 2 setbs 10
  repeat 200 [
    setpos {-200 + random 400 -100 + random 200}
    rt random 360 make "size 20 + random 50
    setfc pick [1 9 13 7] lo 0.01
    until :size = 0 [
      randfs spot 0.05 * :size
      fd 5 lo 0.01 dec "size
    ]
  ]
END


TO dotcube
  cs seticosphereiterations 1 pu
  repeat 9 [
    repeat 9 [
      repeat 9 [
        setposition {-100 + 20 * repabove 2 -100 + 20 * repabove 1 -100 + 20 * repcount}
        setfc repabove 1 setfs repcount ico 2
      ]
    ]
  ]
END

TO dotspiral
  Reset setbg 13 setfc 9 cs
  repeat 1400 [
    pu fd repcount / 10
    spot repcount / 250
    rt 35
  ]
END


TO fireworks
  cs setpenwidth 5
  repeat 60 [
    pu home
    rt random 360
    randpc pd
    fd 30 + random 50
    repeat 50 [
      run pick [[pu][pd]]
      fd 2]
  ]
END

TO fish
  reset wrap
  setbounds [-180 -120 180 120]
  setbg 1 setbs 12
  pu setpos [-170 75]
  repeat 12 [
    setpenwidth 4 rt 44.5
    repeat 10 [
      sl 1
      repeat 3 [
        setpc item repcount [13 1 13]
        if repcount = 2 [ra 0.2]
        if repcount = 3 [lo 0.2]
        pd fd 50 pu bk 50 pu sr 1
      ]
      sl 2 rt 10
    ]
    setfc 1 ico 1 st
    lt 54.5 sr 13 fd 60
    lt 90
  ]
END

TO gaia
  reset setbg 2 setpenwidth 5  setpc 1
  repeat 5 [
    setpc item repcount [8 1 9 13 15]
    setorigin {0 0 2 * repcount}
    repeat 20 [
      pu home pd rt repcount * 18
      repeat 80 [
        fd 0.9 + ((repabove 2) * 0.1)
        rt 8 * sin (repcount * 8)
      ]
      lt 7.5
      repeat 5 [
        fd 20 pu bk 20 rt 15 pd
      ]
    ]
  ]
END


TO gradient
  cs pu
  repeat 30 [
    setfs -15 + repcount quad repcount 200 lo 0.01 sl 0.5
  ]
END

TO gridart
  reset
  randbg
  randfc
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      spot 3.5 * sin ((:i + repcount) * 2)
      sr 7.5
    ]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO gridartico
  cs
  seticosphereiterations 1
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      ico 3.5 * sin ((:i + repcount) * 2)
      sr 7.5
    ]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO gridartshade
  reset randbg randfc pu
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      setfs int (10 * (sin ((:i + repcount) * 2)))
      spot 3.5
      sr 7.5
    ]
    sl 57 * 7.5 bk 7.5
  ]
END

TO gridartwave :size
  cs
  seticosphereiterations 1
  pu
  
  setpos [-210 113]
  repeat 31 [
    for [i 1 57] [
      make "sin 3.5 * sin ((:i + repcount) * 2)
      ra :size * :sin
      ico :sin
      lo :size * :sin
      sr 7.5]
    sl 57 * 7.5
    bk 7.5
  ]
END

TO guessing
  Reset setspeed 5 setbg 9 setbs 3 setpenwidth 5
  repeat 8 [
    pu home ra repcount rt repcount * 45 pd
    repeat 22 [
      if repcount < 4 [
        setpc 8 setps 9 - (3 * repcount)] [
        setpc 13 setps (penshade - 1) + random 3
      ]
      repeat 360 [fd 1 - (0.015 * repabove 1) rt 1]
      pu sr 0.02 pd
    ]
  ]
END



TO heat
  cs pu
  repeat 10 [
    setfc pick [1 9 13]
    setpos {-170 + (repcount * 30) -120}
    up 90
    repeat 80 [
      cylinder 0.1 * repcount 1.6 10
      sr sin (repcount * 10)
      lo 1.5
    ]
    repeat 80 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10)
      lo 1.5
    ]
    dn 90
  ]
END

TO heat2
  cs pu
  repeat 10 [
    setfc pick [1 9 13]
    setpos {-170 + (repcount * 30) -120}
    up 90
    repeat 80 [
      cylinder 0.1 * repcount 1.6 10
      sr sin (repcount * 10)
      lo 1.5
    ]
    repeat 80 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10)
      lo 1.5
    ]
    dn 90 rr 180
  ]
END

TO hedgehog
  reset  setfc 1 pu ra 1 spot 20 setpc 13
  repeat 36 [
    home dropanchor tether pullout 18
    orbitleft repcount * 10 rt 225
    setmarkerwidth 0.1 * random 20
    mark 30 + random 80
  ]
END

TO funnybird :col1 :col2
  rl 90 setfc :col1 icospheroid 20 0.5
  pu rr 90 fd 5 sr 12 lt 30
  cylindroidarc 10 15 20 30 10 0.3
  fd 10 sr 15 ra 2
  setfc :col2 ico 3 lo 3.5 ico 3 ra 1.75
  bk 10 dn 90 lt 90
  domoid 10 8 20 0.3 fd 30 sl 7 rt 90
  icospheroid 8 2 fd 14
  icospheroid 8 2 bk 7 rr 30 rr 10 up 10
  cylinder 2 35 20 lo 40 rr 180 lt 90 dn 10
  domoid 7 10 10 0.5 oval 3.5 7 up 10 rt 90
  rl 180 ra 35 dn 20 rl 20
  cylinder 2 35 20 lo 40 rr 180 lt 90 up 10
  domoid 7 10 10 0.5 oval 3.5 7
END

TO hiding
  reset setpenwidth 5 pu
  sl 30 funnybird 1 9 home
  ra 20 rr 180 sl 30 up 10
  funnybird 13 8 rl 180 fd 20
  sr 20 spot 100 sl 40 up 90
  rl 90 sl 60 pd setpc 13
  pushturtle
  repeat 50 [
    popturtle
    pushturtle
    pu sr repcount * 2
    pd lt -10 + random 30
    setpc pick [8 9 13]
    setfs -10 + random 20
    raise -2 + random 6
    repeat 70 + random 30 [fd 1 rt 0.7]
  ]
  ht
END



TO icicles
  reset pu up 90
  repeat 20 [
    setpos {-210 + (20 * repcount) 115}
    make "size 20 + random 15 randfc
    repeat :size [
      cylinder 0.2 * (:size - repcount) 0.6 + (:size / 5) 20
      ra 0.5 + (:size / 5)
    ]
  ]
END

TO moon
  reset lt 120
  repeat 180 [fd 1 rt 1]
  rt 150
  repeat 180 [fd 0.774 lt 0.676]
  pu fd 30 pd
  repeat 3 [
    repeat 5 [
      fd 20 bk 40 fd 20 rt 36
    ]
    pu rt 180 sl 40 fd 40 pd
  ]
  ht
END

TO needles
  reset
  repeat 5 [
    repeat 10 [
      pu setpos {-240 + 80 * repabove 1 126 - repcount * 23}
      pushturtle rr 90 up -15 + random 30 randfc
      cylinder 1 30 10 rr 180 cylinder 1 30 10 popturtle
    ]
  ]
END


TO nest
  reset setspeed 1
  repeat 3 [
    setpc item repcount [9 8 4]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 7 * repabove 1 rt repcount * 20
      setps -5 up 10 pd
      mark 50 + 2 * repabove 1
      repeat 4 [
        setps penshade + 2
        repeat 90 [
          pu bk 0.1 pd mark 0.2 + 0.1 * repabove 1
          rt 2 up 1
        ]
        setpenshade penshade + 1
        repeat 90 [
          pu bk 0.1 pd
          mark 0.2 + 0.1 * repabove 1
          lt 2 up 1
        ]
      ]
    ]
  ]
  setfc 7 pu home ra 17 icospheroid 10 2 ht
END



TO notnot
  reset pu sl 10 lt 40 setpc 15 setbg 1
  setmarkerwidth 10 repeat 360 [
    mark 1.1 bk 0.1 lt 1
  ]
  lt 90 mark 115 home sr 90 fd 25 rt 40
  repeat 360 [
    mark 0.8 bk 0.1 lt 1
  ]
  lt 90 mark 80
END


TO orangepeel
  reset setpenwidth 8 setbs 3
  setbg 13 setpc 9 setps 0
  repeat 5 [
    pu home
    setpos {-240 + repcount * 50 113}
    rt 100
    repeat 10 [
      sr 1.5 fd 1 pd setps -5 + repcount
      repeat 100 [
        if divisorp 10 repcount [
          setps penshade + 1
        ]
        fd 2.75 rt repcount
      ] lt 10
    ]
  ]
END

TO patio
  cs pu setpos [-87.5 85] setfc 13
  repeat 5 [
    repeat 6 [
      setfillshade -10 + random 21
      make "offset random 10
      lt 50 - :offset
      polyspot 20 4
      rt 50 - :offset
      sr 35
    ]
    sl 210 bk 35
  ]
END

TO peaks
  reset  ht pu bk 125 setbg 2
  repeat 3 [
    setfs 0 setfc 13
    fiso 100 250
    setfc 7 setfs repcount * 3
    ra 0.1
    fiso 75 200
    sl 120 lo 50 bk 30
  ]
  home bk 125 sr 120 lo 50 bk 30
  repeat 2 [
    setfc 13 setfs 0 fiso 100 250
    setfs 3 + repcount * 3
    setfc 7 ra 0.1 fiso 75 200
    sr 120 lo 50 bk 30
  ]
  setpenwidth 5 home setpos [140 80]
  setpc 13
  repeat 36 [
    pd fd 35 pu bk 35 rt 10
  ]
END


TO pinwheel
  reset twosided
  pu setbg 2
  setfc 14 setpc 7
  repeat 2 [
    setpc item repcount [7 11]
    setfc item repcount [14 13]
    pu home rt repcount * 45
    bk 10
    repeat 100 [
      fd 40 + repcount * 1.2
      lt 90 fd 10 lt 92 fd 10
      frag lt 90
    ]
  ]
END

TO postits
  reset pu
  repeat 10 [
    repeat 10 [
      setpos {-120 + 20 * repcount -120 + 20 * repabove 1}
      randfc
      setheading -5 + random 11
      square 20 ra 0.1
    ]
  ]
END


TO rainbow
  reset setpenwidth 10  pu sl 225 bk 125 lt 10 pd
  repeat 500 [
    foreach "col {red orange yellow green blue lightblue magenta} [
      setpc :col fd 0.5 * (0.1 * (10 + repcount))
    ]
    pu bk (0.5 * (7 * (0.1 * (10 + repcount))))
    sr 1 fd 0.2 * (sin (0.5 * (repcount + 100)))
    pd
  ]
END

TO redonpink
  reset setpc 1 setbg 11 setbs -5
  pu setfc 1
  repeat 1000 [
    setpos {-220 + random 440 -120 + random 240}
    ra 0.001 setfo 50 setfs -15 + random 10
    spot 5 + random 5
  ]
  setorigin [-50 -30 2]
  repeat 16 [
    setmarkerwidth 3 home dropanchor
    pullout 10 orbitleft repcount * 22.5
    rt 180
    repeat 70 [
      setmarkerwidth markerwidth - 0.02
      bk 0.1 mark 1 rt 2
    ]
    repeat 70 [
      setmarkerwidth markerwidth - 0.02
      bk 0.1 mark 2 lt 2
    ]
  ]
END


TO roses
  reset setpenwidth 5
  repeat 3 [
    pu setpos {-190 + (repcount * repcount) * 30 -90 + repcount * 50}
    pd make "size 0.05 * (repcount / 2)
    setpc item repcount [1 9 13]
    repeat 9 [
      repeat 100 [
        fd repcount *  :size rt 10
      ]
    ]
  ]
END


TO slats
  reset
  setorigin [-260 -120]
  repeat 23 [
    pu setps -7 + repcount
    home sr 20 * repcount
    setmarkerwidth 18 rt 10
    mark 250
  ]
END


TO slats2
  reset
  setorigin [-260 -120]
  repeat 23 [
    pu setps -7 + repcount
    home setpc pick [8 9 13]
    sr 20 * repcount
    setmarkerwidth 18 rt 10
    mark 250
  ]
END

TO snake
  CS PU RANDFC
  BK 110 UP 90
  repeat 80 [
    cylinder 0.1 * repcount 1.6 10
    sr sin (repcount * 10)
    lo 1.5
  ]
  repeat 60 [
    cylinder 0.1 * (80 - repcount) 1.6 10
    sr sin ((80 + repcount) * 10)
    lo 1.5
  ]
  DN 90 RT 60 ICOSPHEROID 5 2 SL 7 FD 3
  RANDFC ICO 1 BK 6 ICO 1 HT
END

TO snakes
  CS PU RANDFC
  repeat 10 [
    home setpos {-170 + (repcount * 30) -110}
    up 90 repeat 80 [
      cylinder 0.1 * repcount 1.6 10 sr sin (repcount * 10) lo 1.5
    ]
    repeat 60 [
      cylinder 0.1 * (80 - repcount) 1.6 10
      sr sin ((80 + repcount) * 10) lo 1.5
    ]
    DN 90 RT 60 ICOSPHEROID 5 2 SL 7 FD 3
    RANDFC ICO 1 BK 6 ICO 1
  ]
  HT
END

TO solar
  reset  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt repabove 1 rt repcount * 20
      setps 0 pd mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END

TO solar2
  reset setspeed 5
  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 3 * repabove 1
      rt repcount * 20
      setps 0 pd
      mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END


TO solar3
  reset           setspeed 5
  repeat 5 [
    setpc item repcount [1 8 9 13 15]
    repeat 18 [
      pu home raise 2 * repabove 1
      rt 4 * repabove 1
      rt repcount * 20 setps 0
      pd mark 50
      repeat 5 [
        setps penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1
          rt 2
        ]
        setpenshade penshade + 1
        repeat 90 [
          mark 0.2 + 0.1 * repabove 1 lt 2
        ]
      ]
    ]
  ]
END

TO sparks
  reset setpenwidth random 10
  randbs randbg
  repeat 5 [
    pu setposition {-200 + random 400 -100 + random 200 -100 + random 100}
    setorigin position randpc randps
    repeat 30 [
      rt random 360 pd
      while (and xpos < 300 xpos > -300 ypos < 180 ypos > -180) [fd 1 lt 0.2]
      pu home
    ]
  ]
END

TO spiralart
  reset
  snappy:pullin 100
  pu
  randbg
  sl 40
  rr 90
  bk 10
  repeat 2 [
    randfc
    repeat 2800 [
      tube 2 repcount / 400 6
      lo repcount / 500
      up 2
    ]
    pu home
    fd 10 sr 40 rl 90
  ]
  ht
END


TO spirallights
  reset  setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    randpc
    repeat 10 [
      pu setpos {-220 + (40 * repcount) :ypos}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10 rt 30
      ]
    ]
  ]
END

TO spirallightsorange
  reset  setbg 8
  setbs 13 setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    repeat 10 [
      pu setpc pick [1 8 9 13]
      setpos {-220 + (40 * repcount) :ypos}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10
        rt 30
      ]
    ]
  ]
END


TO spirallightsorange3d
  reset  setbg 8 setbs 13
  setpenwidth 5
  repeat 5 [
    make "ypos 130 - (40 * repcount)
    repeat 10 [
      pu setpc pick [1 8 9 13]
      setposition {-220 + (40 * repcount) :ypos 0}
      pd
      repeat 100 [
        setps -10 + int (repcount / 5)
        fd repcount / 10 rt 30 dn 2
      ]
    ]
  ]
END

TO splash
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      setps -15 + (repcount / 12)
      fd .4
    ]
  ]
  pu home
END

TO splash2
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      setps -15 + (repcount / 12)
      fd .4
    ]
  ]
  pu home
END

TO splash3
  reset setspeed 5 setpenwidth 5
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      rr sin repcount
      setps -15 + (repcount / 12)
      fd .4]
  ]
  pu home
END

TO splash4
  reset setspeed 5 setpenwidth 5 setpc 1
  repeat 144 [
    pu home rt repcount * 2.5 dn 75 pd
    repeat 400 [
      up 5 * (sin (repcount * 4))
      rt sin repcount
      rr sin repcount * 2
      setps -15 + (repcount / 12)
      fd .4]
  ]
  pu home
END

TO spotwave
  cs  pu
  repeat 32 [
    setpos {-220 205 - (repcount * 10)}
    repeat 45 [
      setfc pick [2 3 5 6 7 10 14 15]
      spot 5 sr 10
      fd -2 + sin (repcount * 10)
    ]
  ]
END


TO stickman :size
  lt 45 setmarkerwidth :size / 3
  repeat 2 [
    lt 90 mark :size * 5 spot :size
    bk :size * 5] lt 135 mark :size * 2
  lt 45 repeat 2 [
    mark :size * 5 spot :size bk :size * 5 rt 90
  ]
  lt 135 mark :size * 5
  spot :size * 2 pu bk :size * 10
END

TO stickmen
  reset pu sl 80 fd 20
  repeat 3 [
    randfc setpc fillcolor
    stickman repcount * 3
    pu sr 80 ra 20
  ]
END

TO stormy
  reset  pu setpos [-230 -120]
  repeat 8 [
    setpc item repcount [2 6 7 14 1 8 9 13]
    repeat 160 [
      pushturtle rt 45 bk random 20
      randps mark 50 + random 20
      popturtle pu
      sr 2.5 + random 5 ra 0.01
    ]
    ra 0.1 pu
    setpos {-230 -120 + repcount * 30}
  ]
END

TO swirl
  reset pu bk 20 sr 40 setpc 1
  setbg 13 setbs -10 setorigin position pd
  repeat 12 [
    repeat 30 [
      setropewidth 6.1 - (repcount / 5)
      rope 4 bk 0.2 rt 6 bk 0.2
    ]
    pu home rt repcount * 30 pd
  ]
  ht
END


TO thicket3
  reset  setbg 2 setpenwidth 5  setpc 1
  repeat 8 [
    setpc item repcount [8 1 9 4 12 13 14 15]
    repeat 20 [
      pu setposition {-200 + (repcount * 20) 0 5 + repabove 1}
      up 25 pd
      repeat 80 [
        fd 0.9 + ((repabove 2) * 0.1)
        rt 8 * sin (repcount * 8)
      ]
      lt 7.5
      repeat 5 [
        fd 20 pu bk 20 rt 15 pd
      ]
    ]
  ]
END

TO twomoons
  reset
  setorigin [-23 -23 0]
  repeat 2 [
    setpc item repcount [7 2]
    repeat 36 [
      pu home dropanchor
      pullout 10 * repabove 1
      orbitleft repcount * 10
      rt 180 pd
      if oddp repcount [fd 40 * repabove 1] [fd 20 * repabove 1]
    ]
    setorigin [30 30 -20]
  ]
END


TO vase
  reset setpenwidth 5  pu fd 50 sl 50 pd rt 135
  repeat 40 [fd 1 rt 2]
  repeat 125 [fd 1 lt 1]
  lt 5 quad 80 220 rt 180 rr 180
  quad 80 220 rr 180 rt 185
  repeat 125 [fd 1 lt 1]
  repeat 40 [fd 1 rt 2]
  pu home bk 70 lt 15 setpc 15
  repeat 6 [
    pushturtle pd fd 150 + random 20
    setfc pick [1 8 9 11] ra 0.1
    spot 5 popturtle rt 6
  ]
END


TO weave
  reset  wrap
  repeat 30000 [
    fd 1 rt
    sin repcount
    if divisorp 1000 repcount [randpc]
  ]
END

TO zig
  reset  setbg pick [1 8 9 13]
  setbs 10 setpenwidth 10
  repeat 200 [
    ra 0.1 pu
    setpos {-220 + random 440 -120 + random 240}
    rt random 360 setpc pick [1 8 9 13]
    setps -15 + random 10
    repeat 50 [
      pd fd 50 + random 3 lt random 3 bk 50 + random 3
      rt random 3 setps penshade + (-1 + random 3)
    ]
  ]
  pu setpos [-100 -50]
  setheading 300 pd setpc 1
  setps 5 ra 1
  repeat 15 [
    bk 0.2 fd 20 rt 140
    bk 0.2 fd 20 lt 132.5
  ]
END


TO zigzag
  reset setbg 8 setbs 0 setpenwidth 5
  
  repeat 360 [
    pu home pd rt repcount * 1 lt 45
    setpc pick [1 5 7 9]
    repeat 20 [
      fd repcount rt 90
      fd repcount lt 90
    ]
  ]
END

TO zigzag3d
  reset setbg 8 setbs 0 setpenwidth 5
  repeat 360 [
    pu home pd rt repcount * 1
    lt 45 up 45 setpc pick [1 5 7 9]
    repeat 20 [
      fd repcount rt 90 fd repcount lt 90
    ]
  ]
END

Example: Fly Me to the Moon

Let’s make a rocket ship kind of like the Saturn V used in the moon landings!

TO rocket
  
  ;step [rocket]
  
  ;uncomment step line above to 'step through'
  ;building the rocket. You will need to call
  ;rocket twice
  
  clearscreen
  penup
  
  up 90
  
  setfillcolor red
  cone 10 30 12
  ;create the nose cone
  
  ;cone takes three parameters:
  ;radius, depth (or height) and sides
  
  ;So in this case, a radius of 10 turtle
  ;units, a depth of 30 turtle units, and
  ;12 sides.

  ;the cone is created under the turtle
  
  down 180
  ;flip over
  
  setfillcolor white
  cylinder 10 50 12
  ;create the body
  
  ;cylinder takes three parameters:
  ;radius, depth and sides, like cone
  
  ;the cylinder is created under the turtle
  ;similarly to cone
  lower 50
  ;lowers the turtle, like as if going
  ;down in an elevator
  
  ;same as: down 90 forward 50 up 90
  
  setfillcolor blue
  cutcone 10 15 20 12
  ;create the base
  
  ;cutcone creates a truncated cone
  ;cutcone takes four parameters:
  ;near radius, far radius, depth and sides

  ;like cone, the cut cone is created under
  ;the turtle
  
  ;begin APOLLO inscription
  
  up 90
  raise 11
  ;going up! (like in an elevator)
  
  settypedepth 5
  settypesize 6
  slideright 3
  ;same as right 90 forward 3 left 90
  
  inscribe |  APOLLO|
  ;incribe prints text in front of the turtle
  ;without moving it.
  ;compare with typeset which prints to the right
  ;and moves the turtle.
  
  slideleft 3
  ;same as left 90 forward 3 right 90
  
  lower 11
  ;going down!
  
  down 90
  ;not the same as lower, which lowers
  ;down tilts the turtle down
  
  ;end of APOLLO inscription
  
  ;begin fins:
  lower 20
  up 90
  setfillcolor grey
  twosided
  ;light both sides of surfaces
  
  rat 40 lat 40
  ;create a triangle to the right,
  ;(Right Angle Triangle = rat)
  ;and a triangle to the left
  ;(Left-facing right Angle Triangle = lat)
  
  rollright 90
  setfillcolor lightblue
  rat 40 lat 40
  rollleft 90  down 90
  ;end fins
  
  ;begin rockets
  forward 8
  setfillcolor yellow
  cylinder 5 5 10
  back 16
  cylinder 5 5 10
  forward 8
  slideleft 8
  cylinder 5 5 10
  slideright 16
  cylinder 5 5 10
  ;end rockets
  
  ;begin fire
  setfillcolor orange
  lower 5
  cutcone 3 2 3 10
  slideleft 16
  cutcone 3 2 3 10
  slideright 8
  forward 8
  cutcone 3 2 3 10
  back 16
  cutcone 3 2 3 10
  ;end fire
  
END