Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ 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

Save Automatically?

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", 1024, 768, black, black, {font:"Reuben", src:"https://assets.codepen.io/2104200/Reuben.otf"});
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
	const stage = frame.stage;
	const stageW = frame.width;
	const stageH = frame.height;

	// REFERENCES for ZIM at https://zimjs.com
	// see https://zimjs.com/intro.html for an intro example
	// see https://zimjs.com/learn.html for video and code tutorials
	// see https://zimjs.com/docs.html for documentation
	// see https://codepen.io/topic/zim/ for ZIM on CodePen
	
	// *** NOTE: ZIM Cat defaults to time in seconds
	// All previous versions, examples, videos, etc. have time in milliseconds
	// This can be set back with TIME = "milliseconds" but we suggest you give it a try!
	// There will be a warning in the conslole if your animation is not moving ;-)

	// CODE HERE

	const segments = 180; 				// how many lines
	const delta = 360/segments; 		// angle between each line
	const inner = 50; 					// inner radius
	const outer = 300; 					// outer radius
	const variation = outer-inner;	// maximum noise

	let c = 2.5;    // curve factor 
	let s = .05;    // speed factor
	let t = 0;      // time

	const colors = series(red, purple, pink, blue, green, orange, yellow, grey, black, lighter, lighter, black);
	let innerColor = colors(); // each time this is called it returns the next color in the series
	let outerColor = colors();

	// The ZIM Generator() works somewhat like Processing / P5js.
	// Setting stamp instead of draw will draw all generations immediately 
	// rather than one generation at a time.
	const g = new Generator({
		stamp:gen,
		strokeWidth:5,
		maxCount:segments,
		startY:stageH/2+30 // move it down a little to handle title
	});
	function gen(count) {  
		let angle = delta*count*RAD;  // (0-360 degrees in radians)

		// NOISE
		// Noise returns a value along a Simplex Noise equation.
		// Noise will give the same value if you give it the same inputs.
		// For instance noise(1,2,3) will always equal noise(1,2,3) - for a given Noise seed. 
		// A random seed is set when the Generator is made.  
		// There is a seed parameter if a specific seed is desired.

		// The Noise equation is static for a given seed - it does not change.
		// You can imagine it like a wiggly line for 1D noise. 
		// When you change the first parameter it moves along the wiggly line 
		// and the height of the wiggly line is the return result. 
		// For ZIM Noise() this is between -1 and 1. 
		// For Generator() noise() this is between 0 and 1.
		// Smaller parameter changes will mean smaller differences in results 
		// because you are not moving very far along the wiggly line each time.
		// Larger parameter changes will mean larger differences in results 
		// because you are moving farther along the wiggly line each time.
		// You can think of it as zooming in and out on the wiggly line.
		// Zoom in and it looks smoother, zoom out and it looks less smooth.

		// 2D noise can be thought of in two ways.
		// 1. a wiggly line that is moving with the second parameter how fast it moves. 
		// 2. a wiggly plane that is not moving.
		// In this case, the wiggly plane might be best - like a wiggly blanket.        
		// For 3D noise, think of it as a wiggly plane moving in time like the surface of a stream
		// Smaller third parameter changes will result in a slower moving stream 
		// Larger third parameter changes will result in a faster moving stream 

		// The noise is providing the length of each line 
		// which acts like the blob radius as we rotate each line by delta below.
		// We want these to look continuous at the seam where the lines start (0) and end (360).
		// The angle will go from 0 to 360 because gen() is run by the Generator for each segment (maxCount). 
		// Luckily, sin and cos will give numbers that repeat every 360 degrees 
		// so they are perfect for sending in to noise to match at the seam.
		// If we passed in only the sin, then we would see a mirrored blob 
		// about the vertical axis - or cos would be about the horizontal axis.
		// This is because the values go from -1 to 1 
		// effectively going forwards and backwards through the noise repeating the values.
		// The amplitude of 1 will lead to a specific curviness - but we change that with the C Dial.

		// DIAL C (curve)
		// We multiply the sin and cos by c to allow us to change the curve amount
		// Smaller c values will be smoother as we do not move as much in the noise equation 
		// and larger will be more bumpy as we move more along the noise equation each time.

		// DIAL S (speed)
		// In the Ticker function we constantly call restamp().
		// restamp() runs this gen() function for each line. 
		// We pass t into the the third parameter of the noise equation.
		// We can think of t as time and t is being increased by s each restamp().
		// If s is bigger then time (t) changes more quickly and we move farther along the noise equation 
		// which animates the blob faster.
		// If s is smaller time (t) goes slower and if s is negative it goes backwards!
		// We set the dial to go from negative (at left) to positive (at right) so we can see this cool effect.
		// s is zero at the top of the dial - so t does not change 
		// and therefore the blob just stays the same.
		// Using the Speed dial, we can scrub back and forth along the noise equation - very cool!

		let noise = g.noise(c*Math.sin(angle), c*Math.cos(angle), t);
		let radius = inner+variation*noise;
		g.push() // remember the starting position
				.stroke(innerColor)
				.line(0,0,radius,0)
				.stroke(outerColor)
				.line(0,0,outer-radius,0)
		  .pop() // go back to the starting position
		  .rotate(delta); // rotate delta each time
	}

	Ticker.add(()=>{
		t+=s; // set the speed through the noise
		g.restamp();
	});
	// g.drawing.drag();

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// DIALS

	STYLE = {        
		step:0, 
		useTicks:true,
		tickColor:purple,
		tickStep:series(.01,.5)
	}

	const speed = new Dial({min:-.1, max:.1, currentValue:s})
		.pos(120,60,LEFT,BOTTOM)
		.rot(180)
		.change(()=>{s = speed.currentValue;});

	const curve = new Dial({min:0, max:10, step:0, currentValue:c})
		.pos(120,60,RIGHT,BOTTOM)
		.change(()=>{c = curve.currentValue;});

	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// HOODS AND TITLES

	const borderColor = purple.darken(.6);
	const borderWidth = 3;
	STYLE = {
		font:"Reuben",
		color:tin,
		align:CENTER,
		valign:CENTER,
		size:50,
		dashed:true,
		backing:new Circle(35, darker, borderColor, borderWidth),
		letterSpacing:0
	}

	const hood = new Circle(outer+45, darker)        
		.pos(0,30,CENTER,CENTER)
		.animate({
			props:{percent:0},
			time:2,
			wait:.2
		});   
	// backing    
	hood.clone().addTo().bot().tap(()=>{
		hood.animate({
			props:{percent:100},
			time:1.5,                
			rewindWait:.1,
			rewind:true,
			rewindCall:()=>{
				innerColor = colors();
				outerColor = colors();
			}
		})
	});     
	new LabelOnArc({
		label:"BLOOB",         
		radius:outer+40
	}).center().mov(0,40).bot();        

	const speedHood = new Circle(speed.width/2+50, darker)        
		.loc(speed)
		.rot(-30)
		.animate({
			props:{percent:0},
			time:2,
			wait:.8
		});        
	speedHood.clone().addTo().bot();
	const speedLabel = new LabelOnArc({
		label:"S", 
		radius:speedHood.radius-10
	}).loc(speedHood).bot().rot(-30);
	

	const curveHood = new Circle(curve.width/2+50, darker)        
		.loc(curve)
		.rot(30)
		.animate({
			props:{percent:0},
			time:2,
			wait:1.2
		});        
	curveHood.clone().addTo().bot();
	const curveLabel = new LabelOnArc({
		label:"C", 
		radius:curveHood.radius-10
	}).loc(curveHood).bot().rot(30);


	STYLE = {
		size:18,
		backgroundColor:grey,
		corner:5,
		color:light,
		align:series(LEFT,RIGHT),
		valign:CENTER
	}
	speedLabel.on(mobile()?"mousedown":"mouseover", ()=>{
		speedTip.show(0,1).mov(0,90);
		stage.update();
	});
	const speedTip = new Tip("SPEED");
	curveLabel.on(mobile()?"mousedown":"mouseover", ()=>{
		curveTip.show(0,1).mov(0,90);
		stage.update();
	});
	const curveTip = new Tip("CURVE");

	// Backing borders
	const hoodBack = hood.clone().addTo().bot();
	hoodBack.radius += borderWidth;
	hoodBack.color = borderColor;

	const speedHoodBack = speedHood.clone().addTo().bot();
	speedHoodBack.radius += borderWidth;
	speedHoodBack.color = borderColor;

	const curveHoodBack = curveHood.clone().addTo().bot();
	curveHoodBack.radius += borderWidth;
	curveHoodBack.color = borderColor;
	
	STYLE = {}


	// g.drawing.centerReg().animate({
	//     props:{rotation:360},
	//     time:50,
	//     loop:true,
	//     ease:"linear"
	// })

	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=Circle
	// https://zimjs.com/docs.html?item=LabelOnArc
	// https://zimjs.com/docs.html?item=Tip
	// https://zimjs.com/docs.html?item=Dial
	// https://zimjs.com/docs.html?item=tap
	// https://zimjs.com/docs.html?item=change
	// https://zimjs.com/docs.html?item=drag
	// https://zimjs.com/docs.html?item=animate
	// https://zimjs.com/docs.html?item=pos
	// https://zimjs.com/docs.html?item=loc
	// https://zimjs.com/docs.html?item=mov
	// https://zimjs.com/docs.html?item=bot
	// https://zimjs.com/docs.html?item=alp
	// https://zimjs.com/docs.html?item=rot
	// https://zimjs.com/docs.html?item=addTo
	// https://zimjs.com/docs.html?item=centerReg
	// https://zimjs.com/docs.html?item=center
	// https://zimjs.com/docs.html?item=Generator
	// https://zimjs.com/docs.html?item=series
	// https://zimjs.com/docs.html?item=Noise
	// https://zimjs.com/docs.html?item=darken
	// https://zimjs.com/docs.html?item=zog
	// https://zimjs.com/docs.html?item=STYLE
	// https://zimjs.com/docs.html?item=Ticker

	frame.madeWith(grey, null, null, black)
		.pos(80,50,RIGHT,TOP)
		.alp(0)
		.sca(1.2)
		.animate({
			wait:3,
			props:{alpha:.8}
		})

}); // end of ready
              
            
!
999px

Console