Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

Auto Save

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                
              
            
!

CSS

              
                
              
            
!

JS

              
                const frame = new Frame("fit", 500, 500, "#ddd", "#111");
frame.on("ready", ()=>{ // ES6 Arrow Function - similar to function(){}
    zog("ready from ZIM Frame"); // logs in console (F12 - choose console)

    // often need below - so consider it part of the template
    let stage = frame.stage;
    let stageW = frame.width;
    let stageH = frame.height;

    // REFERENCES for ZIM at http://zimjs.com
    // see http://zimjs.com/learn.html for video and code tutorials
    // see http://zimjs.com/docs.html for documentation
    // see https://www.youtube.com/watch?v=pUjHFptXspM for INTRO to ZIM
    // see https://www.youtube.com/watch?v=v7OT0YrDWiY for INTRO to CODE

    // CODE HERE
   
    // DEDICATION
    // this code is dedicated to Jared Tarbell
    // http://www.complexification.net/gallery/machines/substrate/
    // who did much more sublime versions
    // this is my first crack at it - would like to experiment more!

    // BLITTING
    // create a ZIM Shape to draw vectors into
    // cache this and create a Bitmap from the cacheCanvas
    // this Bitmap is what we see
    // we will be constantly drawing in a Ticker (powered by RequestAnimationFrame)
    // we will update the cache with source-over when we change the drawing
    // this allows us to make vectors and paste them on to the Bitmap
    // then we clear the vectors as they have just been copied to the Bitmap
    // this system is called Blitting
    // it allows us to make many vectors over time
    // but only keep a few in memory at any given time!
    const shape = new Shape();
    shape.cache(stageW, stageH);
    const blit = new Bitmap(shape.cacheCanvas).addTo();

    // We will make Line objects and draw them over time
    // We will keep a grid that matches the x, y pixels of the stage
    // This will be calculated by the y*stageW+x
    // so when y is 0, then the top row matches the x
    // When y is 1 then the next row will start at the stageW and then add x
    // It is just a way to use a single array rather than a nested array
    // In the grid array, we will store a reference to the line
    // that makes a pixel at the x and y position in the grid
    // We will use this data:
    //      1. to find out if lines are hitting other lines
    //      2. to start a new line perpendicular to an existing line
    //      3. fill our shading into the empty space between lines

    const lines = [];
    const grid = [];
    const colors = [green,blue,pink,orange,brown,grey];
    const speed = .6;
    const startLines = 10;

    // still using ES5 class - ES6, I would like private variables please!
    function Line(startX, startY, angle) {
        // if this line hits another line we will stop drawing it
        let draw = true;
        let x = startX;
        let y = startY;
        // a handy way to get a random color for the
        let color = shuffle(colors)[0];
        // inside any private methods we will need to use that (no need in ES6)
        let that = this;
        // we will need a public angle for when we start new line perpendicular to this line
        this.angle = angle;

        // this method gets called in the Ticker outside the class
        let colorCount = 0;
        this.move = function() {
            if (!draw) return;
            // here is how we move along an angle
            x+=speed*Math.cos(angle*Math.PI/180);
            y+=speed*Math.sin(angle*Math.PI/180);
            // find out the index of our grid based on the x and y
            let index = Math.floor(y)*stageW+Math.floor(x);
            // check to see if we are in range of the stage
            if (index >= 0 && index < stageW*stageH) {
                // check to see if there is a line
                // this was just check the grid at the index
                // but found lines would sometimes go through lines
                // so did a neighboring check - see checkForLines function below
                if (checkForLine(x,y)) {
                    draw = false; // stop our current line
                    startLine(); // start another line
                } else {
                    // record that our line is at this index in the grid
                    grid[index]=this;
                }
            } else { // we have gone off the stage
                draw = false;
                startLine();
            }
            this.regionColor();
            let fuzzX = rand(-.3,.3); // or set to 0 ;-)
            let fuzzY = rand(-.3,.3);
            // draw our line into the graphics of the shape - use a little rectangle
            // s() is short for beginStroke and dr() is short for drawRect()
            // this rectangle is a vector and remembered as such
            // until the graphics is cleared - see the Ticker function
            shape.graphics.s("rgba(0,0,0,.2)").dr(x+fuzzX,y+fuzzY,.5,.5);
        }

        // found checking for a single pixel sometimes lets lines go through lines
        // built this loop to check the central pixel and each pixel around it
        // so 9 pixels - but then just checking a 4 pixel box seems to work
        function checkForLine(x,y,num=2) {
            let half = Math.floor(num/2);
            // ZIM loop() is like a for loop but calls a function each loop
            // so there is no continue and no break
            // instead, a return is a continue and a return value is a break
            // and the returned value is the return value for the loop() function
            // if no value is returned, the return value is undefined
            // SO... the inner loop will return a value of true if we are hitting
            // this gets assigned to the result variable in the outer loop
            // and if the result is true then we return true for the outer loop
            // which returns the value for the checkForLine function
            return loop(num, i=>{
                let result = loop(num, j=>{
                    let index = Math.floor(y+i-half)*stageW+Math.floor(x+j-half);
                    if (grid[index] && grid[index] != that) return true;
                });
                if (result) return true;
            });

            // Here is the code for above done with a for loop
            // 70 characters longer...
            // let hitting = false;
            // outer: for (let i=0; i<num; i++) {
            //     for (let j=0; j<num; j++) {
            //         let index = Math.floor(y+i-half)*stageW+Math.floor(x+j-half);
            //         if (grid[index] && grid[index] != that) hitting = true;
            //         break outer;
            //     }
            // }
            // return hitting;
        }

        // this method draws the shading the extends out from the line
        // and goes until it hits another line
        this.regionColor = function() {
            // x and y are the current point of our line
            // rx and ry will be moving perpendicular to our current line
            let rx = x;
            let ry = y;
            let openspace = true;
            // we need to keep the distance for the check small
            // but we don't need to draw a rect each check
            // as they would overlap and make the alpha bigger
            // so we will draw every third time - that's what count is for
            let count = 0;
            while (openspace) {
                // similar technique as detecting if lines are hitting in the move method
                let index = Math.floor(ry)*stageW+Math.floor(rx);
                if (index >= 0 && index < stageW*stageH) {
                    // the modulus % will be 0 each time count is divisible by 3
                    if (++count%3==0) shape.graphics
												.s(convertColor(color, "rgba", .15))
												.dr(rx,ry,1,1);
                    if (checkForLine(rx,ry)) openspace=false;
                } else {
                    openspace=false;
                }
                // move perpendicular to crack
                // note that we have swapped the sin and cos and the - for the y
                rx+=speed*Math.sin(angle*Math.PI/180);
                ry-=speed*Math.cos(angle*Math.PI/180);
            }
        }
    }

    // create start lines - set different number at top...
    loop(startLines, (i,t)=>{
        lines.push(new Line(rand(stageW), rand(stageH), rand(360)));
    });

    function startLine() {
        // look for another line
        let line = loop(5000, i=>{
            // get a random index of the grid
            let r = rand(0,grid.length-1);
            if (grid[r]) {
                // if a line is there then return a special array
                // this exits this loop and gives the array to the variable loop
                // the special array holds the x, y and angle for a new line
                // we now need to work backwards to turn an index to x and y values
                // for the x we take the remainder (modulus %) of how many are in each row (stageW)
                // for the y we floor the index divided by how many are in the row
                // this is standard for going from a linear to an x,y grid
                // just try out some numbers and see how it works!
                // the angle is the angle of the line we hit +- 90 degrees plus a little skew
                // we use the ternary operator to assign either 90 or -90
                // depending on if rand() is greater than .5 (half the time)
                return [
                    r%stageW, // working backwards to turn index into x
                    Math.floor(r/stageW), // and into y
                    grid[r].angle+(rand()>.5?-90:90)+rand(-4,4) // perpendicularish
                ];
            }
        });
        // if we came up with an existing line then add a new line
        // use the ES6 spread to add the three array elements as three parameters
        if (line!=null) lines.push(new Line(...line));
    }

    // this happens 60 frames per second (30 on mobile)
    // set with Ticker.setFPS()
    const ticker = Ticker.add(()=>{
        // move each line with its method
        loop(lines, line=>{
            line.move();
        });
        // stamp current shape vectors onto cache
        // the cache is read automatically by the Bitmap and viewed
        shape.updateCache("source-over");
        // clear the vectors from memory now that they are blitted to bitmap
        shape.graphics.c();
    });

    // pause the drawing when stage is clicked on
    stage.on("stagemousedown", ()=>{
        if (Ticker.has(ticker)) Ticker.remove(ticker);
        else Ticker.add(ticker);
    });

    new Label({
			text:"DEDICATED TO JARED TARBELL", 
			size:14, 
			color:white, 
			outlineColor:blue, 
			outlineWidth:2
		})
        .alp(.6)
        .pos(20,20,false,true)
        .cache()
	
    stage.update(); // this is needed to show any changes
  
    // DOCS FOR ITEMS USED
		// https://zimjs.com/docs.html?item=Frame
		// https://zimjs.com/docs.html?item=Shape
		// https://zimjs.com/docs.html?item=Bitmap
		// https://zimjs.com/docs.html?item=Label
		// https://zimjs.com/docs.html?item=mov
		// https://zimjs.com/docs.html?item=loop
		// https://zimjs.com/docs.html?item=pos
		// https://zimjs.com/docs.html?item=alp
		// https://zimjs.com/docs.html?item=addTo
		// https://zimjs.com/docs.html?item=shuffle
		// https://zimjs.com/docs.html?item=rand
		// https://zimjs.com/docs.html?item=loop
		// https://zimjs.com/docs.html?item=zog
		// https://zimjs.com/docs.html?item=Ticker
  
}); // end of ready
              
            
!
999px

Console