Pen Settings



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


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


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.


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.






                // Using a Frame for animation and a Frame for interface
// so animation does not have to update interface
// Storing data outside the Frame calls so both Frames can use it

const data = {
	curve:.5,     // curve factor 
	speed:.02,    // speed factor
	delay:.03     // delay of pattern between rings

// ~~~~~~~ Rings animation Frame

const scaling = "outside"; // this will resize to fit outside the screen dimensions
const width = 1024;
const height = 768;
const color = black;
const outerColor = black;

// turning off rollovers and press events (last false, false)
const frame = new Frame(scaling, width, height, color, outerColor, null, null, null, false, false);
frame.on("ready", 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;

	// see for an intro example
	// see for video and code tutorials
	// see for documentation
	// see 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 ;-)

	// rings are made with little lines in a ring
	const segments = 180; // how many lines
	const delta = 360/segments; // angle for each line
	const inner = 50; // inner radius - multiplied by 2 at largest ring, etc.
	const outer = 200; // outer radius
	const variation = outer-inner; // maximum noise        
	const colors = series(green, blue, yellow, orange, red, purple);
	let time = 0; 

	// 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
	// and then we will call restamp() in a Ticker to animate patterns
	var g = new Generator({

	// Generator lines do not fill (Generator shapes do)
	// so send info to Shape objects on stage
	var shapes = [];
	loop(6, i=>{
		shapes.push(new Shape(stageW, stageH).addTo());

	function gen(count) {  
		let angle = delta*count*RAD;  // (0-360 degrees in radians)   
		loop(6, i=>{
			let noise = g.noise(data.curve*Math.sin(angle), data.curve*Math.cos(angle), time+i*data.delay);
			let radius = inner+variation*noise;
			// find global position of generator 
			let p = g.drawing.localToGlobal(g.currentX, g.currentY);   
			// if first time then start the drawing otherwise draw line     
			if (count==1) shapes[i].c().f(colors()).mt(p.x, p.y);
			else shapes[i].lt(p.x, p.y); 
		g.rotate(delta); // rotate delta each time              

	Ticker.add(function () {
		time += data.speed; // set the speed through the noise equation

}); // end of ready

// ~~~~~~~ Interface animation Frame

// will go with full mode (default Frame)
// so interface can be anchored to the bottom 
// as other Frame is outside which takes whole window

const frame2 = new Frame();
frame2.on("ready", ()=>{
	frame2.setDefault(); // so center() etc. defaults to this stage rather than the first Frame stage
	const stage = frame2.stage;
	let stageW = frame2.width; // stageW and stageH change in the resize event
	let stageH = frame2.width;    

	// make interfaces then Tile them 
	// could use a Button with an arrow Icon Triangle and Toggle Icon Triangle
	// but it is as easy to just rotate a Triangle - as long as we do not care about rollover	
	const toggle = new Triangle(70,70,70,grey) 
			// could add 180 each time but we use the rotation to determine the toggle state
			toggle.rotation = toggle.rotation==90?-90:90;  
			// animate in or out the objects in the components array with a sequence
			// we want the farthest one to start (last in tile) so reverse the order
	// List has some compact interface combinations so use the slider 
	// these are stored right on the list as static methods
	// label, min, max, val, call, step, obj, property, paddingLeft, paddingRight, factor, offset
	const curveSlider = List.slider("Curve", 0, 2, .5, null, null, data, "curve", 50, null, 5);
	const speedSlider = List.slider("Speed", -.05, .05, .02, .001, null, data, "speed", 50, null, 200);
	const delaySlider = List.slider("Delay", 0, .1, .03, null, null, data, "delay", 50, null, 100);
	const icon = frame.makeIcon(null,black).sca(.9).tap(()=>{zgo("", "_blank")});
	const components = [toggle, curveSlider, speedSlider, delaySlider, icon];
	STYLE = {valign:CENTER}; // for centering height of Triangle
	const panel = new Tile(components, 5, 1, 40, 0, true).sca(.3);
	STYLE = {};
	components.shift(); // remove arrow from array (so we do not animate it out on tap)

	frame2.on("resize", ()=>{
		panel.scaleTo(stage, 95);
		// like setting minWidth and maxWidth styles 
		// remember to assign results of constrain back
		panel.width = constrain(panel.width, 300, 700);