HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
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.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
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.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
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.
Using packages here is powered by esm.sh, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ESM usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
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
Also see: Tab Triggers