lot

File*
Docs
Download
What do I make?
log in to save
Machine control
/*
@title: Pyro Snow
@author: Map
@snapshot: snapshot1.png
*/
const width = 300
const height = 300

setDocDimensions(width, height)

const rr = bt.randInRange
const ri = bt.randIntInRange
const t = new bt.Turtle()
const bg = new bt.Turtle()

//determine the size of each snowflake with these 2.
//warning; very unpredictable, trust me! I greatly limited the variables for now
//feel free to go wild though. see the white sun for yourself.
const shaftLength = ri(10, 15)
const branches = ri(2, 5)

//flip a coin to determine if your flake has a "third branch"
const third = ri(0, 1)

//main background drawer func
function drawBG() {

//draws a white rectangular background up top for clouds
const cg = new bt.Turtle();
cg.jump([0, 250])
for (let i = 250; i < 300; i++) {
cg.forward(width - 2)
if (i % 2 == 0) {
cg.left(90)
cg.forward(1)
cg.left(90)
} else {
cg.right(90)
cg.forward(1)
cg.right(90)
}
}
const cgs = cg.lines();
drawLines(cgs, { width: 4, stroke: "black" })

//draws the cloud bumps
var clouds = []
var base = 0
for (let z = 0; z < 3; z++) {
for (let a = 0; a < 3; a++) {
const cloud = bt.catmullRom([
[base, 250 + (a * 3.5)],
[base + 50, 240 + (a * 3.5)],
[base + 100, 250 + (a * 3.5)]
], 1000)
clouds.push(cloud)
}
base += 100
}
drawLines(clouds, { width: 6, stroke: "black" })
}
drawBG();

//main branch creation logic; recursive
//i know loops exist; found it easier to do this instead though.
function generateBranch(brs) {
t.right(90)
t.forward(((shaftLength) / 2) * (brs / 10))
t.right(90)
t.forward(((shaftLength) / 3) * (brs / 10))
if (brs > 1) {
generateBranch(brs - 1);
}
t.left(90)
t.forward(((shaftLength) / 4) * (brs / 10))
t.left(90)
if (brs > 1) {
generateBranch(brs - 1);
}
t.forward(((shaftLength) / 3) * (brs / 10))
t.right(90)
t.forward(((shaftLength) / 5) * (brs / 10))
t.left(90)
t.forward(((shaftLength) / 5) * (brs / 10))
t.left(90)
t.forward(((shaftLength) / 5) * (brs / 10))
t.right(90)
t.forward(((shaftLength) / 3) * (brs / 10))
if (brs > 1) {
generateBranch(brs - 1);
}
t.left(90)
t.forward(((shaftLength) / 4) * (brs / 10))
t.left(90)
if (brs > 1) {
generateBranch(brs - 1);
}
t.forward(((shaftLength) / 3) * (brs / 10))
t.right(90)
t.forward(((shaftLength) / 2) * (brs / 10))

if (brs != 0) {
t.right(90)
}
if (brs == 0) {
t.right(90)
t.forward(shaftLength * (1 / 5))
}
}

//generate the snowflake shaft itself
t.forward(shaftLength * (4 / 5))
generateBranch(branches);
t.left(90)
t.forward(Math.sqrt(shaftLength) / 4)
if (third == 1) generateBranch(branches);
t.forward(Math.sqrt(shaftLength) / 4)
t.left(90)
generateBranch(branches);
t.forward(shaftLength * (4 / 5))
generateBranch(branches)
t.left(90)
t.forward(Math.sqrt(shaftLength) / 4)
if (third == 1) generateBranch(branches);
t.forward(Math.sqrt(shaftLength) / 4)
t.left(90)
generateBranch(branches);


const shaft = t.lines()

//determine number of flake arms
const armNums = ri(3, 5)
bt.rotate(shaft, 90)

//draw multiple shafts based on randomized arm number
for (let x = 0; x < 30; x++) {
//determine random location of 30 snowflakes
var randX = rr(10, 290);
var randY = rr(10, 230);
for (let i = 0; i < armNums; i++) {
bt.rotate(shaft, parseInt(360 / armNums));
bt.originate(shaft)
bt.translate(shaft, [randX, randY])
bt.merge(shaft)
bt.simplify(shaft)
drawLines(shaft, { width: 0.1, stroke: "black" })
}
}

