Export STL format 3D models created in turtleSpaces 3D Logo using the SAVESTL primitive

turtleSpaces has a new primitive, SAVESTL, which can be used to export 3D models of the current turtleSpace.

savestl "modelname

creates a new folder in the current project folder (TSP) with the extension MDL (eg modelname.mdl), inside which contains STL format files, one for each color used in the space. These files can be used with other 3D applications (such as the pictured viewstl.com website), and can be 3D printed (although the sides of objects may need to be extruded using another application first, if the desire is for the objects to be hollow).

Another primitive, SETSTLLINETHICKNESS, is used to set the radius of the ropes used to represent lines in exported STL files. It takes a number.

setstllinethickness 10

Happy 3D printing!

 

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

Control turtleSpaces from other applications with its API

You can communicate with turtleSpaces over a socket (telnet) connection to port 1967.

First you need to issue the API command inside of turtleSpaces to enable API connections, or use the -enable-api flag when starting up.

Then connect to turtleSpaces from an external application or terminal. You can issue instructions to affect turtles and the environment just like you would do inside the turtleSpaces application.

The API connection executes as its own worker. You can also redirect input and output to the API instance by using setread “api and setwrite “api – but these must be issued by the API worker itself to redirect to that worker (if you use another API connection, reading and writing will be redirected to that API instance, for example).

Using the API, you can use turtleSpaces as a visualiser for another application, and have it act as a light organ, or create charts and graphs.

 

‘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

Example: Random Solar System

Create a ‘random’ solar system and surrounding star field using these commented Logo procedures:

TO solsys
  reset
  ;reset the turtles and clear the environment
  
  fullscreen
  ;don't display text
  
  ask "snappy [pullout 1000]
  ;ask the camera turtle to pull away from
  ;myrtle 1000 turtle units
  
  penup
  ;raise the turtle's pen so she doesn't draw
  
  hideturtle
  ;go incognito
  
  stars
  ;jump to the stars procedure, which creates
  ;a starfield around our solar system
  
  setfillcolor yellow
  icosphere 75
  ;make the sun, an icosphere 75 turtle units
  ;in radius
  
  dropanchor
  ;set Myrtle's 'anchor point' or the point
  ;she orbits around to her home position.
  ;By default it is somewhat in front of it.
  
  pullout 100
  ;pull out from the anchor point 100 turtle units
  
  repeat 10 [
    ;do the following ten times, to create ten planets
    
    pullout 100
    ;pull out from the anchor point 100 more
    ;turtle units
    
    orbitleft random 360
    ;orbit to the left between 0 and 360 degrees
    ;(up to one full orbit of the anchor point)
    
    planet repcount
    ;jump to the planet procedure, passing it
    ;the current iteration of the repeat loop
    ;as its parameter - the current planet number
    
  ]
  ;this is the end of the planet creation loop
  
  snappy:forever [orbitdown 0.001]
  ;orbit around the scene
  ;snappy: is shorthand for 'ask "snappy []'
  
END

TO stars
  ;create a starfield
  
  repeat 500 [
    
    randomvectors
    ;points the turtle in a random 3D
    ;direction. 'Vectors' describe absolute
    ;directions in 3D space using numbers.
    ;We call them vectors so as to not confuse
    ;them with relative directions such as up,
    ;down, left or right. A turtle with certain
    ;vectors will always point a certain way.
    ;For now, that's all you need to know!
    
    forward 1500 + random 500
    ;move forward 1500 turtle units plus
    ;between 0 and 499 turtle units in the
    ;turtle's forward direction - its forward
    ;'vector'
    
    ;Note: 'random' generates a number between
    ;0 and one less than the number you give it.
    ;The turtle knows what you mean when you say
    ;'random' because random is a primitive - a
    ;word the turtle knows.
    
    up 90
    ;tilt the turtle up 90 degrees, one quarter of
    ;a circle or one quarter of a complete rotation.
    ;Like as if you leaned back so far you were
    ;staring up at the sky
    
    randomfillcolor
    ;random means 'pick one at random', in this
    ;case a random fill color, numbered between 1
    ;and 15 (there are 16 default colors, but 0 is
    ;transparent and not typically a useful fill
    ;color!)
    
    spot 5 + random 5
    ;make a 'star', a spot with a radius of 5
    ;turtle units plus 0 - 4 additional turtle units
    
    home
    ;go back to the home position
  ]
  ;make 500 stars
  
