// ----- setup ----- // var illoElem = document.querySelector('.illo'); var sceneSize = 96; var TAU = Zdog.TAU; var ROOT3 = Math.sqrt(3); var ROOT5 = Math.sqrt(5); var PHI = ( 1 + ROOT5 ) / 2; var isSpinning = true; var viewRotation = new Zdog.Vector(); var displaySize; // colors var eggplant = '#636'; var garnet = '#C25'; var orange = '#E62'; var gold = '#EA0'; var yellow = '#ED0'; var illo = new Zdog.Illustration({ element: illoElem, scale: 8, resize: 'fullscreen', onResize: function( width, height ) { displaySize = Math.min( width, height ); this.zoom = Math.floor( displaySize / sceneSize ); }, }); var solids = []; // ----- hourglass ----- // ( function() { var hourglass = new Zdog.Anchor({ addTo: illo, translate: { x: 0, y: -4 }, }); solids.push( hourglass ); var hemi = new Zdog.Hemisphere({ diameter: 2, translate: { z: -1 }, addTo: hourglass, color: garnet, backface: orange, stroke: false, }); hemi.copy({ translate: { z: 1 }, rotate: { y: TAU/2 }, color: eggplant, backface: gold, }); })(); // ----- sphere ----- // ( function() { var sphere = new Zdog.Anchor({ addTo: illo, translate: { x: -4, y: -4 }, }); solids.push( sphere ); var hemi = new Zdog.Hemisphere({ diameter: 2, addTo: sphere, color: orange, backface: eggplant, stroke: false, }); hemi.copy({ rotate: { y: TAU/2 }, color: eggplant, backface: orange, }); })(); // ----- cylinder ----- // var cylinder = new Zdog.Cylinder({ diameter: 2, length: 2, addTo: illo, translate: { x: 4, y: -4 }, // rotate: { x: TAU/4 }, color: gold, backface: garnet, stroke: false, }); solids.push( cylinder ); // ----- cone ----- // var cone = new Zdog.Anchor({ addTo: illo, translate: { x: -4, y: 0 }, }); solids.push( cone ); new Zdog.Cone({ diameter: 2, length: 2, addTo: cone, translate: { z: 1 }, rotate: { y: TAU/2 }, color: garnet, backface: gold, stroke: false, }); // ----- tetrahedron ----- // ( function() { var tetrahedron = new Zdog.Anchor({ addTo: illo, translate: { x: 0, y: 0 }, scale: 2.5, }); var radius = 0.5; var inradius = Math.cos( TAU/6 ) * radius; var height = radius + inradius; solids.push( tetrahedron ); var triangle = new Zdog.Polygon({ sides: 3, radius: radius, addTo: tetrahedron, translate: { y: height/2 }, fill: true, stroke: false, color: eggplant, // backface: false, }); for ( var i=0; i < 3; i++ ) { var rotor1 = new Zdog.Anchor({ addTo: tetrahedron, rotate: { y: TAU/3 * -i }, }); var rotor2 = new Zdog.Anchor({ addTo: rotor1, translate: { z: inradius, y: height/2 }, rotate: { x: Math.acos(1/3) * -1 + TAU/4 }, }); triangle.copy({ addTo: rotor2, translate: { y: -inradius }, color: [ gold, garnet, orange ][i], }); } triangle.rotate.set({ x: -TAU/4, z: -TAU/2 }); })(); // ----- octahedron ----- // ( function() { var octahedron = new Zdog.Anchor({ addTo: newcanvas, translate: { x: -4, y: 4 }, scale: 1.75, }); var colorWheel = [ eggplant, garnet, orange, gold, yellow ]; // radius of triangle with side length = 1 var radius = ROOT3/2 * 2/3; var height = radius * 3/2; var tilt = Math.asin( 0.5 / height ); [ -1, 1 ].forEach( function( ySide ) { for ( var i=0; i < 4; i++ ) { var rotor = new Zdog.Anchor({ addTo: octahedron, rotate: { y: TAU/4 * (i + 1.5) * -1 }, }); var anchor = new Zdog.Anchor({ addTo: rotor, translate: { z: 0.5 }, rotate: { x: tilt * ySide }, // scale: { y: -ySide }, }); new Zdog.Polygon({ sides: 3, radius: radius, addTo: anchor, translate: { y: -radius/2 * ySide }, scale: { y: ySide }, stroke: false, fill: true, color: colorWheel[ i + 0.5 + 0.5*ySide ], backface: false, }); } }); })(); // ----- cube ----- // var cube = new Zdog.Box({ addTo: illo, width: 2, height: 2, depth: 2, translate: { x: 4, y: 0 }, topFace: yellow, frontFace: gold, leftFace: orange, rightFace: orange, rearFace: garnet, bottomFace: eggplant, stroke: false, }); solids.push( cube ); // ----- dodecahedron ----- // ( function() { var dodecahedron = new Zdog.Anchor({ addTo: illo, translate: { x: 0, y: 4 }, scale: 0.75, }); solids.push( dodecahedron ); // https://en.wikipedia.org/wiki/Regular_dodecahedron#Dimensions var midradius = ( PHI * PHI ) / 2; // top & bottom faces var face = new Zdog.Polygon({ sides: 5, radius: 1, addTo: dodecahedron, translate: { y: -midradius }, rotate: { x: TAU/4 }, fill: true, stroke: false, color: yellow, // backface: false, }); face.copy({ translate: { y: midradius }, rotate: { x: -TAU/4 }, color: eggplant, }); [ -1, 1 ].forEach( function( ySide ) { var colorWheel = { '-1': [ eggplant, garnet, gold, orange, garnet ], 1: [ yellow, gold, garnet, orange, gold ], }[ ySide ]; for ( var i=0; i < 5; i++ ) { var rotor1 = new Zdog.Anchor({ addTo: dodecahedron, rotate: { y: TAU/5 * (i) }, }); var rotor2 = new Zdog.Anchor({ addTo: rotor1, rotate: { x: TAU/4*ySide - Math.atan(2) }, }); face.copy({ addTo: rotor2, translate: { z: midradius }, rotate: { z: TAU/2 }, color: colorWheel[i], }); } }); })(); // ----- isocahedron ----- // ( function() { var isocahedron = new Zdog.Anchor({ addTo: illo, translate: { x: 4, y: 4 }, scale: 1.2, }); solids.push( isocahedron ); // geometry // radius of triangle with side length = 1 var faceRadius = ROOT3/2 * 2/3; var faceHeight = faceRadius * 3/2; var capApothem = 0.5 / Math.tan( TAU/10 ); var capRadius = 0.5 / Math.sin( TAU/10 ); var capTilt = Math.asin( capApothem / faceHeight ); var capSagitta = capRadius - capApothem; var sideTilt = Math.asin( capSagitta / faceHeight ); var sideHeight = Math.sqrt( faceHeight*faceHeight - capSagitta*capSagitta ); // var colorWheel = [ eggplant, garnet, orange, gold, yellow ]; [ -1, 1 ].forEach( function( ySide ) { var capColors = { '-1': [ garnet, gold, yellow, gold, orange ], 1: [ gold, garnet, eggplant, garnet, orange ], }[ ySide ]; var sideColors = { '-1': [ garnet, gold, yellow, orange, garnet ], 1: [ gold, garnet, eggplant, orange, orange ], }[ ySide ]; for ( var i=0; i < 5; i++ ) { var rotor = new Zdog.Anchor({ addTo: isocahedron, rotate: { y: TAU/5 * -i }, translate: { y: sideHeight/2 * ySide }, }); var capRotateX = -capTilt; var isYPos = ySide > 0; capRotateX += isYPos ? TAU/2 : 0; var capAnchor = new Zdog.Anchor({ addTo: rotor, translate: { z: capApothem * ySide }, rotate: { x: capRotateX }, }); // cap face var face = new Zdog.Polygon({ sides: 3, radius: faceRadius, addTo: capAnchor, translate: { y: -faceRadius/2 }, stroke: false, fill: true, color: capColors[i], // backface: false, }); var sideRotateX = -sideTilt; sideRotateX += isYPos ? 0 : TAU/2; var sideAnchor = capAnchor.copy({ rotate: { x: sideRotateX }, }); face.copy({ addTo: sideAnchor, translate: { y: -faceRadius/2 }, rotate: { y: TAU/2 }, color: sideColors[i] }); } }); })(); // -- animate --- // var keyframes = [ { x: 0, y: 0 }, { x: 0, y: TAU }, { x: TAU, y: TAU }, ]; var ticker = 0; var cycleCount = 180; var turnLimit = keyframes.length - 1; function animate() { update(); illo.renderGraph(); requestAnimationFrame( animate ); } animate(); function update() { if ( isSpinning ) { var progress = ticker / cycleCount; var tween = Zdog.easeInOut( progress % 1, 4 ); var turn = Math.floor( progress % turnLimit ); var keyA = keyframes[ turn ]; var keyB = keyframes[ turn + 1 ]; viewRotation.x = Zdog.lerp( keyA.x, keyB.x, tween ); viewRotation.y = Zdog.lerp( keyA.y, keyB.y, tween ); ticker++; } solids.forEach( function( solid ) { solid.rotate.set( viewRotation ); }); illo.updateGraph(); } // ----- inputs ----- // var dragStartRX, dragStartRY; new Zdog.Dragger({ startElement: illoElem, onDragStart: function() { isSpinning = false; dragStartRX = viewRotation.x; dragStartRY = viewRotation.y; }, onDragMove: function( pointer, moveX, moveY ) { viewRotation.x = dragStartRX - ( moveY / displaySize * TAU ); viewRotation.y = dragStartRY - ( moveX / displaySize * TAU ); }, });