The Toolkit

This is a quick reference sheet. For full documentation refer to this.

For an introduction to Blot check out this guide.

Check out our 38 second trailer for a brief overview of the whole Blot project.

There are three names that provide functionality available in the Blot editor: setDocDimensions, drawLines, and blotToolkit (which can also be referenced as bt).

The first two affect the drawing environment itself, and the blotToolkit is used for creating line drawings.

Environment Affecting

setDocDimensions(width: number, height: number)
drawLines(polylines: [number, number][][])

Modify Polylines

Take and modify polylines in place returns first passed polylines.

These functions are available in the blotToolkit or bt object.

bt.iteratePoints(polylines, (pt, t) => { ... }) // return pt to modify, "BREAK" to split, "REMOVE" to filter out point
bt.scale(polylines, scale : scaleXY | [scaleX, scaleY], ?origin: [ x, y ]) 
bt.rotate(polylines, degrees, ?origin: [ x, y ]) 
bt.translate(polylines, [dx, dy], ?origin: [ x, y ]) 
bt.originate(polylines) // moves center to [0, 0] 
bt.resample(polylines, sampleRate) 
bt.simplify(polylines, tolerance) 
bt.trim(polylines, tStart, tEnd)
bt.merge(polylines)  
bt.join(polylines0, ...morePolylines) 
bt.copy(polylines)
bt.cut(polylines0, polylines1) 
bt.cover(polylines0, polylines1) 
bt.union(polylines0, polylines1)
bt.difference(polylines0, polylines1)
bt.intersection(polylines0, polylines1)
bt.xor(polylines0, polylines1)
bt.offset(polylines, delta, ?ops = { endType, joinType, miterLimit, arcTolerance })

Get Data From Polylines

These functions are available in the blotToolkit or bt object.

// take polylines return other
bt.getAngle(polylines, t: [0 to 1]) // returns angle in degrees
bt.getPoint(polylines, t: [0 to 1]) // returns point as [x, y]
bt.getNormal(polylines, t: [0 to 1]) // returns normal vector as [x, y]

bt.pointInside(polylines, pt)

bt.bounds(polylines) 
/*
returns { 
  xMin, xMax, 
  yMin, yMax, 
  lt, ct, rt, 
  lc, cc, rc,
  lb, cb, rb,
  width, height
}

l is left
c is center
r is right
t is top
b is bottom

they are arranged in this configuration around the bounding box of the polylines

lt--ct--rt
 |   |   |
lc--cc--rc
 |   |   | 
lb--cb--rb
*/

Generate Polylines

These functions are available in the blotToolkit or bt object.

const myTurtle = new bt.Turtle()
  .forward(distance: number)
  .arc(angle: number, radius: number)
  .goTo( [ x: number, y: number ] ) // move with up/down state
  .jump( [ x: number, y: number ] ) // move but don't draw
  .step( [ dx: number, dy: number ] ) // add delta to turtles current position
  .right(angle: number)
  .left(angle: number)
  .setAngle(angle: number)
  .up() // sets drawing to false
  .down() // sets drawing to true
  .copy()
  .applyToPath(fn) // takes (turtlePath) => { }
  .lines() // get copy of the Turtle's path

// data
const position = myTurtle.pos // [x: number, y: number]
const angle = myTurtle.angle // number
const path = myTurtle.path // is array of polylines [number, number][][]
const drawing = myTurtle.drawing // boolean
bt.catmullRom(points, ?steps = 1000) // returns polyline [number, number][]
bt.nurbs(points, ?ops = { steps: 100, degree: 2}) // returns polyline [number, number][]

Randomness

These functions are available in the blotToolkit or bt object.

bt.rand();

bt.randInRange(min: number, max: number);

bt.randIntInRange(min: number, max: number); 

bt.setRandSeed(seed: number);

bt.noise(
  number | [ x:number , ?y: number , ?z: number ], 
  { 
    octaves: number [0 to 8], 
    falloff: number [0 to 100] 
  }
);

Idioms

These are small useful code snippets.

function centerPolylines(polylines, documentWidth, documentHeight) {
  const cc = bt.bounds(polylines).cc;
  bt.translate(polylines, [documentWidth / 2, documentHeight / 2], cc);
}