END

TO planet :number
  ;make a planet. The number passed to
  ;planet is used to uniquely identify
  ;its 'model' - what it looks like
  
  newmodel :number [
    randomfillcolor
    ;Remember: not black!
    
    icosphere 10 + random 25
    ;create a randomly-sized sphere
    
    randomvectors
    ;'what's your vectors, Victor?'
    
    dountil fillcolor != yellow [randomfillcolor]
    ;not yellow!
    
    spot 10 + random 30
    ;create a randomly-sizes spot.
    ;If it's bigger than the sphere
    ;then it will act as a ring
    
  ]
  ;make a random planet model with the
  ;name of the planet number stored
  ;in the :number container, which was
  ;created when the number was passed
  ;in to the planet procedure
  
  ;Models are not unique to turtles, and
  ;so they each need a unique name, regardless
  ;of whatever turtle 'wears' them. But that
  ;name can just be a number, as long as it
  ;is a unique number
  
  hatch [
    ;hatch a new turtle from this spot
    
    showturtle
    ;show the hatchling's model. Hatchlings
    ;models are hidden when they are hatched
    ;as are those of other turtles when they
    ;are newly created. Only Myrtle is shown
    ;by default
    
    put 1 + random 10 in "speed
    ;generate a random number between
    ;0 and 9, add it to 1 and put it in
    ;a container named 'speed'
    
    setmodel :number
    ;set the hatchling's 'model' or
    ;appearance to the name stored in
    ;the :number container
    
    setanchor [0 0 0]
    ;set the 'anchor' or the point a turtle
    ;orbits around to [0 0 0], the location
    ;of the sun
    
    forever [
      orbitleft :speed * 0.001
    ]
    ;orbit around the sun 'forever'
  ]
  ;this is the end of the hatchling's code
  
END

Example: 3D Filled Trees

Filled triangles

TO tree
  clearscreen penup 
  setpos [0 80] setfillcolor 4 
  repeat 6 [
    setfillshade -6 + 3 * repcount 
    ;repcount returns the current iteration
    back 4 * repcount 
    fiso 8 * repcount 5 * repcount 
    ;fiso = filled iso triangle
    lower 0.1
  ] 
  setfillcolor 8 setfillshade 5 
  back 50 slideleft 10 
  quad 20 50
  ;trunk
END

‘Tents’ – fiso prisms

TO tree3d
  cs pu setpos [0 80] 
  ;cs = clearscreen
  ;pu = penup
  setfc 4 
  ;setfc = setfillcolor
  repeat 6 [
    setfs -6 + 3 * repcount 
    ;setfs = setfillshade
    bk 4 * repcount 
    ;bk = back  
    tent 8 * repcount 5 * repcount 10 
    lo 0.1
    ;lo = lower
  ] 
  setfc 8 setfs 5
  bk 50 sl 10 
  ;sl = slideleft
  voxeloid 20 50 10
  ;voxeloids are stretched cubes
END

Cones

TO conetree
  cs pu setpos [0 80] 
  setfc 4 up 90 
  repeat 6 [
    setfs -6 + 3 * repcount 
    ra 4 * repcount 
    cone 8 * repcount 5 * repcount 20
  ] 
  setfc 8 setfs 5 ra 50
  cylinder 8 50 20
END

Pyramids (5-sided ‘cones’)

TO pyramidtree
  cs pu setpos [0 80] 
  setfc 4 up 90 
  repeat 6 [
    setfs -6 + 3 * repcount ra 4 * repcount
    cone 8 * repcount 5 * repcount 4
    ;while there is also a pyramid primitive, you can 
    ;also create a pyramid by creating a 4-sided cone
  ] 
  setfc 8 setfs 5 ra 50 
  cylinder 8 50 4
END

4-sided cones

TO tetratree
  cs pu setpos [0 80] setfc 4 up 90 
  repeat 6 [setfs -6 + 3 * repcount 
    ra 4 * repcount 
    cone 8 * repcount 5 * repcount 3] 
  setfc 8 setfs 5 ra 50 
  cylinder 8 50 3
END