├── Makefile ├── .gitignore ├── .jshintrc ├── README.md ├── demo ├── happy-town │ ├── hedge.js │ ├── lil-pyramid.js │ ├── index.html │ └── make-building.js ├── santorini │ ├── make-window.js │ ├── index.html │ ├── make-rock.js │ ├── buildings.js │ ├── make-building.js │ └── santorini.js ├── curves │ ├── index.html │ └── curves.js ├── solid-shifter │ ├── solid-shifter.js │ ├── index.html │ └── shifter.js ├── madeline │ ├── bokeh-shape.js │ ├── index.html │ ├── make-bird.js │ ├── madeline.js │ └── make-madeline.js ├── fps-counter.js ├── translate-rotate │ ├── index.html │ └── translate-rotate.js ├── castle │ ├── index.html │ └── castle.js ├── tri-prism │ ├── index.html │ └── tri-prism.js ├── patties │ ├── patties.js │ └── index.html ├── truck-flight │ ├── index.html │ └── truck-flight.js ├── cones │ ├── index.html │ └── cones.js ├── codepen-logo │ ├── index.html │ └── codepen-logo.js ├── sauropod │ ├── index.html │ └── sauropod.js ├── crypto-kitty │ ├── index.html │ └── crypto-kitty.js ├── mario │ ├── index.html │ └── mario.js ├── mega-man │ ├── index.html │ └── mega-man.js ├── shade-and-shades │ ├── index.html │ └── shade-and-shades.js ├── bird-house │ ├── index.html │ └── bird-house.js ├── hemisphere-ball │ ├── index.html │ └── hemisphere-ball.js ├── template │ ├── demo.js │ └── index.html ├── inside-house │ ├── index.html │ └── inside-house.js ├── rgb-birdie │ ├── index.html │ └── rgb-birdie.js ├── gear-icon │ ├── index.html │ └── gear-icon.js ├── cylinders │ ├── index.html │ └── cylinders.js ├── la-link │ ├── index.html │ └── la-link.js ├── strutter │ ├── index.html │ └── strutter.js ├── composite-shapes-scale-svg │ ├── index.html │ └── composite-shapes-scale-svg.js ├── composite-shapes-scale │ ├── index.html │ └── composite-shapes-scale.js ├── fizzy-bear │ └── index.html ├── little-forest │ └── index.html ├── unpkg-explode │ ├── index.html │ └── unpkg-explode.js └── davey-nippu │ └── index.html └── package.json /Makefile: -------------------------------------------------------------------------------- 1 | lint: 2 | npx jshint demo/**/*.js 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "browser": true, 3 | "unused": true, 4 | "undef": true, 5 | "globals": { 6 | "Zdog": false 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zdog demos 2 | 3 | _Bigger, wilder Zdog demos_ 4 | 5 | View complete Zdog documentation and live demos at [zzz.dog](https://zzz.dog). 6 | 7 | ## Install 8 | 9 | ``` bash 10 | npm install 11 | ``` 12 | 13 | Then view `demo/*/index.html` in your browser. 14 | -------------------------------------------------------------------------------- /demo/happy-town/hedge.js: -------------------------------------------------------------------------------- 1 | /* globals navy */ 2 | 3 | window.hedge = function( options ) { 4 | var anchor = new Zdog.Anchor({ 5 | addTo: options.addTo, 6 | translate: options.translate, 7 | }); 8 | 9 | var ball = new Zdog.Shape({ 10 | path: [ { y: 0 }, { y: -1 } ], 11 | addTo: anchor, 12 | translate: { y: -2.5 }, 13 | stroke: 5, 14 | color: options.color || navy, 15 | }); 16 | 17 | ball.copy({ 18 | stroke: 4, 19 | translate: { y: -5 }, 20 | }); 21 | 22 | ball.copy({ 23 | stroke: 2.5, 24 | translate: { y: -7.5 }, 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zdog-demos", 3 | "version": "1.0.0", 4 | "description": "Bigger, wilder Zdog demos", 5 | "dependencies": { 6 | "zdog": "^1.1.2" 7 | }, 8 | "devDependencies": { 9 | "jshint": "^2.10.2" 10 | }, 11 | "scripts": { 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "git+https://github.com/metafizzy/zdog-demos.git" 17 | }, 18 | "author": "David DeSandro", 19 | "private": true, 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/metafizzy/zdog-demos/issues" 23 | }, 24 | "homepage": "https://zzz.dog" 25 | } 26 | -------------------------------------------------------------------------------- /demo/happy-town/lil-pyramid.js: -------------------------------------------------------------------------------- 1 | /* globals TAU, navy, red */ 2 | 3 | window.lilPyramid = function( options ) { 4 | var anchor = new Zdog.Anchor({ 5 | addTo: options.addTo, 6 | translate: options.translate, 7 | }); 8 | 9 | var panel = new Zdog.Shape({ 10 | path: [ 11 | { x: 0, y: -3, z: 0 }, 12 | { x: 3, y: 0, z: 0 }, 13 | { x: 0, y: 0, z: 3 }, 14 | ], 15 | addTo: anchor, 16 | color: red, 17 | }); 18 | 19 | panel.copy({ 20 | rotate: { y: TAU/4 }, 21 | color: red, 22 | }); 23 | panel.copy({ 24 | rotate: { y: TAU/2 }, 25 | color: navy, 26 | }); 27 | panel.copy({ 28 | rotate: { y: TAU * 3/4 }, 29 | color: navy, 30 | }); 31 | 32 | }; 33 | -------------------------------------------------------------------------------- /demo/santorini/make-window.js: -------------------------------------------------------------------------------- 1 | /*jshint unused: false */ 2 | 3 | function makeWindow( options ) { 4 | if ( options.style == 'circle' ) { 5 | makeCircleWindow( options ); 6 | } else { 7 | makeLongWindow( options ); 8 | } 9 | } 10 | 11 | function makeCircleWindow( options ) { 12 | new Zdog.Ellipse( Zdog.extend( options, { 13 | diameter: 2, 14 | })); 15 | } 16 | 17 | function makeLongWindow( options ) { 18 | var y2 = options.height - 1; 19 | 20 | var windowShape = new Zdog.Shape( Zdog.extend( options, { 21 | path: [ 22 | { x: -1, y: 0 }, 23 | { arc: [ 24 | { x: -1, y: -1 }, 25 | { x: 0, y: -1 }, 26 | ]}, 27 | { arc: [ 28 | { x: 1, y: -1 }, 29 | { x: 1, y: 0 }, 30 | ]}, 31 | { x: 1, y: y2 }, 32 | { x: -1, y: y2 }, 33 | ], 34 | })); 35 | 36 | return windowShape; 37 | } -------------------------------------------------------------------------------- /demo/curves/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | curves 8 | 9 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |

Click & drag to rotate

27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /demo/solid-shifter/solid-shifter.js: -------------------------------------------------------------------------------- 1 | /* globals Shifter */ 2 | 3 | // ----- setup ----- // 4 | 5 | var illoElem = document.querySelector('.illo'); 6 | var illoSize = 10; 7 | var minWindowSize = Math.min( window.innerWidth - 20, window.innerHeight - 20 ); 8 | var zoom = Math.floor( minWindowSize / illoSize ); 9 | illoElem.setAttribute( 'width', illoSize * zoom ); 10 | illoElem.setAttribute( 'height', illoSize * zoom ); 11 | 12 | var illo = new Zdog.Illustration({ 13 | element: illoElem, 14 | zoom: zoom, 15 | dragRotate: true, 16 | }); 17 | 18 | // ----- model ----- // 19 | 20 | var shifterA = new Shifter({ 21 | addTo: illo, 22 | translate: { x: -3 }, 23 | }); 24 | var shifterB = new Shifter({ 25 | addTo: illo, 26 | }); 27 | var shifterC = new Shifter({ 28 | addTo: illo, 29 | translate: { x: 3 }, 30 | }); 31 | 32 | // ----- animate ----- // 33 | 34 | var ticker = 0; 35 | var cycleCount = 80; 36 | 37 | function animate() { 38 | // update 39 | var progress = ticker / cycleCount; 40 | shifterA.update( progress + 4 ); 41 | shifterB.update( progress + 2 ); 42 | shifterC.update( progress + 0 ); 43 | ticker++; 44 | 45 | illo.updateRenderGraph(); 46 | requestAnimationFrame( animate ); 47 | } 48 | 49 | animate(); 50 | 51 | -------------------------------------------------------------------------------- /demo/madeline/bokeh-shape.js: -------------------------------------------------------------------------------- 1 | var BokehShape = Zdog.Shape.subclass({ 2 | bokehSize: 5, 3 | bokehLimit: 64, 4 | }); 5 | 6 | BokehShape.prototype.updateBokeh = function() { 7 | // bokeh 0 -> 1 8 | this.bokeh = Math.abs( this.sortValue ) / this.bokehLimit; 9 | this.bokeh = Math.max( 0, Math.min( 1, this.bokeh ) ); 10 | return this.bokeh; 11 | }; 12 | 13 | BokehShape.prototype.getLineWidth = function() { 14 | return this.stroke + this.bokehSize * this.bokeh * this.bokeh; 15 | }; 16 | 17 | BokehShape.prototype.getBokehAlpha = function() { 18 | var alpha = 1 - this.bokeh; 19 | alpha *= alpha; 20 | return alpha * 0.8 + 0.2; 21 | }; 22 | 23 | BokehShape.prototype.renderCanvasDot = function( ctx ) { 24 | this.updateBokeh(); 25 | ctx.globalAlpha = this.getBokehAlpha(); // set opacity 26 | Zdog.Shape.prototype.renderCanvasDot.apply( this, arguments ); 27 | ctx.globalAlpha = 1; // reset 28 | }; 29 | 30 | BokehShape.prototype.renderPath = function( ctx, renderer ) { 31 | this.updateBokeh(); 32 | // set opacity 33 | if ( renderer.isCanvas ) { 34 | ctx.globalAlpha = this.getBokehAlpha(); 35 | } 36 | Zdog.Shape.prototype.renderPath.apply( this, arguments ); 37 | // reset opacity 38 | if ( renderer.isCanvas ) { 39 | ctx.globalAlpha = 1; 40 | } 41 | }; 42 | -------------------------------------------------------------------------------- /demo/fps-counter.js: -------------------------------------------------------------------------------- 1 | ( function() { 2 | 3 | var outputElem = document.createElement('div'); 4 | outputElem.style.fontFamily = 'monospace'; 5 | outputElem.style.fontSize = '20px'; 6 | outputElem.style.position = 'absolute'; 7 | outputElem.style.top = '10px'; 8 | outputElem.style.left = '10px'; 9 | 10 | var prevTickTime = new Date(); 11 | var prevUpdateTime = new Date(); 12 | 13 | var tickTimeDeltas = []; 14 | 15 | function tick() { 16 | var now = new Date(); 17 | var tickTimeDelta = now - prevTickTime; 18 | tickTimeDeltas.push( tickTimeDelta ); 19 | 20 | var updateTimeDelta = now - prevUpdateTime; 21 | // update every half second 22 | if ( updateTimeDelta > 500 ) { 23 | update( now ); 24 | } 25 | prevTickTime = now; 26 | requestAnimationFrame( tick ); 27 | } 28 | 29 | function update( now ) { 30 | var avgDelta = averageArray( tickTimeDeltas ); 31 | outputElem.textContent = Math.round( 1000 / avgDelta ); 32 | 33 | // reset 34 | tickTimeDeltas = []; 35 | prevUpdateTime = now; 36 | } 37 | 38 | function averageArray( ary ) { 39 | var sum = 0; 40 | var length = ary.length; 41 | for ( var i=0; i < length; i++ ) { 42 | sum += ary[i]; 43 | } 44 | return sum / length; 45 | } 46 | 47 | document.body.appendChild( outputElem ); 48 | tick(); 49 | 50 | })(); 51 | -------------------------------------------------------------------------------- /demo/curves/curves.js: -------------------------------------------------------------------------------- 1 | var illoElem = document.querySelector('.illo'); 2 | var w = 72; 3 | var h = 72; 4 | var zoom = 6; 5 | illoElem.setAttribute( 'width', w * zoom ); 6 | illoElem.setAttribute( 'height', h * zoom ); 7 | // colors 8 | 9 | var illo = new Zdog.Illustration({ 10 | element: illoElem, 11 | zoom: zoom, 12 | dragRotate: true, 13 | }); 14 | 15 | // -- illustration shapes --- // 16 | 17 | // rectangle with curve 18 | new Zdog.Shape({ 19 | path: [ 20 | { x: -6, y: -8 }, 21 | { bezier: [ 22 | { x: 0, y: -12, z: -5 }, 23 | { x: 0, y: -4 }, 24 | { x: 6, y: -8 }, 25 | ]}, 26 | { x: 6, y: 8 }, 27 | { bezier: [ 28 | { x: 0, y: 8, z: -5 }, 29 | { x: 0, y: 8, z: 5 }, 30 | { x: -6, y: 8 }, 31 | ]}, 32 | { x: -6, y: 8 }, 33 | ], 34 | addTo: illo, 35 | stroke: 2, 36 | color: '#19F', 37 | }); 38 | 39 | // quarter circle 40 | new Zdog.Shape({ 41 | path: [ 42 | { x: 10, y: 0 }, 43 | { arc: [ 44 | { x: 20, y: 0 }, 45 | { x: 20, y: 10 } 46 | ]}, 47 | { x: 10, y: 10 } 48 | ], 49 | addTo: illo, 50 | stroke: 2, 51 | color: '#A00', 52 | }); 53 | 54 | // -- animate --- // 55 | 56 | function animate() { 57 | illo.updateRenderGraph(); 58 | requestAnimationFrame( animate ); 59 | } 60 | 61 | animate(); 62 | -------------------------------------------------------------------------------- /demo/translate-rotate/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | translate-rotate 8 | 9 | 21 | 22 | 23 | 24 | 25 | 26 | 27 |

Click & drag to rotate

28 |

29 | 30 |

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /demo/castle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | castle 8 | 9 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo/tri-prism/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | tri-prism 8 | 9 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo/patties/patties.js: -------------------------------------------------------------------------------- 1 | // ------------------------- demo ------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var sceneSize = 48; 5 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 6 | var zoom = Math.floor( minWindowSize / sceneSize ); 7 | var illoSize = sceneSize * zoom; 8 | illoElem.setAttribute( 'width', illoSize ); 9 | illoElem.setAttribute( 'height', illoSize ); 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | dragRotate: true, 17 | onDragStart: function() { 18 | isSpinning = false; 19 | }, 20 | }); 21 | 22 | // ----- model ----- // 23 | 24 | var rect = new Zdog.Rect({ 25 | width: 20, 26 | height: 20, 27 | addTo: illo, 28 | translate: { y: 2 }, 29 | rotate: { x: TAU/4 }, 30 | stroke: 2, 31 | color: '#E21', 32 | }); 33 | 34 | new Zdog.Ellipse({ 35 | diameter: 20, 36 | addTo: illo, 37 | translate: { y: -2 }, 38 | rotate: { x: TAU/4 }, 39 | stroke: 2, 40 | color: '#19F', 41 | }); 42 | 43 | new Zdog.Shape({ 44 | addTo: rect, 45 | translate: { y: -10, z: 2 }, 46 | stroke: 2, 47 | color: '#EA0', 48 | }); 49 | 50 | // ----- animate ----- // 51 | 52 | function animate() { 53 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 54 | illo.updateRenderGraph(); 55 | requestAnimationFrame( animate ); 56 | } 57 | 58 | animate(); 59 | 60 | -------------------------------------------------------------------------------- /demo/truck-flight/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | truck-flight 8 | 9 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |

Click & drag to rotate

27 | 28 |

29 | 30 |

31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /demo/cones/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | cones 8 | 9 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /demo/codepen-logo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | codepen-logo 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /demo/sauropod/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | sauropod 8 | 9 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |

Click & drag to rotate

35 |

36 | 37 | 38 |

39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/crypto-kitty/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | crypto-kitty 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /demo/mario/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | mario 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/mega-man/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | mega-man 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/shade-and-shades/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | shade & shades 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |

37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/bird-house/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | bird house 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/hemisphere-ball/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | hemisphere ball 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/template/demo.js: -------------------------------------------------------------------------------- 1 | // ------------------------- demo ------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var sceneSize = 48; 5 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 6 | var zoom = Math.floor( minWindowSize / sceneSize ); 7 | var illoSize = sceneSize * zoom; 8 | illoElem.setAttribute( 'width', illoSize ); 9 | illoElem.setAttribute( 'height', illoSize ); 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | dragRotate: true, 17 | onDragStart: function() { 18 | isSpinning = false; 19 | }, 20 | }); 21 | 22 | // ----- model ----- // 23 | 24 | new Zdog.Rect({ 25 | width: 20, 26 | height: 20, 27 | addTo: illo, 28 | translate: { z: -10 }, 29 | stroke: 2, 30 | color: '#E21', 31 | }); 32 | 33 | new Zdog.Ellipse({ 34 | diameter: 16, 35 | addTo: illo, 36 | translate: { z: 10 }, 37 | stroke: 4, 38 | color: '#19F', 39 | }); 40 | 41 | new Zdog.Shape({ 42 | path: [ 43 | { x: 0, z: 1 }, 44 | { x: -1, z: -1 }, 45 | { x: 1, z: -1 }, 46 | ], 47 | scale: { x: 5, z: 5 }, 48 | addTo: illo, 49 | stroke: 2, 50 | fill: true, 51 | color: '#EA0', 52 | }); 53 | 54 | new Zdog.Shape({ 55 | translate: { x: 10, y: -5 }, 56 | addTo: illo, 57 | stroke: 7, 58 | color: '#246', 59 | }); 60 | 61 | // ----- animate ----- // 62 | 63 | function animate() { 64 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 65 | illo.updateRenderGraph(); 66 | requestAnimationFrame( animate ); 67 | } 68 | 69 | animate(); 70 | 71 | -------------------------------------------------------------------------------- /demo/inside-house/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | inside house 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/rgb-birdie/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | rgb birdie 8 | 9 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /demo/patties/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | template 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | template 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/gear-icon/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | gear-icon 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/cylinders/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | cylinders 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/la-link/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Link's Awakening Link 8 | 9 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /demo/strutter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | strutter 8 | 9 | 28 | 29 | 30 | 31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /demo/solid-shifter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | solid-shifter 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /demo/translate-rotate/translate-rotate.js: -------------------------------------------------------------------------------- 1 | var illoElem = document.querySelector('.illo'); 2 | var illoSize = 72; 3 | var zoom = 6; 4 | illoElem.setAttribute( 'width', illoSize * zoom ); 5 | illoElem.setAttribute( 'height', illoSize * zoom ); 6 | var TAU = Zdog.TAU; 7 | 8 | 9 | var illo = new Zdog.Illustration({ 10 | element: illoElem, 11 | zoom: zoom, 12 | dragRotate: true, 13 | }); 14 | 15 | // -- illustration shapes --- // 16 | 17 | var rect1 = new Zdog.Rect({ 18 | width: 12, 19 | height: 16, 20 | translate: { z: -6 }, 21 | // rotate: { z: 1 }, 22 | stroke: 2, 23 | // fill: true, 24 | color: '#08D', 25 | addTo: illo, 26 | }); 27 | 28 | var moon1 = new Zdog.Shape({ 29 | path: [ 30 | { z: 0 }, 31 | { z: 6 } 32 | ], 33 | translate: { y: -11 }, 34 | stroke: 3, 35 | color: 'white', 36 | addTo: rect1, 37 | }); 38 | 39 | new Zdog.Rect({ 40 | width: 12, 41 | height: 8, 42 | translate: { y: 8 }, 43 | rotate: { x: TAU/4 }, 44 | stroke: 2, 45 | fill: true, 46 | color: '#E21', 47 | addTo: illo, 48 | }); 49 | 50 | new Zdog.Shape({ 51 | path: [ 52 | { y: -6, z: 4 }, 53 | { y: 6, z: 4 }, 54 | { y: 6, z: 0 }, 55 | { y: -6, z: 0 }, 56 | ], 57 | stroke: 1, 58 | fill: true, 59 | color: '#F80', 60 | addTo: illo, 61 | }); 62 | 63 | // -- animate --- // 64 | 65 | var rZSpeed = 0; 66 | 67 | function animate() { 68 | // rotate 69 | moon1.rotate.y += 0.03; 70 | rect1.rotate.z -= 0.02; 71 | illo.rotate.z += rZSpeed; 72 | // update & render 73 | illo.updateRenderGraph(); 74 | requestAnimationFrame( animate ); 75 | } 76 | 77 | animate(); 78 | 79 | // ----- inputs ----- // 80 | 81 | document.querySelector('.toggle-z-rotation-button').onclick = function() { 82 | rZSpeed = rZSpeed ? 0 : TAU/360; 83 | }; 84 | -------------------------------------------------------------------------------- /demo/composite-shapes-scale-svg/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | composite-shapes-scale-svg 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /demo/composite-shapes-scale/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | composite-shapes-scale 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /demo/madeline/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | madeline 8 | 9 | 30 | 31 | 32 | 33 | 34 |
35 | 36 |
37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /demo/fizzy-bear/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | fizzy-bear 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |

37 | 38 | 39 |

40 | 41 |
42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /demo/santorini/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | santorini 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

36 | 37 |

38 |
39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /demo/happy-town/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | happy town 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |

37 |
38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /demo/little-forest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | little forest 8 | 9 | 45 | 46 | 47 | 48 | 49 |
50 | 51 |

52 |
53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /demo/santorini/make-rock.js: -------------------------------------------------------------------------------- 1 | /* globals midnight */ 2 | 3 | // width 4 | // depth 5 | // height 6 | // translate 7 | // eastOffset 8 | // westOffset 9 | // northOffset 10 | // southOffset 11 | 12 | window.makeRock = function( options ) { 13 | 14 | var x = options.width/2; 15 | var z = options.depth/2; 16 | var y = -options.height; 17 | var bottomWestNorth = { x: -x, y: 0, z: z }; 18 | var bottomEastNorth = { x: x, y: 0, z: z }; 19 | var bottomEastSouth = { x: x, y: 0, z: -z }; 20 | var bottomWestSouth = { x: -x, y: 0, z: -z }; 21 | 22 | var topWestX = x + ( options.westOffset || 0 ); 23 | var topEastX = x + ( options.eastOffset || 0 ); 24 | var topNorthZ = z + ( options.northOffset || 0 ); 25 | var topSouthZ = z + ( options.southOffset || 0 ); 26 | 27 | var topWestNorth = { x: -topWestX, y: y, z: topNorthZ }; 28 | var topEastNorth = { x: topEastX, y: y, z: topNorthZ }; 29 | var topEastSouth = { x: topEastX, y: y, z: -topSouthZ }; 30 | var topWestSouth = { x: -topWestX, y: y, z: -topSouthZ }; 31 | 32 | var anchor = new Zdog.Anchor({ 33 | addTo: options.addTo, 34 | translate: options.translate, 35 | }); 36 | 37 | function makeRockFace( path ) { 38 | new Zdog.Shape({ 39 | path: path, 40 | addTo: anchor, 41 | color: midnight, 42 | stroke: 2, 43 | }); 44 | } 45 | 46 | // north face 47 | makeRockFace([ 48 | topWestNorth, 49 | topEastNorth, 50 | bottomEastNorth, 51 | bottomWestNorth, 52 | ]); 53 | // south face 54 | makeRockFace([ 55 | topWestSouth, 56 | topEastSouth, 57 | bottomEastSouth, 58 | bottomWestSouth, 59 | ]); 60 | // west face 61 | makeRockFace([ 62 | topWestSouth, 63 | topWestNorth, 64 | bottomWestNorth, 65 | bottomWestSouth, 66 | ]); 67 | 68 | // east face 69 | makeRockFace([ 70 | topEastSouth, 71 | topEastNorth, 72 | bottomEastNorth, 73 | bottomEastSouth, 74 | ]); 75 | // top face 76 | makeRockFace([ 77 | topWestNorth, 78 | topEastNorth, 79 | topEastSouth, 80 | topWestSouth, 81 | ]); 82 | 83 | }; 84 | -------------------------------------------------------------------------------- /demo/madeline/make-bird.js: -------------------------------------------------------------------------------- 1 | /* globals TAU */ 2 | 3 | window.makeBird = function( options ) { 4 | 5 | var spin = options.spin || 0; 6 | 7 | var arrow = new Zdog.Anchor({ 8 | addTo: options.addTo, 9 | scale: 2/3, 10 | rotate: { z: spin }, 11 | }); 12 | 13 | var bird = new Zdog.Group({ 14 | addTo: arrow, 15 | translate: { x: 87 }, 16 | rotate: { x: -spin }, 17 | }); 18 | 19 | // bird body 20 | new Zdog.Shape({ 21 | path: [ 22 | { x: -3, y: 0 }, 23 | { arc: [ 24 | { x: -2, y: 1.5 }, 25 | { x: 0, y: 1.5 }, 26 | ]}, 27 | { arc: [ 28 | { x: 2, y: 1.5 }, 29 | { x: 2, y: 0 }, 30 | ]}, 31 | ], 32 | addTo: bird, 33 | translate: { x: 0.5 }, 34 | stroke: 3, 35 | color: options.color, 36 | fill: true, 37 | }); 38 | 39 | // bird head 40 | new Zdog.Shape({ 41 | translate: { x: 4, y: -1 }, 42 | addTo: bird, 43 | stroke: 4, 44 | color: options.color, 45 | }); 46 | 47 | // beak 48 | new Zdog.Shape({ 49 | path: [ 50 | { x: 0, y: -1 }, 51 | { x: 3, y: 0 }, 52 | { x: 0, y: 1 }, 53 | ], 54 | addTo: bird, 55 | translate: { x: 5, y: -1 }, 56 | stroke: 1, 57 | color: options.color, 58 | fill: true, 59 | }); 60 | 61 | // tail feather 62 | new Zdog.Shape({ 63 | path: [ 64 | { x: -3, z: -2 }, 65 | { x: 0, z: 0 }, 66 | { x: -3, z: 2 }, 67 | ], 68 | addTo: bird, 69 | translate: { x: -4, y: 0 }, 70 | stroke: 2, 71 | color: options.color, 72 | fill: true, 73 | }); 74 | 75 | var wing = new Zdog.Shape({ 76 | path: [ 77 | { x: 3, y: 0 }, 78 | { x: -1, y: -9 }, 79 | { arc: [ 80 | { x: -5, y: -4 }, 81 | { x: -3, y: 0 }, 82 | ]}, 83 | ], 84 | addTo: bird, 85 | translate: { z: -1.5}, 86 | rotate: { x: TAU/8 }, 87 | stroke: 1, 88 | color: options.color, 89 | fill: true, 90 | }); 91 | 92 | wing.copy({ 93 | translate: { z: 1.5}, 94 | scale: { z: -1 }, 95 | rotate: { x: -TAU/8 }, 96 | }); 97 | 98 | }; 99 | -------------------------------------------------------------------------------- /demo/santorini/buildings.js: -------------------------------------------------------------------------------- 1 | /* globals makeBuilding */ 2 | 3 | window.oneStoryBuilding = function( options ) { 4 | 5 | var anchor = new Zdog.Anchor({ 6 | addTo: options.addTo, 7 | translate: options.translate, 8 | }); 9 | 10 | var isNS = options.gable == 'ns'; 11 | 12 | var buildOptions = { 13 | width: isNS ? 8 : 10, 14 | height: 8, 15 | depth: isNS ? 10 : 8, 16 | gable: options.gable, 17 | addTo: anchor, 18 | }; 19 | 20 | // single window 21 | buildOptions[ options.gable + 'Windows'] = [ { x: 0 } ]; 22 | // two windows on long side 23 | var oppositeSide = isNS ? 'ew' : 'ns'; 24 | buildOptions[ oppositeSide + 'Windows'] = [ 25 | { x: -2 }, 26 | { x: 2 }, 27 | ]; 28 | 29 | makeBuilding( buildOptions ); 30 | 31 | }; 32 | 33 | window.twoStoryBuilding = function( options ) { 34 | 35 | var anchor = new Zdog.Anchor({ 36 | addTo: options.addTo, 37 | translate: options.translate, 38 | }); 39 | 40 | var isNS = options.gable == 'ns'; 41 | 42 | var buildOptions = { 43 | width: isNS ? 8 : 10, 44 | height: 14, 45 | depth: isNS ? 10 : 8, 46 | gable: options.gable, 47 | addTo: anchor, 48 | }; 49 | 50 | // single column 51 | buildOptions[ options.gable + 'Windows'] = [ 52 | { x: 0, y: -5 }, 53 | { x: 0, y: -11 }, 54 | ]; 55 | // two windows on long side 56 | var oppositeSide = isNS ? 'ew' : 'ns'; 57 | buildOptions[ oppositeSide + 'Windows'] = [ 58 | { x: -2, y: -5 }, 59 | { x: 2, y: -5 }, 60 | { x: -2, y: -11 }, 61 | { x: 2, y: -11 }, 62 | ]; 63 | 64 | makeBuilding( buildOptions ); 65 | 66 | }; 67 | 68 | 69 | window.oneStorySlanter = function( options ) { 70 | 71 | var anchor = new Zdog.Anchor({ 72 | addTo: options.addTo, 73 | translate: options.translate, 74 | }); 75 | 76 | makeBuilding({ 77 | width: 14, 78 | height: 8, 79 | depth: 6, 80 | gable: options.gable, 81 | addTo: anchor, 82 | nsWindows: [ 83 | { x: -4 }, 84 | { x: 0 }, 85 | { x: 4 }, 86 | ], 87 | ewWindows: [ 88 | { x: 0 } 89 | ], 90 | }); 91 | 92 | }; -------------------------------------------------------------------------------- /demo/unpkg-explode/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | unpkg explode 8 | 9 | 29 | 30 | 31 | 32 | 33 |
34 | 35 |

Click & drag to rotate

36 |

37 | 38 | 39 | 40 |

41 |

42 | 43 |

44 |

45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /demo/composite-shapes-scale-svg/composite-shapes-scale-svg.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var svg = document.querySelector('svg'); 4 | var sceneSize = 48; 5 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 6 | var zoom = Math.floor( minWindowSize / sceneSize ); 7 | svg.setAttribute( 'width', sceneSize * zoom ); 8 | svg.setAttribute( 'height', sceneSize * zoom ); 9 | var isSpinning = true; 10 | var TAU = Zdog.TAU; 11 | 12 | var illo = new Zdog.Illustration({ 13 | element: svg, 14 | zoom: zoom, 15 | scale: 2, 16 | dragRotate: true, 17 | onDragStart: function() { 18 | isSpinning = false; 19 | }, 20 | }); 21 | 22 | // -- illustration shapes --- // 23 | 24 | new Zdog.Rect({ 25 | width: 10, 26 | height: 10, 27 | addTo: illo, 28 | translate: { z: -10 }, 29 | stroke: 2, 30 | color: '#E21', 31 | }); 32 | 33 | /* 34 | new Zdog.Ellipse({ 35 | diameter: 16, 36 | addTo: illo, 37 | translate: { z: 10 }, 38 | stroke: 4, 39 | color: '#19F', 40 | }); 41 | 42 | new Zdog.Shape({ 43 | path: [ 44 | { x: 0, z: 1 }, 45 | { x: -1, z: -1 }, 46 | { x: 1, z: -1 }, 47 | ], 48 | scale: { x: 5, z: 5 }, 49 | addTo: illo, 50 | stroke: 2, 51 | fill: true, 52 | color: '#EA0', 53 | }); 54 | */ 55 | 56 | new Zdog.Hemisphere({ 57 | diameter: 4, 58 | scale: 2, 59 | addTo: illo, 60 | translate: { x: 8 }, 61 | color: '#EA0', 62 | backface: '#456', 63 | stroke: false, 64 | }); 65 | 66 | new Zdog.Cylinder({ 67 | diameter: 4, 68 | length: 4, 69 | scale: 2, 70 | addTo: illo, 71 | translate: { x: 0 }, 72 | color: '#C25', 73 | backface: '#E62', 74 | frontBaseColor: '#EA0', 75 | rearBaseColor: '#636', 76 | stroke: false, 77 | }); 78 | 79 | new Zdog.Cone({ 80 | diameter: 4, 81 | length: 3, 82 | scale: 2, 83 | addTo: illo, 84 | translate: { x: -8 }, 85 | color: '#456', 86 | backface: '#EA0', 87 | stroke: false, 88 | }); 89 | 90 | // -- animate --- // 91 | 92 | function animate() { 93 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 94 | illo.updateGraph(); 95 | illo.renderGraph(); 96 | requestAnimationFrame( animate ); 97 | } 98 | 99 | animate(); 100 | 101 | // -- update -- // 102 | -------------------------------------------------------------------------------- /demo/composite-shapes-scale/composite-shapes-scale.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 7 | var zoom = Math.min( 8, Math.floor( minWindowSize / w ) ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | 11 | var TAU = Zdog.TAU; 12 | var isSpinning = true; 13 | 14 | var illo = new Zdog.Illustration({ 15 | element: illoElem, 16 | zoom: zoom, 17 | scale: 2, 18 | dragRotate: true, 19 | onDragStart: function() { 20 | isSpinning = false; 21 | }, 22 | }); 23 | 24 | // -- illustration shapes --- // 25 | 26 | new Zdog.Rect({ 27 | width: 10, 28 | height: 10, 29 | addTo: illo, 30 | translate: { z: -10 }, 31 | stroke: 2, 32 | color: '#E21', 33 | }); 34 | 35 | /* 36 | new Zdog.Ellipse({ 37 | diameter: 16, 38 | addTo: illo, 39 | translate: { z: 10 }, 40 | stroke: 4, 41 | color: '#19F', 42 | }); 43 | 44 | new Zdog.Shape({ 45 | path: [ 46 | { x: 0, z: 1 }, 47 | { x: -1, z: -1 }, 48 | { x: 1, z: -1 }, 49 | ], 50 | scale: { x: 5, z: 5 }, 51 | addTo: illo, 52 | stroke: 2, 53 | fill: true, 54 | color: '#EA0', 55 | }); 56 | */ 57 | 58 | new Zdog.Hemisphere({ 59 | diameter: 4, 60 | scale: 2, 61 | addTo: illo, 62 | translate: { x: 8 }, 63 | color: '#EA0', 64 | backface: '#456', 65 | stroke: false, 66 | }); 67 | 68 | new Zdog.Cylinder({ 69 | diameter: 4, 70 | length: 4, 71 | scale: 2, 72 | addTo: illo, 73 | translate: { x: 0 }, 74 | color: '#C25', 75 | backface: '#E62', 76 | frontBaseColor: '#EA0', 77 | rearBaseColor: '#636', 78 | stroke: false, 79 | }); 80 | 81 | new Zdog.Cone({ 82 | diameter: 4, 83 | length: 3, 84 | scale: 2, 85 | addTo: illo, 86 | translate: { x: -8 }, 87 | color: '#456', 88 | backface: '#EA0', 89 | stroke: false, 90 | }); 91 | 92 | // -- animate --- // 93 | 94 | function animate() { 95 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 96 | illo.updateGraph(); 97 | illo.renderGraph(); 98 | requestAnimationFrame( animate ); 99 | } 100 | 101 | animate(); 102 | 103 | // -- update -- // 104 | -------------------------------------------------------------------------------- /demo/davey-nippu/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | davey nippu 8 | 9 | 48 | 49 | 50 | 51 | 52 |
53 | 54 |

Original illustration by Robin Davey

55 |

56 |
57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /demo/codepen-logo/codepen-logo.js: -------------------------------------------------------------------------------- 1 | // ----- setup ----- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 48; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.floor( minWindowSize / illoSize ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | var TAU = Zdog.TAU; 11 | var isSpinning = true; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | scale: 4, 16 | zoom: zoom, 17 | dragRotate: true, 18 | onDragStart: function() { 19 | isSpinning = false; 20 | }, 21 | }); 22 | 23 | var tiltAngle = Math.asin(2/3); 24 | 25 | var prism = new Zdog.Anchor({ 26 | addTo: illo, 27 | }); 28 | 29 | // ----- model ----- // 30 | 31 | var RT2 = Math.sqrt(2); 32 | var capLength = 6/RT2; 33 | var sideLength = 2 / Math.cos( tiltAngle ); 34 | var sideZ = sideLength/2; 35 | 36 | var cap = new Zdog.Rect({ 37 | width: capLength, 38 | height: capLength, 39 | addTo: prism, 40 | translate: { z: -sideZ }, 41 | stroke: 2, 42 | color: 'white', 43 | }); 44 | 45 | cap.copy({ 46 | translate: { z: sideZ }, 47 | }); 48 | 49 | var side = new Zdog.Shape({ 50 | addTo: prism, 51 | path: [ { z: -1 }, { z: 1 } ], 52 | scale: sideZ, 53 | translate: { x: capLength/2, y: capLength/2 }, 54 | stroke: 2, 55 | color: 'white', 56 | }); 57 | side.copy({ 58 | translate: { x: -capLength/2, y: capLength/2 }, 59 | }); 60 | side.copy({ 61 | translate: { x: -capLength/2, y: -capLength/2 }, 62 | }); 63 | side.copy({ 64 | translate: { x: capLength/2, y: -capLength/2 }, 65 | }); 66 | 67 | // -- animate --- // 68 | 69 | var ticker = 0; 70 | var cycleCount = 90; 71 | 72 | function animate() { 73 | // update 74 | if ( isSpinning ) { 75 | var progress = ticker / cycleCount; 76 | var tween = Zdog.easeInOut( progress % 1, 3 ); 77 | var turn = Math.floor( progress ); 78 | if ( turn === 0 ) { 79 | illo.rotate.z = Zdog.lerp( TAU/8 * -3, TAU/8, tween ); 80 | illo.rotate.x = Zdog.lerp( 0, tiltAngle, tween ); 81 | } else if ( turn == 1 ) { 82 | prism.rotate.x = Zdog.lerp( -TAU/2, 0, tween ); 83 | } 84 | ticker++; 85 | } 86 | 87 | illo.updateRenderGraph(); 88 | requestAnimationFrame( animate ); 89 | } 90 | 91 | animate(); 92 | 93 | 94 | // ----- inputs ----- // 95 | 96 | document.querySelector('.reset-button').onclick = reset; 97 | 98 | function reset() { 99 | ticker = 0; 100 | illo.rotate.set({}); 101 | isSpinning = true; 102 | } 103 | -------------------------------------------------------------------------------- /demo/hemisphere-ball/hemisphere-ball.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 7 | var zoom = Math.min( 10, Math.floor( minWindowSize / w ) ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | 11 | var isSpinning = true; 12 | var TAU = Zdog.TAU; 13 | 14 | var illo = new Zdog.Illustration({ 15 | element: illoElem, 16 | zoom: zoom, 17 | dragRotate: true, 18 | onDragStart: function() { 19 | isSpinning = false; 20 | }, 21 | }); 22 | 23 | // colors 24 | var yellow = '#ED0'; 25 | var gold = '#EA0'; 26 | var orange = '#E62'; 27 | var garnet = '#C25'; 28 | var eggplant = '#636'; 29 | 30 | // -- illustration shapes --- // 31 | 32 | var hemi = new Zdog.Hemisphere({ 33 | diameter: 13, 34 | addTo: illo, 35 | translate: { y: -16 }, 36 | rotate: { x: -TAU/4 }, 37 | color: garnet, 38 | backface: eggplant, 39 | stroke: false, 40 | }); 41 | hemi.copy({ 42 | translate: { y: 16 }, 43 | rotate: { x: TAU/4 }, 44 | color: garnet, 45 | backface: eggplant, 46 | }); 47 | 48 | var colorWheel = [ eggplant, garnet, orange, gold, yellow, ]; 49 | 50 | [ -1, 1 ].forEach( function( ySide ) { 51 | for ( var i=0; i < 5; i++ ) { 52 | var rotor1 = new Zdog.Anchor({ 53 | addTo: illo, 54 | rotate: { y: TAU/5 * i }, 55 | }); 56 | var rotor2 = new Zdog.Anchor({ 57 | addTo: rotor1, 58 | rotate: { x: TAU/6 }, 59 | }); 60 | 61 | hemi.copy({ 62 | addTo: rotor2, 63 | translate: { y: 16*ySide }, 64 | rotate: { x: TAU/4*ySide }, 65 | color: colorWheel[i], 66 | backface: colorWheel[ (i+7) % 5 ], 67 | }); 68 | } 69 | }); 70 | 71 | // -- animate --- // 72 | 73 | var keyframes = [ 74 | { x: TAU * 0, y: TAU * 0 }, 75 | { x: TAU * 1/2, y: TAU * 1/2 }, 76 | { x: TAU * 1, y: TAU * 1 }, 77 | ]; 78 | 79 | var t = 0; 80 | 81 | function animate() { 82 | rotate(); 83 | illo.updateRenderGraph(); 84 | requestAnimationFrame( animate ); 85 | } 86 | 87 | animate(); 88 | 89 | // -- update -- // 90 | 91 | function rotate() { 92 | if ( !isSpinning ) { 93 | return; 94 | } 95 | var easeT = Zdog.easeInOut( t % 1, 3 ); 96 | var turnLimit = keyframes.length - 1; 97 | var turn = Math.floor( t % turnLimit ); 98 | var keyA = keyframes[ turn ]; 99 | var keyB = keyframes[ turn + 1 ]; 100 | var thetaX = Zdog.lerp( keyA.x, keyB.x, easeT ); 101 | illo.rotate.x = Math.cos( thetaX ) * TAU/12; 102 | illo.rotate.y = Zdog.lerp( keyA.y, keyB.y, easeT ) ; 103 | t += 1/180; 104 | } 105 | -------------------------------------------------------------------------------- /demo/gear-icon/gear-icon.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 7 | var zoom = Math.floor( minWindowSize / w ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | rotate: { x: -TAU/8 }, 17 | dragRotate: true, 18 | onDragStart: function() { 19 | isSpinning = false; 20 | }, 21 | }); 22 | 23 | // -- illustration shapes --- // 24 | 25 | var teeth = 8; 26 | var frontZ = { z: 3 }; 27 | var backZ = { z: -3 }; 28 | 29 | var colorA = '#EA0'; 30 | var colorB = '#345'; 31 | 32 | var gearPath = ( function() { 33 | var path = []; 34 | var teethCount = teeth * 4; 35 | for ( var i=0; i < teethCount; i++ ) { 36 | var isOuter = i % 4 < 2; 37 | var radius = isOuter ? 12 : 9.5; 38 | var theta = Math.ceil( i/2 ) * 2; 39 | theta += i % 2 ? -0.2 : 0.2; 40 | theta = ( theta/teethCount + 1/teethCount ) * TAU ; 41 | path.push({ 42 | x: Math.cos( theta ) * radius, 43 | y: Math.sin( theta ) * radius, 44 | }); 45 | } 46 | return path; 47 | })(); 48 | 49 | var gear = new Zdog.Anchor({ 50 | addTo: illo, 51 | rotate: { x: TAU/4 }, 52 | }); 53 | 54 | var gearSide = new Zdog.Anchor({ 55 | addTo: gear, 56 | translate: frontZ, 57 | }); 58 | // gear face 59 | new Zdog.Shape({ 60 | addTo: gearSide, 61 | path: gearPath, 62 | color: colorA, 63 | backface: false, 64 | fill: true, 65 | stroke: 1/zoom, 66 | closed: false, 67 | // visible: false, 68 | }); 69 | // nub 70 | new Zdog.Cylinder({ 71 | addTo: gearSide, 72 | diameter: 6, 73 | length: 2, 74 | color: colorB, 75 | backface: 'white', 76 | translate: { z: 1 }, 77 | fill: true, 78 | stroke: false, 79 | }); 80 | 81 | gearSide.copyGraph({ 82 | rotate: { y: TAU/2 }, 83 | translate: backZ, 84 | }); 85 | 86 | gearPath.forEach( function( corner, i ) { 87 | var nextCorner = gearPath[ i + 1 ] || gearPath[0]; 88 | new Zdog.Shape({ 89 | addTo: gear, 90 | path: [ 91 | new Zdog.Vector( corner ).add( frontZ ), 92 | new Zdog.Vector( corner ).add( backZ ), 93 | new Zdog.Vector( nextCorner ).add( backZ ), 94 | new Zdog.Vector( nextCorner ).add( frontZ ), 95 | ], 96 | color: i % 2 ? colorA : colorB, 97 | fill: true, 98 | stroke: 1/zoom, 99 | }); 100 | }); 101 | 102 | // -- animate --- // 103 | 104 | function animate() { 105 | illo.rotate.y += isSpinning ? +TAU/240 : 0; 106 | illo.updateRenderGraph(); 107 | requestAnimationFrame( animate ); 108 | } 109 | 110 | animate(); 111 | 112 | -------------------------------------------------------------------------------- /demo/cylinders/cylinders.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 7 | var zoom = Math.min( 10, Math.floor( minWindowSize / w ) ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | 11 | var isSpinning = true; 12 | var TAU = Zdog.TAU; 13 | 14 | var illo = new Zdog.Illustration({ 15 | element: illoElem, 16 | zoom: zoom, 17 | dragRotate: true, 18 | onDragStart: function() { 19 | isSpinning = false; 20 | }, 21 | }); 22 | 23 | // colors 24 | var yellow = '#ED0'; 25 | var gold = '#EA0'; 26 | var orange = '#E62'; 27 | var magenta = '#C25'; 28 | var navy = '#249'; 29 | 30 | // -- illustration shapes --- // 31 | 32 | var y = 12; 33 | 34 | var cylinder = new Zdog.Cylinder({ 35 | diameter: 10, 36 | length: 5, 37 | addTo: illo, 38 | translate: { y: -y }, 39 | rotate: { x: -TAU/4 }, 40 | // rotate: { x: -TAU/8 }, 41 | color: magenta, 42 | backface: navy, 43 | stroke: false, 44 | }); 45 | cylinder.copy({ 46 | addTo: illo, 47 | translate: { y: y }, 48 | rotate: { x: TAU/4 }, 49 | color: magenta, 50 | backface: navy, 51 | }); 52 | 53 | var colorWheel = [ navy, magenta, orange, gold, yellow, ]; 54 | 55 | [ -1, 1 ].forEach( function( ySide ) { 56 | for ( var i=0; i < 5; i++ ) { 57 | var rotor1 = new Zdog.Anchor({ 58 | addTo: illo, 59 | rotate: { y: TAU/5 * i }, 60 | }); 61 | var rotor2 = new Zdog.Anchor({ 62 | addTo: rotor1, 63 | rotate: { x: TAU/6 }, 64 | }); 65 | 66 | cylinder.copy({ 67 | addTo: rotor2, 68 | translate: { y: y*ySide }, 69 | rotate: { x: TAU/4*ySide }, 70 | color: colorWheel[i], 71 | backface: colorWheel[ (i+7) % 5 ], 72 | }); 73 | } 74 | }); 75 | 76 | new Zdog.Shape({ 77 | visible: false, 78 | addTo: illo, 79 | stroke: 18, 80 | // color: '#FED', 81 | color: 'hsla(50, 50%, 90%, 0.8)', 82 | }); 83 | 84 | // -- animate --- // 85 | 86 | var keyframes = [ 87 | { x: TAU * 0, y: TAU * 0 }, 88 | { x: TAU * 1/2, y: TAU * 1/2 }, 89 | { x: TAU * 1, y: TAU * 1 }, 90 | ]; 91 | 92 | var t = 0; 93 | 94 | function animate() { 95 | spin(); 96 | illo.updateRenderGraph(); 97 | requestAnimationFrame( animate ); 98 | } 99 | 100 | animate(); 101 | 102 | // -- update -- // 103 | 104 | function spin() { 105 | if ( !isSpinning ) { 106 | return; 107 | } 108 | var easeT = Zdog.easeInOut( t % 1, 3 ); 109 | var turnLimit = keyframes.length - 1; 110 | var turn = Math.floor( t % turnLimit ); 111 | var keyA = keyframes[ turn ]; 112 | var keyB = keyframes[ turn + 1 ]; 113 | var thetaX = Zdog.lerp( keyA.x, keyB.x, easeT ); 114 | illo.rotate.x = Math.cos( thetaX ) * TAU/12; 115 | illo.rotate.y = Zdog.lerp( keyA.y, keyB.y, easeT ) ; 116 | t += 1/180; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /demo/bird-house/bird-house.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 7 | var zoom = Math.floor( minWindowSize / w ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | var isSpinning = false; 11 | var TAU = Zdog.TAU; 12 | // colors 13 | var yellow = "#ED0"; 14 | var gold = '#EA0'; 15 | var orange = '#E62'; 16 | var garnet = '#C25'; 17 | var eggplant = '#636'; 18 | 19 | [ Zdog.Shape, Zdog.Ellipse, Zdog.Rect ].forEach( function( ShapeClass ) { 20 | ShapeClass.defaults.stroke = 1/zoom; 21 | ShapeClass.defaults.fill = true; 22 | }); 23 | 24 | var illo = new Zdog.Illustration({ 25 | element: illoElem, 26 | zoom: zoom, 27 | dragRotate: true, 28 | onDragStart: function() { 29 | isSpinning = false; 30 | }, 31 | }); 32 | 33 | // -- illustration shapes --- // 34 | 35 | var house = new Zdog.Anchor({ 36 | addTo: illo, 37 | scale: 4, 38 | }); 39 | 40 | var frontGroup = new Zdog.Group({ 41 | addTo: house, 42 | translate: { z: 2 }, 43 | }); 44 | 45 | var gable = new Zdog.Shape({ 46 | addTo: frontGroup, 47 | path: [ 48 | { x: 0, y: -2 }, 49 | { x: 2, y: 0 }, 50 | { x: 2, y: 2 }, 51 | { x: -2, y: 2 }, 52 | { x: -2, y: 0 }, 53 | ], 54 | closed: true, 55 | color: gold, 56 | }); 57 | gable.copy({ 58 | addTo: house, 59 | translate: { z: -2 }, 60 | color: garnet, 61 | }); 62 | 63 | // hole 64 | new Zdog.Ellipse({ 65 | addTo: frontGroup, 66 | diameter: 1.25, 67 | color: eggplant, 68 | stroke: false, 69 | }); 70 | 71 | var side = new Zdog.Rect({ 72 | addTo: house, 73 | width: 4, 74 | height: 2, 75 | rotate: { y: TAU/4 }, 76 | translate: { x: 2, y: 1 }, 77 | color: orange, 78 | }); 79 | side.copy({ 80 | translate: { x: -2, y: 1 }, 81 | color: garnet, 82 | }); 83 | 84 | var roofAnchor = new Zdog.Anchor({ 85 | addTo: house, 86 | translate: { y: -2 }, 87 | rotate: { z: -TAU/8 }, 88 | }); 89 | 90 | var roofW = Math.sqrt(2) * 2; 91 | // var roofW = 4; 92 | 93 | var roof = new Zdog.Rect({ 94 | addTo: roofAnchor, 95 | width: roofW, 96 | height: 4, 97 | translate: { x: -roofW/2 }, 98 | rotate: { x: TAU/4 }, 99 | color: orange, 100 | backface: eggplant, 101 | }); 102 | 103 | roof.copy({ 104 | width: 1, 105 | translate: { x: -roofW - 0.5 }, 106 | // color: gold, 107 | }); 108 | 109 | var roofCopy = roofAnchor.copyGraph({ 110 | scale: { x: -1 }, 111 | rotate: { z: TAU/8 }, 112 | }); 113 | 114 | roofCopy.children[0].color = yellow; 115 | roofCopy.children[1].color = yellow; 116 | 117 | // base 118 | new Zdog.Rect({ 119 | addTo: house, 120 | width: 4, 121 | height: 4, 122 | translate: { y: 2 }, 123 | rotate: { x: TAU/4 }, 124 | color: eggplant, 125 | }); 126 | 127 | // -- animate --- // 128 | 129 | function animate() { 130 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 131 | illo.updateRenderGraph(); 132 | requestAnimationFrame( animate ); 133 | } 134 | 135 | animate(); 136 | 137 | -------------------------------------------------------------------------------- /demo/rgb-birdie/rgb-birdie.js: -------------------------------------------------------------------------------- 1 | // ------------------------- demo ------------------------- // 2 | 3 | var sceneSize = 270; 4 | var TAU = Zdog.TAU; 5 | var initialRotate = new Zdog.Vector({ x: -35, y: -45 }).multiply( TAU/360 ); 6 | 7 | var illo = new Zdog.Illustration({ 8 | element: '.illo', 9 | rotate: initialRotate, 10 | dragRotate: true, 11 | resize: 'fullscreen', 12 | onResize: function( width, height ) { 13 | this.zoom = Math.floor( Math.min( width, height ) / sceneSize * 2 ) / 2; 14 | }, 15 | }); 16 | 17 | // ----- model ----- // 18 | 19 | var bird = new Zdog.Anchor({ 20 | addTo: illo, 21 | translate: { z: -20 }, 22 | }); 23 | 24 | var letterGroup = new Zdog.Group({ 25 | addTo: bird, 26 | }); 27 | 28 | // R 29 | new Zdog.Shape({ 30 | addTo: letterGroup, 31 | path: [ 32 | { x: -55, y: -55 }, 33 | { x: 15, y: -55 }, 34 | { arc: [ 35 | { x: 55, y: -55 }, 36 | { x: 55, y: -15 }, 37 | ]}, 38 | { bezier: [ 39 | { x: 55, y: 0 }, 40 | { x: 47, y: 13 }, 41 | { x: 35, y: 20 }, 42 | ]}, 43 | { x: 29, y: 23 }, 44 | { x: 50, y: 55 }, 45 | { x: -55, y: 55 }, 46 | ], 47 | rotate: { x: TAU/4 }, 48 | color: '#F00', 49 | stroke: 10, 50 | fill: true, 51 | }); 52 | 53 | // G 54 | new Zdog.Shape({ 55 | addTo: letterGroup, 56 | path: [ 57 | { x: 0, y: -55 }, 58 | { bezier: [ 59 | { x: 18, y: -55 }, 60 | { x: 32, y: -46 }, 61 | { x: 40, y: -38 }, 62 | ]}, 63 | { x: 7, y: -5 }, 64 | { x: 55, y: -5 }, 65 | { x: 55, y: 53 }, 66 | { x: 35, y: 47 }, 67 | { bezier: [ 68 | { x: 21, y: 52 }, 69 | { x: 10, y: 55 }, 70 | { x: 0, y: 55 }, 71 | ]}, 72 | { arc: [ 73 | { x: -55, y: 55 }, 74 | { x: -55, y: 0 }, 75 | ]}, 76 | { arc: [ 77 | { x: -55, y: -55 }, 78 | { x: 0, y: -55 }, 79 | ]}, 80 | ], 81 | translate: { x: -30, y: 20, z: 33 }, 82 | rotate: { y: TAU/4 }, 83 | color: '#0F0', 84 | stroke: 10, 85 | fill: true, 86 | }); 87 | 88 | // B 89 | new Zdog.Shape({ 90 | addTo: letterGroup, 91 | path: [ 92 | { x: -55, y: -55 }, 93 | { x: 25, y: -55 }, 94 | { arc: [ 95 | { x: 55, y: -55 }, 96 | { x: 55, y: -25 }, 97 | ]}, 98 | { bezier: [ 99 | { x: 55, y: -13 }, 100 | { x: 49, y: -7 }, 101 | { x: 42, y: -4 }, 102 | ]}, 103 | { x: 35, y: 0 }, 104 | { x: 42, y: 4 }, 105 | { bezier: [ 106 | { x: 49, y: 7 }, 107 | { x: 55, y: 13 }, 108 | { x: 55, y: 25 }, 109 | ]}, 110 | { arc: [ 111 | { x: 55, y: 55 }, 112 | { x: 25, y: 55 }, 113 | ]}, 114 | { x: -55, y: 55 }, 115 | ], 116 | translate: { y: -10, z: 60 }, 117 | color: '#00F', 118 | stroke: 10, 119 | fill: true, 120 | }); 121 | 122 | var eye = new Zdog.Shape({ 123 | addTo: bird, 124 | translate: { x: -60, y: -40, z: 30 }, 125 | stroke: 18, 126 | color: '#111', 127 | }); 128 | 129 | // screen blend letters 130 | letterGroup.render = function( ctx ) { 131 | ctx.globalCompositeOperation = 'screen'; 132 | Zdog.Group.prototype.render.apply( this, arguments ); 133 | }; 134 | // normal blend eye 135 | eye.render = function( ctx ) { 136 | ctx.globalCompositeOperation = 'source-over'; 137 | Zdog.Shape.prototype.render.apply( this, arguments ); 138 | }; 139 | 140 | // ----- animate ----- // 141 | 142 | function animate() { 143 | illo.updateRenderGraph(); 144 | requestAnimationFrame( animate ); 145 | } 146 | 147 | animate(); 148 | 149 | -------------------------------------------------------------------------------- /demo/inside-house/inside-house.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 7 | var zoom = Math.min( 8, Math.floor( minWindowSize / w ) ); 8 | illoElem.setAttribute( 'width', w * zoom ); 9 | illoElem.setAttribute( 'height', h * zoom ); 10 | 11 | var isSpinning = true; 12 | var TAU = Zdog.TAU; 13 | 14 | // default to flat, filled shapes 15 | [ Zdog.Shape, Zdog.Rect, Zdog.Ellipse ].forEach( function( ItemClass ) { 16 | ItemClass.defaults.fill = true; 17 | ItemClass.defaults.stroke = false; 18 | ItemClass.defaults.backface = false; 19 | ItemClass.defaults.front = { z: 1 }; 20 | }); 21 | 22 | var illo = new Zdog.Illustration({ 23 | element: illoElem, 24 | zoom: zoom, 25 | dragRotate: true, 26 | onDragStart: function() { 27 | isSpinning = false; 28 | }, 29 | }); 30 | 31 | // -- house --- // 32 | 33 | var house = new Zdog.Anchor({ 34 | addTo: illo, 35 | scale: 10, 36 | }); 37 | 38 | var nsWall = new Zdog.Shape({ 39 | path: [ 40 | { x: -1, y: -1 }, 41 | { x: 0, y: -2 }, 42 | { x: 1, y: -1 }, 43 | { x: 1, y: 1 }, 44 | { x: -1, y: 1 }, 45 | ], 46 | addTo: house, 47 | translate: { z: -1 }, 48 | fill: true, 49 | color: 'hsla(45, 100%, 50%, 0.6)', 50 | }); 51 | 52 | nsWall.copy({ 53 | translate: { z: 1 }, 54 | rotate: { y: TAU/2 }, 55 | }); 56 | 57 | var ewWall = new Zdog.Rect({ 58 | width: 2, 59 | height: 2, 60 | addTo: house, 61 | translate: { x: -1 }, 62 | rotate: { y: -TAU/4 }, 63 | fill: true, 64 | color: 'hsla(210, 100%, 50%, 0.6)', 65 | }); 66 | 67 | ewWall.copy({ 68 | translate: { x: 1 }, 69 | rotate: { y: TAU/4 }, 70 | }); 71 | 72 | // floor 73 | new Zdog.Shape({ 74 | path: [ 75 | { x: -1, z: -1 }, 76 | { x: 1, z: -1 }, 77 | { x: 1, z: 1 }, 78 | { x: -1, z: 1 }, 79 | ], 80 | addTo: house, 81 | backface: true, 82 | translate: { y: 1 }, 83 | // front: { y: Zdog.Shape.defaults.front.z * -1 }, 84 | fill: true, 85 | color: 'hsla(120, 100%, 40%, 0.8)', 86 | }); 87 | 88 | // roof 89 | var roofLength = Math.sqrt(2); 90 | var roof = new Zdog.Shape({ 91 | path: [ 92 | { x: 0, y: -1 }, 93 | { x: roofLength, y: -1 }, 94 | { x: roofLength, y: 1 }, 95 | { x: 0, y: 1 }, 96 | ], 97 | addTo: house, 98 | translate: { y: -2 }, 99 | rotate: { x: -TAU/4, y: TAU/8 }, 100 | fill: true, 101 | color: 'hsla(0, 100%, 60%, 0.6)', 102 | }); 103 | 104 | roof.copy({ 105 | scale: { x: -1 }, 106 | rotate: { x: -TAU/4, y: -TAU/8 }, 107 | }); 108 | 109 | // -- chair --- // 110 | 111 | var chair = new Zdog.Group({ 112 | addTo: illo, 113 | scale: 2, 114 | translate: { y: 5 }, 115 | }); 116 | // chair back 117 | var chairLegs = new Zdog.Shape({ 118 | path: [ 119 | { x: -1, y: 2 }, 120 | { x: -1, y: -2 }, 121 | { x: 1, y: -2 }, 122 | { x: 1, y: 2 }, 123 | ], 124 | addTo: chair, 125 | translate: { z: 1 }, 126 | closed: false, 127 | stroke: 1, 128 | fill: false, 129 | color: '#333', 130 | backface: true, 131 | }); 132 | // chair front 133 | chairLegs.copy({ 134 | path: [ 135 | { x: -1, y: 2 }, 136 | { x: -1, y: 0 }, 137 | { x: 1, y: 0 }, 138 | { x: 1, y: 2 }, 139 | ], 140 | translate: { z: -1 }, 141 | }); 142 | // chair seat 143 | new Zdog.Rect({ 144 | width: 2, 145 | height: 2, 146 | addTo: chair, 147 | rotate: { x: TAU/4 }, 148 | stroke: 1, 149 | fill: true, 150 | color: '#333', 151 | backface: true, 152 | }); 153 | 154 | // -- animate --- // 155 | 156 | function animate() { 157 | illo.rotate.y += isSpinning ? +TAU/240 : 0; 158 | illo.updateRenderGraph(); 159 | requestAnimationFrame( animate ); 160 | } 161 | 162 | animate(); 163 | 164 | -------------------------------------------------------------------------------- /demo/cones/cones.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 64; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.floor( minWindowSize / illoSize ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | dragRotate: true, 17 | onDragStart: function() { 18 | isSpinning = false; 19 | }, 20 | }); 21 | 22 | // colors 23 | var yellow = '#ED0'; 24 | // var gold = '#EA0'; 25 | var orange = '#E62'; 26 | var magenta = '#C25'; 27 | // var navy = '#249'; 28 | var beige = '#FEC'; 29 | var blue = '#8AD'; 30 | 31 | 32 | var colorWheel = [ beige, magenta, orange, blue, yellow ]; 33 | 34 | // ----- model ----- // 35 | 36 | // top & bottom 37 | var cone = new Zdog.Cone({ 38 | diameter: 8, 39 | length: 10, 40 | addTo: illo, 41 | translate: { y: -16 }, 42 | // scale: { x: 2, y: 2 }, 43 | rotate: { x: -TAU/4 }, 44 | color: colorWheel[1], 45 | backface: colorWheel[0], 46 | stroke: false, 47 | }); 48 | cone.copy({ 49 | translate: { y: 16 }, 50 | rotate: { x: TAU/4 }, 51 | }); 52 | 53 | 54 | 55 | [ -1, 1 ].forEach( function( ySide ) { 56 | for ( var i=0; i < 5; i++ ) { 57 | var rotor1 = new Zdog.Anchor({ 58 | addTo: illo, 59 | rotate: { y: TAU/5 * i }, 60 | }); 61 | var rotor2 = new Zdog.Anchor({ 62 | addTo: rotor1, 63 | rotate: { x: TAU/6 }, 64 | }); 65 | 66 | cone.copy({ 67 | addTo: rotor2, 68 | translate: { y: 16*ySide }, 69 | rotate: { x: TAU/4*ySide }, 70 | color: colorWheel[i], 71 | backface: colorWheel[ (i+7) % 5 ], 72 | }); 73 | } 74 | }); 75 | 76 | [ -1, 1 ].forEach( function( ySide ) { 77 | for ( var i=0; i < 5; i++ ) { 78 | var rotor1 = new Zdog.Anchor({ 79 | addTo: illo, 80 | rotate: { y: TAU/5 * (i+0.5) }, 81 | }); 82 | var rotor2 = new Zdog.Anchor({ 83 | addTo: rotor1, 84 | rotate: { x: TAU/10 }, 85 | }); 86 | 87 | cone.copy({ 88 | addTo: rotor2, 89 | translate: { y: -16*ySide }, 90 | rotate: { x: TAU/4*ySide }, 91 | color: colorWheel[ (i+3) % 5 ], 92 | backface: colorWheel[i], 93 | }); 94 | } 95 | }); 96 | 97 | [ -1, 1 ].forEach( function( ySide ) { 98 | for ( var i=0; i < 5; i++ ) { 99 | var rotor1 = new Zdog.Anchor({ 100 | addTo: illo, 101 | rotate: { y: TAU/5 * (i+0.5) }, 102 | }); 103 | var rotor2 = new Zdog.Anchor({ 104 | addTo: rotor1, 105 | rotate: { x: TAU/4.5 }, 106 | }); 107 | 108 | cone.copy({ 109 | addTo: rotor2, 110 | translate: { y: -16*ySide }, 111 | // scale: { y: -1 }, 112 | rotate: { x: TAU/4*ySide }, 113 | color: colorWheel[ (i+1) % 5 ], 114 | backface: colorWheel[ (i+4) % 5 ], 115 | }); 116 | } 117 | }); 118 | 119 | 120 | // -- animate --- // 121 | 122 | var keyframes = [ 123 | { x: TAU * 0, y: TAU * 0 }, 124 | { x: TAU * 1/2, y: TAU * -1/2 }, 125 | { x: TAU * 1, y: TAU * -1 }, 126 | ]; 127 | 128 | var ticker = 0; 129 | var cycleCount = 180; 130 | 131 | function animate() { 132 | spin(); 133 | illo.updateRenderGraph(); 134 | requestAnimationFrame( animate ); 135 | } 136 | 137 | animate(); 138 | 139 | // -- update -- // 140 | 141 | function spin() { 142 | if ( !isSpinning ) { 143 | return; 144 | } 145 | var progress = ticker / cycleCount; 146 | var tween = Zdog.easeInOut( progress % 1, 3 ); 147 | var turnLimit = keyframes.length - 1; 148 | var turn = Math.floor( progress % turnLimit ); 149 | var keyA = keyframes[ turn ]; 150 | var keyB = keyframes[ turn + 1 ]; 151 | var thetaX = Zdog.lerp( keyA.x, keyB.x, tween ); 152 | illo.rotate.x = Math.cos( thetaX ) * TAU/12; 153 | illo.rotate.y = Zdog.lerp( keyA.y, keyB.y, tween ) ; 154 | ticker++; 155 | } 156 | -------------------------------------------------------------------------------- /demo/unpkg-explode/unpkg-explode.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var w = 48; 5 | var h = 48; 6 | var minWindowSize = Math.min( window.innerWidth, (window.innerHeight - 200) ); 7 | var zoom = Math.floor( minWindowSize / w ); 8 | // var zoom = 6; 9 | illoElem.setAttribute( 'width', w * zoom ); 10 | illoElem.setAttribute( 'height', h * zoom ); 11 | var TAU = Zdog.TAU; 12 | 13 | var isSpinning = false; 14 | 15 | var illo = new Zdog.Illustration({ 16 | element: illoElem, 17 | zoom: zoom, 18 | rotate: { x: TAU * (35/360), y: TAU/8 }, 19 | dragRotate: true, 20 | onDragStart: function() { 21 | isSpinning = false; 22 | }, 23 | }); 24 | 25 | var red = '#E21'; 26 | var blue = '#19F'; 27 | var gold = '#EA0'; 28 | var green = '#6C6'; 29 | var magenta = '#E2A'; 30 | 31 | // -- illustration shapes --- // 32 | 33 | var colors = [ red, blue, gold, magenta, green ]; 34 | 35 | var panelAnchors = []; 36 | var panels = []; 37 | var outlines = []; 38 | 39 | [ 40 | { y: 0 }, 41 | { y: TAU/4 }, 42 | { y: TAU/2 }, 43 | { y: TAU * 3/4 }, 44 | { x: TAU/4 }, 45 | ].forEach( function( rotation, i ) { 46 | 47 | var rotor = new Zdog.Anchor({ 48 | addTo: illo, 49 | rotate: rotation, 50 | }); 51 | 52 | var anchor = new Zdog.Anchor({ 53 | addTo: rotor, 54 | translate: { z: -8 }, 55 | }); 56 | 57 | panelAnchors.push( anchor ); 58 | 59 | var panel = new Zdog.RoundedRect({ 60 | width: 16, 61 | height: 16, 62 | cornerRadius: 3, 63 | addTo: anchor, 64 | stroke: false, 65 | fill: true, 66 | color: colors[i], 67 | }); 68 | 69 | panels.push( panel ); 70 | 71 | var outline = panel.copy({ 72 | visible: false, 73 | stroke: 1, 74 | fill: false, 75 | color: 'black', 76 | }); 77 | 78 | outlines.push( outline ); 79 | 80 | }); 81 | 82 | // -- animate --- // 83 | 84 | illo.ctx.globalCompositeOperation = 'multiply'; 85 | 86 | function animate() { 87 | illo.updateRenderGraph(); 88 | requestAnimationFrame( animate ); 89 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 90 | } 91 | 92 | animate(); 93 | 94 | // ----- animation ----- // 95 | 96 | var animateFrame; 97 | 98 | function animation( duration, onFrame ) { 99 | 100 | var start = now(); 101 | 102 | animateFrame = function() { 103 | var ellasped = now() - start; 104 | var t = ellasped / duration; 105 | onFrame( t ); 106 | if ( ellasped < duration ) { 107 | requestAnimationFrame( animateFrame ); 108 | } 109 | }; 110 | 111 | animateFrame(); 112 | } 113 | 114 | function now() { 115 | return ( new Date() ).getTime(); 116 | } 117 | 118 | function startAnimation() { 119 | animation( 2000, function( t ) { 120 | var easeT = Zdog.easeInOut( t, 3 ); 121 | panelAnchors.forEach( function( panelAnchor ) { 122 | panelAnchor.translate.z = Zdog.lerp( -8, -11, easeT ); 123 | }); 124 | illo.rotate.x = Zdog.lerp( TAU/4, TAU * (35/360), easeT ); 125 | illo.rotate.y = Zdog.lerp( -TAU/2, TAU/8, easeT ); 126 | }); 127 | } 128 | 129 | startAnimation(); 130 | 131 | // ----- more inputs ----- // 132 | 133 | var fillP = document.querySelector('.fill-p'); 134 | fillP.onchange = function( event ) { 135 | changePanelColor( event.target.value ); 136 | }; 137 | 138 | // set initial 139 | changePanelColor( fillP.querySelector(':checked').value ); 140 | 141 | function changePanelColor( value ) { 142 | panels.forEach( function( panel, i ) { 143 | if ( value == 'gray' ) { 144 | panel.color = '#888'; 145 | } else if ( value == 'clear' ) { 146 | panel.color = 'transparent'; 147 | } else { 148 | panel.color = colors[i]; 149 | } 150 | }); 151 | } 152 | 153 | var outlineCheckbox = document.querySelector('.outline-checkbox'); 154 | outlineCheckbox.onchange = function( event ) { 155 | outlines.forEach( function( outline ) { 156 | outline.visible = event.target.checked; 157 | }); 158 | }; 159 | 160 | // set initial 161 | changeOutline( outlineCheckbox.checked ); 162 | 163 | function changeOutline( isRendering ) { 164 | outlines.forEach( function( outline ) { 165 | outline.visible = isRendering; 166 | }); 167 | } 168 | -------------------------------------------------------------------------------- /demo/happy-town/make-building.js: -------------------------------------------------------------------------------- 1 | /* globals TAU, red, blue, navy, gold, white */ 2 | 3 | // -------------------------- makeBuilding -------------------------- // 4 | 5 | window.makeBuilding = function( options ) { 6 | 7 | var wallX = options.width/2; 8 | var wallY = options.height; 9 | var wallZ = options.depth/2; 10 | 11 | // collect walls 12 | var building = {}; 13 | 14 | // south/noth walls 15 | [ true, false ].forEach( function( isSouth ) { 16 | var wallTZ = isSouth ? -wallZ : wallZ; 17 | var wallGroup = new Zdog.Group({ 18 | addTo: options.addTo, 19 | translate: { z: -wallTZ }, 20 | }); 21 | 22 | var wallPath = [ 23 | { x: -wallX, y: -wallY } 24 | ]; 25 | 26 | if ( options.gable == 'ns' ) { 27 | wallPath.push({ x: 0, y: -wallY - wallX }); 28 | } 29 | 30 | wallPath = wallPath.concat([ 31 | { x: wallX, y: -wallY }, 32 | { x: wallX, y: 0 }, 33 | { x: -wallX, y: 0 }, 34 | ]); 35 | 36 | // wall 37 | new Zdog.Shape({ 38 | path: wallPath, 39 | addTo: wallGroup, 40 | color: isSouth ? red : gold, 41 | }); 42 | 43 | var windowColor = isSouth ? navy : red; 44 | var windowProperty = isSouth ? 'southWindows' : 'northWindows'; 45 | handleWindows( options, windowProperty, wallGroup, windowColor ); 46 | 47 | var wallProperty = isSouth ? 'southWall' : 'northWall'; 48 | building[ wallProperty ] = wallGroup; 49 | 50 | }); 51 | 52 | // east/west wall 53 | [ true, false ].forEach( function( isWest ) { 54 | var wallGroup = new Zdog.Group({ 55 | addTo: options.addTo, 56 | translate: { x: isWest ? -wallX : wallX }, 57 | rotate: { y: TAU/4 }, 58 | }); 59 | 60 | var wallPath = [ 61 | { x: -wallZ, y: -wallY } 62 | ]; 63 | 64 | if ( options.gable == 'ew' ) { 65 | wallPath.push({ x: 0, y: -wallY - wallZ }); 66 | } 67 | 68 | wallPath = wallPath.concat([ 69 | { x: wallZ, y: -wallY }, 70 | { x: wallZ, y: 0 }, 71 | { x: -wallZ, y: 0 }, 72 | ]); 73 | 74 | // wall 75 | new Zdog.Shape({ 76 | path: wallPath, 77 | addTo: wallGroup, 78 | color: isWest ? blue : white, 79 | }); 80 | 81 | var windowColor = isWest ? navy : blue; 82 | var windowProperty = isWest ? 'westWindows' : 'eastWindows'; 83 | handleWindows( options, windowProperty, wallGroup, windowColor ); 84 | 85 | var wallProperty = isWest ? 'westWall' : 'eastWall'; 86 | building[ wallProperty ] = wallGroup; 87 | }); 88 | 89 | 90 | var roofMakers = { 91 | ns: function() { 92 | var y0 = -wallY - wallX; 93 | var roofPanel = new Zdog.Shape({ 94 | path: [ 95 | { x: 0, y: y0, z: wallZ }, 96 | { x: 0, y: y0, z: -wallZ }, 97 | { x: wallX, y: -wallY, z: -wallZ }, 98 | { x: wallX, y: -wallY, z: wallZ }, 99 | ], 100 | addTo: options.addTo, 101 | color: gold, 102 | }); 103 | roofPanel.copy({ 104 | scale: { x: -1 }, 105 | color: navy, 106 | }); 107 | }, 108 | 109 | ew: function() { 110 | var y0 = -wallY - wallZ; 111 | var xA = options.isChurch ? -wallX + 8 : -wallX; 112 | var roofPanel = new Zdog.Shape({ 113 | path: [ 114 | { z: 0, y: y0, x: xA }, 115 | { z: 0, y: y0, x: wallX }, 116 | { z: -wallZ, y: -wallY, x: wallX }, 117 | { z: -wallZ, y: -wallY, x: xA }, 118 | ], 119 | addTo: options.addTo, 120 | color: red, 121 | }); 122 | roofPanel.copy({ 123 | path: [ 124 | { z: 0, y: y0, x: -wallX }, 125 | { z: 0, y: y0, x: wallX }, 126 | { z: -wallZ, y: -wallY, x: wallX }, 127 | { z: -wallZ, y: -wallY, x: -wallX }, 128 | ], 129 | scale: { z: -1 }, 130 | color: navy, 131 | }); 132 | }, 133 | }; 134 | 135 | var roofMaker = roofMakers[ options.gable ]; 136 | if ( roofMaker ) { 137 | roofMaker(); 138 | } 139 | 140 | return building; 141 | }; 142 | 143 | function handleWindows( options, windowProperty, wallGroup, color ) { 144 | var windowOption = options[ windowProperty ]; 145 | if ( !windowOption ) { 146 | return; 147 | } 148 | 149 | var columns = windowOption[0]; 150 | var rows = windowOption[1]; 151 | // var windowPaths = []; 152 | for ( var row=0; row < rows; row++ ) { 153 | for ( var col=0; col < columns; col++ ) { 154 | var x = ( col - (columns-1)/2 ) * 6; 155 | var y = -options.height + (row + 0.75) * 8; 156 | var windowPath = [ 157 | { x: x + -1, y: y + -2 }, 158 | { x: x + 1, y: y + -2 }, 159 | { x: x + 1, y: y + 2 }, 160 | { x: x + -1, y: y + 2 }, 161 | ]; 162 | new Zdog.Shape({ 163 | path: windowPath, 164 | addTo: wallGroup, 165 | color: color, 166 | }); 167 | } 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /demo/la-link/la-link.js: -------------------------------------------------------------------------------- 1 | // ------------------------- demo ------------------------- // 2 | 3 | var illoElem = document.querySelector('.zdog-canvas'); 4 | var sceneSize = 128; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.floor( minWindowSize / sceneSize ); 7 | var illoSize = sceneSize * zoom; 8 | illoElem.setAttribute( 'width', illoSize ); 9 | illoElem.setAttribute( 'height', illoSize ); 10 | var isSpinning = false; 11 | var TAU = Zdog.TAU; 12 | 13 | // colors 14 | var skinTone = '#FEA'; 15 | var amber = '#FB2'; 16 | var green = '#462'; 17 | var blue = '#59F'; 18 | // var brown = '#743'; 19 | var brown = '#832'; 20 | var black = '#222'; 21 | var yellow = '#FF4'; 22 | var silver = '#ABB'; 23 | var lightGreen = '#3A4'; 24 | var white = '#DDD'; 25 | 26 | var illo = new Zdog.Illustration({ 27 | element: illoElem, 28 | zoom: zoom, 29 | dragRotate: true, 30 | resize: 'fullscreen', 31 | onDragStart: function() { 32 | isSpinning = false; 33 | }, 34 | onResize: function( width, height ) { 35 | this.zoom = Math.floor( Math.min( width, height ) / sceneSize ); 36 | }, 37 | }); 38 | 39 | // ----- head ----- // 40 | 41 | var headAnchor = new Zdog.Anchor({ 42 | addTo: illo, 43 | }); 44 | 45 | // face 46 | var face = new Zdog.Hemisphere({ 47 | addTo: headAnchor, 48 | diameter: 38, 49 | rotate: { x: -TAU/8 }, 50 | color: skinTone, 51 | backface: amber, 52 | stroke: false, 53 | }); 54 | 55 | // used for copying one side the other 56 | var headSide = new Zdog.Anchor({ 57 | addTo: headAnchor, 58 | }); 59 | 60 | var eye = new Zdog.Ellipse({ 61 | addTo: headSide, 62 | width: 3, 63 | height: 8, 64 | translate: { x: -6, y: 2, z: 18 }, 65 | color: black, 66 | fill: true, 67 | backface: false, 68 | }); 69 | 70 | var brow = new Zdog.Shape({ 71 | addTo: eye, 72 | path: [ 73 | { x: -3, y: -1, z: -1 }, 74 | { arc: [ 75 | { x: -2, y: -3 }, 76 | { x: 3, y: 0.5 }, 77 | ]}, 78 | ], 79 | color: brown, 80 | translate: { x: -1, y: -6 }, 81 | fill: true, 82 | }); 83 | 84 | // mouth 85 | new Zdog.Shape({ 86 | addTo: headAnchor, 87 | path: [ 88 | { x: -3 }, 89 | { arc: [ 90 | { y: -2, z: 1 }, 91 | { x: 3 }, 92 | ]}, 93 | ], 94 | closed: false, 95 | translate: { y: 11, z: 15 }, 96 | color: brown, 97 | }); 98 | 99 | // big bang lock 100 | new Zdog.Shape({ 101 | addTo: headAnchor, 102 | path: [ 103 | { x: 0 }, 104 | { arc: [ 105 | { x: -12, y: -4, z: 4 }, 106 | { x: -24, y: 6, z: -4 }, 107 | ]}, 108 | { arc: [ 109 | { x: -12, y: -8, z: -2 }, 110 | { x: 0, y: -4, z: -4 } 111 | ]}, 112 | ], 113 | translate: { x: 4, y: -16, z: 19 }, 114 | fill: true, 115 | color: amber, 116 | stroke: 12, 117 | }); 118 | 119 | // front part lock 120 | new Zdog.Shape({ 121 | addTo: headAnchor, 122 | path: [ 123 | { y: 0 }, 124 | { arc: [ 125 | { x: 4, y: 0, z: 2 }, 126 | { x: 10, y: 14, z: -6 }, 127 | ]}, 128 | { arc: [ 129 | { x: 4, y: 0, z: -4 }, 130 | { y: -2, z: -4 }, 131 | ]} 132 | ], 133 | translate: { x: 12, y: -15, z: 15 }, 134 | fill: true, 135 | color: amber, 136 | stroke: 10, 137 | }); 138 | 139 | // hair crown 140 | // new Zdog.Ellipse({ 141 | // addTo: face, 142 | // width: 24, 143 | // height: 12, 144 | // translate: { y: -12, z: -9 }, 145 | // color: amber, 146 | // stroke: 18, 147 | // fill: true, 148 | // }); 149 | 150 | // ear 151 | new Zdog.Shape({ 152 | addTo: headSide, 153 | path: [ 154 | { x: 0 }, 155 | { arc: [ 156 | { x: -2, y: -2 }, 157 | { x: -4, y: -1 }, 158 | ]}, 159 | { arc: [ 160 | { x: -2, y: 4 }, 161 | { x: 0, y: 4, z: -4 }, 162 | ]}, 163 | ], 164 | scale: { x: 3 }, 165 | translate: { x: -18, y: 2, z: 2 }, 166 | rotate: { y: TAU/8 }, 167 | color: skinTone, 168 | stroke: 4, 169 | fill: true, 170 | }); 171 | 172 | // side down lock 173 | new Zdog.Shape({ 174 | addTo: headSide, 175 | path: [ 176 | { y: 0 }, 177 | { arc: [ 178 | { y: 6 }, 179 | { x: -1, y: 16, z: -2 }, 180 | ]}, 181 | ], 182 | closed: false, 183 | translate: { x: -19, z: 5 }, 184 | stroke: 6, 185 | color: amber, 186 | }); 187 | 188 | // crown hair gap 189 | new Zdog.Shape({ 190 | addTo: headSide, 191 | path: [ 192 | { x: -1 }, 193 | { arc: [ 194 | { x: -1, y: -1 }, 195 | { x: 0, y: -1 }, 196 | ]}, 197 | ], 198 | closed: false, 199 | scale: { x: 14, y: 12 }, 200 | translate: { y: -8 }, 201 | rotate: { x: -TAU/32 }, 202 | color: amber, 203 | stroke: 20, 204 | }) 205 | 206 | headSide.copyGraph({ 207 | scale: { x: -1 }, 208 | }); 209 | 210 | // ----- animate ----- // 211 | 212 | function animate() { 213 | illo.rotate.y += isSpinning ? +TAU/150 : 0; 214 | illo.updateRenderGraph(); 215 | requestAnimationFrame( animate ); 216 | } 217 | 218 | animate(); 219 | 220 | -------------------------------------------------------------------------------- /demo/tri-prism/tri-prism.js: -------------------------------------------------------------------------------- 1 | // ----- setup ----- // 2 | 3 | var illoCanvas = document.querySelector('.illo'); 4 | var proxyCanvas = document.createElement('canvas'); 5 | var ctx = illoCanvas.getContext('2d'); 6 | var illoSize = 14 * Math.sqrt(2); 7 | var minWindowSize = Math.min( window.innerWidth - 20, window.innerHeight - 20 ); 8 | var zoom = Math.floor( minWindowSize / illoSize ); 9 | 10 | var canvasWidth = illoCanvas.width = illoSize * zoom; 11 | var canvasHeight = illoCanvas.height = illoSize * zoom; 12 | var shrink = 1/3; 13 | proxyCanvas.width = canvasWidth * shrink; 14 | proxyCanvas.height = canvasHeight * shrink; 15 | var TAU = Zdog.TAU; 16 | 17 | var illo = new Zdog.Illustration({ 18 | element: proxyCanvas, 19 | rotate: { x: -35/360 * TAU, y: 45/360 * TAU }, 20 | zoom: zoom, 21 | }); 22 | 23 | var isSpinning = false; 24 | 25 | var navy = '#456'; 26 | var red = '#D21'; 27 | var orange = '#F90'; 28 | 29 | // ----- model ----- // 30 | 31 | function makePrism( options ) { 32 | var prism = new Zdog.Anchor({ 33 | addTo: illo, 34 | rotate: options.rotate, 35 | }); 36 | 37 | var rotor = new Zdog.Anchor({ 38 | addTo: prism, 39 | }); 40 | 41 | var positioner = new Zdog.Anchor({ 42 | addTo: rotor, 43 | translate: { z: 1, y: -1 }, 44 | }); 45 | 46 | var triangle = new Zdog.Shape({ 47 | addTo: positioner, 48 | path: [ 49 | { z: 1, y: 1 }, 50 | { z: -1, y: -1 }, 51 | { z: -1, y: 1 }, 52 | ], 53 | color: red, 54 | fill: true, 55 | stroke: 1/zoom, 56 | }); 57 | triangle.copy({ 58 | translate: { x: -2 }, 59 | color: navy, 60 | }); 61 | 62 | // slope 63 | new Zdog.Shape({ 64 | addTo: positioner, 65 | path: [ 66 | { x: -2, y: 1, z: 1 }, 67 | { x: -2, y: -1, z: -1 }, 68 | { x: 0, y: -1, z: -1 }, 69 | { x: 0, y: 1, z: 1 }, 70 | ], 71 | color: orange, 72 | fill: true, 73 | stroke: 1/zoom, 74 | }); 75 | 76 | var base = new Zdog.Rect({ 77 | addTo: positioner, 78 | width: 2, 79 | height: 2, 80 | translate: { x: -1, z: -1 }, 81 | rotate: { y: TAU/2 }, 82 | color: navy, 83 | fill: true, 84 | stroke: 1/zoom, 85 | backface: false, 86 | }); 87 | base.copy({ 88 | translate: { x: -1, y: 1 }, 89 | rotate: { x: -TAU/4 }, 90 | color: red, 91 | }); 92 | 93 | return prism; 94 | } 95 | 96 | var prismA = makePrism({}); 97 | 98 | var prismB = makePrism({ 99 | rotate: { x: TAU/4, z: TAU/4 }, 100 | }); 101 | 102 | var prismC = makePrism({ 103 | rotate: { y: -TAU/4, z: -TAU/4 }, 104 | }); 105 | 106 | // -- animate --- // 107 | 108 | var t = 0; 109 | var tSpeed = 1/80; 110 | 111 | // -- update -- // 112 | 113 | var keyframes = [ 114 | { x: 0, y: 0, z: 0 }, 115 | { x: 1, y: 0, z: 0 }, 116 | { x: 1, y: -1, z: 0 }, 117 | { x: 1, y: -2, z: 0 }, 118 | { x: 1, y: -2, z: -1 }, 119 | { x: 1, y: -2, z: -2 }, 120 | { x: 2, y: -2, z: -2 }, 121 | ]; 122 | 123 | function transform( shape, turn, alpha ) { 124 | var keyA = keyframes[ turn ]; 125 | var keyB = keyframes[ turn + 1 ]; 126 | shape.rotate.x = Zdog.lerp( keyA.x, keyB.x, alpha ) * TAU/4; 127 | shape.rotate.y = Zdog.lerp( keyA.y, keyB.y, alpha ) * TAU/4; 128 | shape.rotate.z = Zdog.lerp( keyA.z, keyB.z, alpha ) * TAU/4; 129 | } 130 | 131 | function update() { 132 | var easeT = Zdog.easeInOut( t % 1, 4 ); 133 | var turn = Math.floor( t % 6 ); 134 | 135 | transform( prismA.children[0], turn, easeT ); 136 | transform( prismB.children[0], turn, easeT ); 137 | transform( prismC.children[0], turn, easeT ); 138 | 139 | t += tSpeed; 140 | 141 | illo.updateGraph(); 142 | } 143 | 144 | // -- render -- // 145 | 146 | var shiftX = Math.round( 3 * Math.sqrt(2) * zoom ); 147 | var shiftY = Math.round( 2 * Math.sqrt(2) * Math.sqrt(3)/2 * zoom ); 148 | 149 | function render() { 150 | illo.renderGraph(); 151 | 152 | ctx.clearRect( 0, 0, canvasWidth, canvasHeight ); 153 | 154 | ctx.save(); 155 | var center = Math.round( illoSize * shrink * zoom ); 156 | ctx.translate( center, center ); 157 | 158 | for ( var col = -2; col < 3; col++ ) { 159 | for ( var row = -2; row < 3; row++ ) { 160 | var x = col * shiftX; 161 | var y = ( row * 2 + col % 2 ) * shiftY; 162 | ctx.drawImage( illo.element, x, y ); 163 | } 164 | } 165 | 166 | ctx.restore(); 167 | } 168 | 169 | function animate() { 170 | update(); 171 | render(); 172 | requestAnimationFrame( animate ); 173 | } 174 | 175 | animate(); 176 | 177 | // ----- inputs ----- // 178 | 179 | // click drag to rotate 180 | var dragStartRX, dragStartRY; 181 | 182 | new Zdog.Dragger({ 183 | startElement: illoCanvas, 184 | onDragStart: function() { 185 | isSpinning = false; 186 | dragStartRX = illo.rotate.x; 187 | dragStartRY = illo.rotate.y; 188 | }, 189 | onDragMove: function( pointer, moveX, moveY ) { 190 | illo.rotate.x = dragStartRX - moveY / canvasWidth * TAU; 191 | illo.rotate.y = dragStartRY - moveX / canvasWidth * TAU; 192 | }, 193 | }); 194 | 195 | -------------------------------------------------------------------------------- /demo/sauropod/sauropod.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 104; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.min( 5, Math.floor( minWindowSize / illoSize ) ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | var isSpinning = true; 10 | var TAU = Zdog.TAU; 11 | // ratio to make things look square when rotated a quarter 12 | var antiTwist = 1 / Math.cos( TAU/8 ); 13 | // colors 14 | var blue = '#19F'; 15 | 16 | var initialRotate = { y: TAU/8 }; 17 | 18 | var illo = new Zdog.Illustration({ 19 | element: illoElem, 20 | zoom: zoom, 21 | scale: { x: antiTwist, z: antiTwist }, 22 | rotate: initialRotate, 23 | dragRotate: true, 24 | onDragStart: function() { 25 | isSpinning = false; 26 | }, 27 | }); 28 | 29 | // -- illustration shapes --- // 30 | 31 | // front right leg 32 | var leg = new Zdog.Shape({ 33 | path: [ 34 | { x: -8, y: 0 }, 35 | { arc: [ 36 | { x: 0, y: 0 }, 37 | { x: 0, y: 8 } 38 | ]}, 39 | { arc: [ 40 | { z: 0, y: 0 }, 41 | { z: -8, y: 0 } 42 | ]}, 43 | { move: { y: -4 } }, 44 | { line: { y: 12 } }, 45 | ], 46 | addTo: illo, 47 | translate: { x: 16, y: 16, z: 8 }, 48 | stroke: 8, 49 | color: blue, 50 | closed: false, 51 | }); 52 | // front left leg 53 | leg.copy({ 54 | translate: { x: 16, y: 16, z: -8 }, 55 | rotate: { y: -TAU/4 }, 56 | }); 57 | // back right leg 58 | leg.copy({ 59 | translate: { x: -16, y: 16, z: 8 }, 60 | rotate: { y: TAU/4 }, 61 | }); 62 | // back left leg 63 | leg.copy({ 64 | translate: { x: -16, y: 16, z: -8 }, 65 | rotate: { y: -TAU/2 }, 66 | }); 67 | 68 | 69 | // leg connectors 70 | var legConnector = new Zdog.Shape({ 71 | path: [ { x: -8 }, { x: 8 } ], 72 | addTo: illo, 73 | translate: { y: 16, z: 8 }, 74 | stroke: 8, 75 | color: blue, 76 | closed: false, 77 | }); 78 | legConnector.copy({ 79 | translate: { y: 16, z: -8 }, 80 | }); 81 | 82 | // body 83 | new Zdog.Shape({ 84 | path: [ 85 | { x: -1, z: 1 }, 86 | { x: 1, z: 1 }, 87 | { x: 1, z: -1 }, 88 | { x: -1, z: -1 }, 89 | ], 90 | // fudge these numbers 91 | scale: { x: 14.25, z: -3.75 }, 92 | addTo: illo, 93 | translate: { y: 10 }, 94 | stroke: 20, 95 | color: blue, 96 | }); 97 | 98 | // neck squiggle 99 | new Zdog.Shape({ 100 | path: [ 101 | { x: 16, y: 4 }, 102 | { arc: [ 103 | { x: 24, y: 4 }, 104 | { x: 24, y: -4 } 105 | ]}, 106 | { arc: [ 107 | { x: 24, y: -12 }, 108 | { x: 16, y: -12 } 109 | ]}, 110 | { x: -16, y: -12 }, 111 | { arc: [ 112 | { x: -24, y: -12 }, 113 | { x: -24, y: -20 } 114 | ]}, 115 | { arc: [ 116 | { x: -24, y: -28 }, 117 | { x: -16, y: -28 } 118 | ]}, 119 | { x: 24, y: -28 }, 120 | ], 121 | addTo: illo, 122 | stroke: 8, 123 | color: blue, 124 | closed: false, 125 | }); 126 | 127 | // neck 128 | new Zdog.Shape({ 129 | path: [ 130 | { x: -16, y: -28 }, 131 | { x: 24, y: -28 }, 132 | ], 133 | addTo: illo, 134 | stroke: 8, 135 | color: blue, 136 | closed: false, 137 | }); 138 | 139 | // head ball 140 | var head = new Zdog.Shape({ 141 | translate: { x: 16, y: -31 }, 142 | addTo: illo, 143 | stroke: 14, 144 | color: blue, 145 | }); 146 | 147 | // eyes 148 | var eye = new Zdog.Shape({ 149 | addTo: head, 150 | translate: { z: -1, x: 0 }, 151 | color: 'white', 152 | stroke: 4, 153 | fill: true, 154 | closed: false, 155 | }); 156 | eye.copy({ 157 | translate: { z: 1, x: 0 }, 158 | }); 159 | 160 | // tail 161 | new Zdog.Shape({ 162 | path: [ 163 | { x: -16, z: 0 }, 164 | { arc: [ 165 | { x: -24, z: 0 }, 166 | { x: -24, z: -8 }, 167 | ]}, 168 | { arc: [ 169 | { x: -24, z: -16 }, 170 | { x: -16, z: -16 }, 171 | ]}, 172 | { x: -12, z: -16 }, 173 | { arc: [ 174 | { x: -6, z: -16 }, 175 | { x: -6, z: -22 }, 176 | ]}, 177 | { arc: [ 178 | { x: -6, z: -28 }, 179 | { x: -12, z: -28 }, 180 | ]}, 181 | { x: -18, z: -28 }, 182 | ], 183 | addTo: illo, 184 | translate: { y: 4 }, 185 | // rotate: { x: -0.25 }, 186 | color: blue, 187 | stroke: 8, 188 | closed: false, 189 | }); 190 | 191 | // -- animate --- // 192 | 193 | var t = 0; 194 | 195 | function animate() { 196 | // update 197 | if ( isSpinning ) { 198 | var easeT = Zdog.easeInOut( t % 1, 3 ); 199 | illo.rotate.y = easeT*-TAU + TAU/8; 200 | illo.rotate.x = ( Math.cos( easeT * TAU ) * 0.5 + -0.5 ) * TAU/12; 201 | t += 1/210; 202 | } 203 | illo.updateRenderGraph(); 204 | requestAnimationFrame( animate ); 205 | } 206 | 207 | animate(); 208 | 209 | // ----- inputs ----- // 210 | 211 | document.querySelector('.reset-button').onclick = function() { 212 | illo.rotate.set( initialRotate ); 213 | isSpinning = false; 214 | }; 215 | 216 | document.querySelector('.rotate-button').onclick = function() { 217 | isSpinning = true; 218 | t = 0; 219 | }; 220 | 221 | -------------------------------------------------------------------------------- /demo/strutter/strutter.js: -------------------------------------------------------------------------------- 1 | // Made with Zdog 2 | 3 | // ----- setup ----- // 4 | 5 | var illoElem = document.querySelector('.illo'); 6 | var illoSize = 48; 7 | var minWindowSize = Math.min( window.innerWidth - 20 , window.innerHeight - 20 ); 8 | var zoom = Math.floor( minWindowSize / illoSize ); 9 | illoElem.width = illoElem.height = illoSize * zoom; 10 | var isRotating = true; 11 | var TAU = Zdog.TAU; 12 | // colors 13 | var gold = '#EA0'; 14 | var red = '#E21'; 15 | var denim = '#345'; 16 | 17 | var illo = new Zdog.Illustration({ 18 | element: illoElem, 19 | zoom: zoom, 20 | rotate: { y: -TAU/8 }, 21 | translate: { y: 2 }, 22 | dragRotate: true, 23 | onDragStart: function() { 24 | isRotating = false; 25 | }, 26 | }); 27 | 28 | // ----- model ----- // 29 | 30 | var hipX = 3; 31 | 32 | new Zdog.Shape({ 33 | addTo: illo, 34 | path: [ { x: -1 }, { x: 1 } ], 35 | scale: hipX, 36 | color: denim, 37 | stroke: 4, 38 | }); 39 | 40 | var rightLeg = new Zdog.Shape({ 41 | addTo: illo, 42 | path: [ { y: 0 }, { y: 12 } ], 43 | translate: { x: -hipX }, 44 | rotate: { x: TAU/4 }, 45 | color: denim, 46 | stroke: 4, 47 | }); 48 | // foot 49 | new Zdog.RoundedRect({ 50 | addTo: rightLeg, 51 | width: 2, 52 | height: 4, 53 | radius: 1, 54 | translate: { y: 14, z: 2 }, 55 | rotate: { x: TAU/4 }, 56 | color: red, 57 | fill: true, 58 | stroke: 4, 59 | }); 60 | 61 | var plantAngle = -TAU/32 * 3; 62 | var leftLeg = rightLeg.copyGraph({ 63 | translate: { x: hipX }, 64 | rotate: { x: plantAngle }, 65 | color: '#234' 66 | }); 67 | 68 | leftLeg.children[0].rotate.set({ x: TAU/4 - plantAngle }); 69 | 70 | // chest 71 | new Zdog.Shape({ 72 | addTo: illo, 73 | path: [ { x: -1 }, { x: 1 } ], 74 | scale: 1.5, 75 | translate: { y: -5.5, z: -3 }, 76 | color: red, 77 | stroke: 9, 78 | fill: true, 79 | }); 80 | 81 | var armSize = 6; 82 | 83 | [ true, false ].forEach( function( isRight ) { 84 | var xSide = isRight ? -1 : 1; 85 | 86 | var upperArm = new Zdog.Shape({ 87 | addTo: illo, 88 | path: [ { x: 0 }, { x: armSize } ], 89 | scale: { x: xSide }, 90 | translate: { x: 4.5 * xSide, y: -8, z: -4 }, 91 | rotate: isRight ? { y: TAU/8, z: -TAU/16 } : { y: TAU/8 }, 92 | color: denim, 93 | stroke: 4, 94 | }); 95 | 96 | var forearm = new Zdog.Shape({ 97 | addTo: upperArm, 98 | path: [ { x: 0 }, { x: armSize-2 } ], 99 | translate: { x: armSize }, 100 | rotate: isRight ? { z: TAU/16 * 3, y: TAU/4 } : { z: -TAU/4, x: -TAU/32 * 2, y: TAU/8 }, 101 | color: red, 102 | stroke: 4, 103 | }); 104 | // hand 105 | new Zdog.Shape({ 106 | addTo: forearm, 107 | translate: { x: armSize, z: 1 }, 108 | stroke: 6, 109 | color: gold, 110 | }); 111 | 112 | }); 113 | 114 | var head = new Zdog.Anchor({ 115 | addTo: illo, 116 | translate: { y: -12, z: -10 }, 117 | rotate: { x: TAU/8 }, 118 | }); 119 | 120 | // face 121 | new Zdog.Hemisphere({ 122 | addTo: head, 123 | diameter: 12, 124 | color: gold, 125 | backface: red, 126 | rotate: { x: -TAU/4 }, 127 | stroke: false, 128 | }); 129 | 130 | var eye = new Zdog.Ellipse({ 131 | addTo: head, 132 | width: 2, 133 | height: 2, 134 | quarters: 2, 135 | translate: { x: -2, y: 1.5, z: 5 }, 136 | rotate: { z: -TAU/4 }, 137 | color: denim, 138 | stroke: 0.5, 139 | backface: false, 140 | }); 141 | eye.copy({ 142 | translate: { x: 2, y: 1.5, z: 5 }, 143 | rotate: { z: -TAU/4 }, 144 | }); 145 | // smile 146 | new Zdog.Ellipse({ 147 | addTo: head, 148 | width: 3, 149 | height: 3, 150 | quarters: 2, 151 | translate: { y: 3, z: 4.5 }, 152 | rotate: { z: TAU/4 }, 153 | closed: true, 154 | color: '#FED', 155 | stroke: 0.5, 156 | fill: true, 157 | backface: false, 158 | }); 159 | 160 | new Zdog.Hemisphere({ 161 | addTo: head, 162 | diameter: 12, 163 | color: red, 164 | backface: gold, 165 | rotate: { x: TAU/4 }, 166 | stroke: false, 167 | }); 168 | 169 | var brim = new Zdog.Anchor({ 170 | addTo: head, 171 | scale: 5.5, 172 | translate: { y: -0.5, z: 6 }, 173 | }); 174 | 175 | new Zdog.Shape({ 176 | addTo: brim, 177 | path: [ 178 | { x: 0, z: 0 }, 179 | { arc: [ 180 | { x: -1, z: 0 }, 181 | { x: -1, z: -1 }, 182 | ]}, 183 | { x: -1, z: 0 }, 184 | ], 185 | color: denim, 186 | fill: true, 187 | }); 188 | 189 | new Zdog.Shape({ 190 | addTo: brim, 191 | path: [ 192 | { x: -1, z: 0 }, 193 | { arc: [ 194 | { x: -1, z: 1 }, 195 | { x: 0, z: 1 }, 196 | ]}, 197 | { x: 0, z: 0 }, 198 | ], 199 | color: denim, 200 | fill: true, 201 | }); 202 | 203 | brim.copyGraph({ 204 | scale: brim.scale.copy().multiply({ x: -1 }), 205 | }); 206 | 207 | 208 | // ----- model ----- // 209 | 210 | var ticker = 0; 211 | var cycleCount = 150; 212 | 213 | function animate() { 214 | if ( isRotating ) { 215 | var progress = ticker / cycleCount; 216 | var tween = Zdog.easeInOut( progress % 1, 4 ); 217 | illo.rotate.y = tween * TAU - TAU/8; 218 | ticker++; 219 | } 220 | illo.updateRenderGraph(); 221 | requestAnimationFrame( animate ); 222 | } 223 | 224 | animate(); 225 | 226 | -------------------------------------------------------------------------------- /demo/crypto-kitty/crypto-kitty.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 64; 5 | var minWindowSize = Math.min( window.innerWidth - 20, window.innerHeight - 80 ); 6 | var zoom = Math.floor( minWindowSize / illoSize ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | rotate: { x: -TAU/32 }, 17 | dragRotate: true, 18 | onDragStart: function() { 19 | isSpinning = false; 20 | }, 21 | }); 22 | 23 | // colors 24 | var magenta = '#F49'; 25 | var midnight = '#103'; 26 | var white = 'white'; 27 | 28 | 29 | // -- illustration shapes --- // 30 | 31 | var cat = new Zdog.Group({ 32 | addTo: illo, 33 | updateSort: true, 34 | }); 35 | 36 | // body 37 | new Zdog.Shape({ 38 | path: [ { y: -1 }, { y: 1} ], 39 | scale: { y: 3 }, 40 | addTo: cat, 41 | stroke: 14, 42 | color: magenta, 43 | }); 44 | 45 | var face = new Zdog.Anchor({ 46 | addTo: cat, 47 | translate: { y: -4, z: 6.5 }, 48 | }); 49 | 50 | // nose 51 | new Zdog.Shape({ 52 | path: [ 53 | { x: -1 }, 54 | { x: 1 }, 55 | { y: 1 }, 56 | ], 57 | scale: { x: 0.25, y: 0.25 }, 58 | addTo: face, 59 | translate: { z: 1.5 }, 60 | stroke: 1, 61 | color: midnight, 62 | }); 63 | 64 | // tummy 65 | new Zdog.RoundedRect({ 66 | width: 5, 67 | height: 7, 68 | cornerRadius: 2.5, 69 | addTo: cat, 70 | translate: { y: 3.5, z: 5 }, 71 | // rotate: { x: TAU/64 }, 72 | color: white, 73 | stroke: 3, 74 | fill: true, 75 | }); 76 | 77 | // chin 78 | new Zdog.Shape({ 79 | path: [ { x: -1 }, { x: 1 } ], 80 | scale: { x: 2 }, 81 | addTo: cat, 82 | translate: { y: -3, z: 4 }, 83 | stroke: 4, 84 | color: magenta, 85 | }); 86 | 87 | // tail 88 | new Zdog.Shape({ 89 | path: [ { y: 0 }, { y: 8 } ], 90 | addTo: cat, 91 | translate: { y: 7, z: -4 }, 92 | rotate: { x: -TAU/32 }, 93 | stroke: 1, 94 | color: magenta, 95 | }); 96 | 97 | var backLine = new Zdog.Shape({ 98 | path: [ { x: -1 }, { x: 1 } ], 99 | scale: { x: 3 }, 100 | addTo: cat, 101 | translate: { y: 0, z: -6.5 }, 102 | stroke: 0.5, 103 | color: '#F7A', 104 | }); 105 | backLine.copy({ 106 | translate: { y: -3, z: -6.5 }, 107 | }); 108 | backLine.copy({ 109 | translate: { y: 3, z: -6.5 }, 110 | }); 111 | 112 | [ -1, 1 ].forEach( function( xSide ) { 113 | // eye 114 | new Zdog.Shape({ 115 | path: [ { y: -1 }, { y: 1} ], 116 | scale: { y: 0.3 }, 117 | addTo: face, 118 | translate: { x: 0.75*xSide, y: -1.5 }, 119 | stroke: 0.8, 120 | color: midnight, 121 | }); 122 | 123 | // maw 124 | new Zdog.Shape({ 125 | path: [ { x: -1 }, { x: 1} ], 126 | scale: { x: 0.4 }, 127 | addTo: face, 128 | translate: { x: 1*xSide, y: 0.5, z: 0.5 }, 129 | stroke: 1.5, 130 | color: white, 131 | }); 132 | 133 | // whisker 134 | var whisker = new Zdog.Shape({ 135 | path: [ 136 | { x: 0, y: 0 }, 137 | { x: 1, y: 1 }, 138 | ], 139 | scale: { x: xSide*3, y: 0.75 }, 140 | addTo: face, 141 | translate: { x: 2.5*xSide, y: 0.5 }, 142 | color: white, 143 | stroke: 0.25, 144 | }); 145 | whisker.copy({ 146 | scale: { x: xSide*3, y: -0.75 }, 147 | }); 148 | 149 | // ear 150 | new Zdog.Shape({ 151 | path: [ 152 | { x: 0, y: 0 }, 153 | { x: 1, y: 1 }, 154 | { x: 1, y: -1 }, 155 | ], 156 | scale: { x: 2*xSide, y: 1.5 }, 157 | addTo: cat, 158 | translate: { x: 2*xSide, y: -8 }, 159 | color: magenta, 160 | stroke: 3, 161 | fill: true, 162 | }); 163 | 164 | // arm 165 | var arm = new Zdog.Shape({ 166 | path: [ { y: 0 }, { y: 3.5 } ], 167 | addTo: cat, 168 | translate: { x: 3.5*xSide, y: -1, z: 5.5 }, 169 | rotate: { x: TAU/16 }, 170 | stroke: 3, 171 | color: magenta, 172 | }); 173 | 174 | // leg 175 | arm.copy({ 176 | translate: { x: 3.5*xSide, y: 8, z: 2 }, 177 | rotate: {}, 178 | }); 179 | }); 180 | 181 | var diamondPanel = new Zdog.Shape({ 182 | path: [ 183 | { x: 0, y: 1, z: -0 }, 184 | { x: -1, y: 0, z: 1 }, 185 | { x: 1, y: 0, z: 1 }, 186 | ], 187 | scale: { x: 12, y: 30, z: -12 }, 188 | addTo: illo, 189 | stroke: false, 190 | fill: true, 191 | color: 'hsla(60, 100%, 50%, 0.1)', 192 | }); 193 | diamondPanel.copy({ 194 | rotate: { y: TAU/4*1 }, 195 | color: 'hsla(60, 100%, 50%, 0.2)', 196 | }); 197 | diamondPanel.copy({ 198 | rotate: { y: TAU/4*2 }, 199 | color: 'hsla(60, 100%, 50%, 0.3)', 200 | }); 201 | diamondPanel.copy({ 202 | rotate: { y: TAU/4*3 }, 203 | color: 'hsla(60, 100%, 50%, 0.4)', 204 | }); 205 | diamondPanel.copy({ 206 | scale: { x: 12, y: -30, z: -12 }, 207 | rotate: { y: TAU/4*0 }, 208 | color: 'hsla(60, 100%, 50%, 0.4)', 209 | }); 210 | diamondPanel.copy({ 211 | scale: { x: 12, y: -30, z: -12 }, 212 | rotate: { y: TAU/4*1 }, 213 | color: 'hsla(60, 100%, 50%, 0.3)', 214 | }); 215 | diamondPanel.copy({ 216 | scale: { x: 12, y: -30, z: -12 }, 217 | rotate: { y: TAU/4*2 }, 218 | color: 'hsla(60, 100%, 50%, 0.2)', 219 | }); 220 | diamondPanel.copy({ 221 | scale: { x: 12, y: -30, z: -12 }, 222 | rotate: { y: TAU/4*3 }, 223 | color: 'hsla(60, 100%, 50%, 0.1)', 224 | }); 225 | 226 | // ----- animate ----- // 227 | 228 | function animate() { 229 | illo.rotate.y += isSpinning ? -TAU/150 : 0; 230 | illo.updateRenderGraph(); 231 | requestAnimationFrame( animate ); 232 | } 233 | 234 | animate(); 235 | 236 | -------------------------------------------------------------------------------- /demo/madeline/madeline.js: -------------------------------------------------------------------------------- 1 | /* globals makeMadeline, BokehShape, makeBird */ 2 | 3 | // -------------------------- demo -------------------------- // 4 | 5 | var illoElem = document.querySelector('.illo'); 6 | var w = 160; 7 | var h = 160; 8 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 9 | var zoom = Math.min( 5, Math.floor( minWindowSize / w ) ); 10 | illoElem.setAttribute( 'width', w * zoom ); 11 | illoElem.setAttribute( 'height', h * zoom ); 12 | 13 | var isSpinning = true; 14 | var TAU = Zdog.TAU; 15 | 16 | var illo = new Zdog.Illustration({ 17 | element: illoElem, 18 | zoom: zoom, 19 | rotate: { y: -TAU/4 }, 20 | dragRotate: true, 21 | onDragStart: function() { 22 | isSpinning = false; 23 | }, 24 | }); 25 | 26 | var madColor = { 27 | skin: '#FD9', 28 | hair: '#D53', 29 | parkaLight: '#67F', 30 | parkaDark: '#35D', 31 | tight: '#742', 32 | eye: '#333', 33 | }; 34 | var badColor = { 35 | skin: '#EBC', 36 | hair: '#D4B', 37 | parkaLight: '#85A', 38 | parkaDark: '#527', 39 | tight: '#412', 40 | eye: '#D02', 41 | }; 42 | 43 | var glow = 'hsla(60, 100%, 80%, 0.3)'; 44 | var featherGold = '#FE5'; 45 | 46 | // -- illustration shapes --- // 47 | 48 | makeMadeline( true, madColor, { 49 | addTo: illo, 50 | }); 51 | makeMadeline( false, badColor, { 52 | addTo: illo, 53 | rotate: { y: TAU/2 }, 54 | }); 55 | 56 | 57 | // ----- feather ----- // 58 | 59 | var feather = new Zdog.Group({ 60 | addTo: illo, 61 | rotate: { y: -TAU/4 }, 62 | }); 63 | 64 | ( function() { 65 | 66 | var featherPartCount = 8; 67 | var radius = 12; 68 | var angleX = (TAU/featherPartCount) / 2; 69 | var sector = (TAU * radius)/2 / featherPartCount; 70 | 71 | for ( var i=0; i < featherPartCount; i++ ) { 72 | var curve = Math.cos( (i/featherPartCount) * TAU*3/4 + TAU*1/4 ); 73 | var x = 4 - curve*2; 74 | var y0 = sector/2; 75 | // var y2 = -sector/2; 76 | var isLast = i == featherPartCount - 1; 77 | var y3 = isLast ? sector * -1 : -y0; 78 | var z1 = -radius + 2 + curve*-1.5; 79 | var z2 = isLast ? -radius : -radius; 80 | var barb = new Zdog.Shape({ 81 | path: [ 82 | { x: 0, y: y0, z: -radius }, 83 | { x: x, y: -sector/2, z: z1 }, 84 | { x: x, y: -sector*3/4, z: z1 }, 85 | { x: 0, y: y3, z: z2 }, 86 | ], 87 | addTo: feather, 88 | rotate: { x: angleX * -i + TAU/8 }, 89 | stroke: 1, 90 | color: featherGold, 91 | fill: true, 92 | }); 93 | barb.copy({ 94 | scale: { x: -1 }, 95 | }); 96 | } 97 | 98 | // rachis 99 | var rachis = new Zdog.Ellipse({ 100 | addTo: feather, 101 | diameter: radius*2, 102 | quarters: 2, 103 | rotate: { y: -TAU/4 }, 104 | stroke: 2, 105 | color: featherGold, 106 | }); 107 | rachis.copy({ 108 | stroke: 8, 109 | color: glow, 110 | rotate: { y: -TAU/4, x: -0.5 } 111 | }); 112 | })(); 113 | 114 | // ----- rods ----- // 115 | 116 | ( function() { 117 | 118 | var rodCount = 14; 119 | for ( var i=0; i < rodCount; i++ ) { 120 | var zRotor = new Zdog.Anchor({ 121 | addTo: illo, 122 | rotate: { z: TAU/rodCount * i }, 123 | }); 124 | 125 | var y0 = 32; 126 | var y1 = y0 + 2 + Math.random()*24; 127 | new BokehShape({ 128 | path: [ 129 | { y: y0 }, 130 | { y: y1 }, 131 | ], 132 | addTo: zRotor, 133 | rotate: { x: ( Math.random() * 2 - 1 ) * TAU/8 }, 134 | color: madColor.skin, 135 | stroke: 1, 136 | bokehSize: 6, 137 | bokehLimit: 70, 138 | }); 139 | } 140 | 141 | })(); 142 | 143 | // dots 144 | 145 | ( function() { 146 | var dotCount = 64; 147 | 148 | for ( var i=0; i < dotCount; i++ ) { 149 | var yRotor = new Zdog.Anchor({ 150 | addTo: illo, 151 | rotate: { y: TAU/dotCount * i }, 152 | }); 153 | 154 | new BokehShape({ 155 | path: [ 156 | { z: 40*(1 - Math.random()*Math.random()) + 32 }, 157 | ], 158 | addTo: yRotor, 159 | rotate: { x: ( Math.random() * 2 - 1 ) * TAU*3/16 }, 160 | color: badColor.skin, 161 | stroke: 1 + Math.random(), 162 | bokehSize: 6, 163 | bokehLimit: 74, 164 | }); 165 | } 166 | 167 | })(); 168 | 169 | // ----- birds ----- // 170 | 171 | var birdRotor = new Zdog.Anchor({ 172 | addTo: illo, 173 | rotate: { y: TAU*-1/8 }, 174 | }); 175 | 176 | makeBird({ 177 | addTo: birdRotor, 178 | color: madColor.parkaLight, 179 | spin: TAU/2, 180 | }); 181 | 182 | makeBird({ 183 | addTo: birdRotor, 184 | color: featherGold, 185 | spin: -TAU * 3/8, 186 | }); 187 | 188 | makeBird({ 189 | addTo: birdRotor, 190 | color: 'white', 191 | spin: -TAU/4, 192 | }); 193 | 194 | makeBird({ 195 | addTo: birdRotor, 196 | color: madColor.hair, 197 | spin: -TAU/8, 198 | }); 199 | 200 | makeBird({ 201 | addTo: birdRotor, 202 | color: madColor.parkaDark, 203 | spin: TAU/8, 204 | }); 205 | 206 | // -- animate --- // 207 | 208 | var isSpinning = true; 209 | var rotateSpeed = -TAU/60; 210 | var xClock = 0; 211 | var then = new Date() - 1/60; 212 | 213 | function animate() { 214 | update(); 215 | illo.renderGraph(); 216 | requestAnimationFrame( animate ); 217 | } 218 | 219 | animate(); 220 | 221 | // -- update -- // 222 | 223 | function update() { 224 | var now = new Date(); 225 | var delta = now - then; 226 | // auto rotate 227 | if ( isSpinning ) { 228 | var theta = rotateSpeed/60 * delta * -1; 229 | illo.rotate.y += theta; 230 | xClock += theta/4; 231 | illo.rotate.x = Math.sin( xClock ) * TAU/12; 232 | } 233 | 234 | illo.updateGraph(); 235 | 236 | then = now; 237 | } 238 | 239 | -------------------------------------------------------------------------------- /demo/shade-and-shades/shade-and-shades.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 96; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.min( 8, Math.floor( minWindowSize / illoSize ) ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | var illo = new Zdog.Illustration({ 11 | element: illoElem, 12 | zoom: zoom, 13 | }); 14 | 15 | Zdog.Shape.defaults.closed = false; 16 | Zdog.Shape.defaults.stroke = 3; 17 | Zdog.Ellipse.defaults.stroke = 3; 18 | 19 | var TAU = Zdog.TAU; 20 | var quarterView = 1/Math.sin(TAU/8); 21 | var isRotateXFlat; 22 | var isSpinning = true; 23 | 24 | var illo = new Zdog.Illustration({ 25 | element: illoElem, 26 | zoom: zoom, 27 | onDragStart: function() { 28 | isSpinning = false; 29 | } 30 | }); 31 | 32 | var initialHatRotate = { y: -TAU/8 }; 33 | 34 | var hat = new Zdog.Anchor({ 35 | addTo: illo, 36 | rotate: initialHatRotate, 37 | }); 38 | 39 | illo.setDragRotate( hat ); 40 | 41 | // -- illustration shapes --- // 42 | 43 | // cap top 44 | var capTop = new Zdog.Shape({ 45 | path: [ 46 | { x: -20, y: 4 }, 47 | { x: -20, y: 0 }, 48 | { arc: [ 49 | { x: -20, y: -20 }, 50 | { x: 0, y: -20 }, 51 | ]}, 52 | { arc: [ 53 | { x: 20, y: -20 }, 54 | { x: 20, y: 0 }, 55 | ]}, 56 | { x: 20, y: 4 }, 57 | ], 58 | addTo: illo, 59 | }); 60 | 61 | // cap back 62 | new Zdog.Ellipse({ 63 | addTo: hat, 64 | diameter: 40, 65 | quarters: 2, 66 | translate: { y: 4 }, 67 | rotate: { x: TAU/4, z: -TAU/4 }, 68 | }); 69 | 70 | // brim back arch 71 | new Zdog.Ellipse({ 72 | addTo: hat, 73 | diameter: 32, 74 | quarters: 2, 75 | translate: { y: 4, z: 12 }, 76 | rotate: { z: -TAU/4 }, 77 | }); 78 | 79 | // cap back to brim bottom connect 80 | var brimConnector = new Zdog.Shape({ 81 | path: [ 82 | { x: -20, z: 0 }, 83 | { arc: [ 84 | { x: -20, z: 6 }, 85 | { x: -16, z: 12 }, 86 | ]}, 87 | ], 88 | addTo: hat, 89 | translate: { y: 4 }, 90 | }); 91 | 92 | brimConnector.copy({ 93 | scale: { x: -1 }, 94 | }); 95 | 96 | var brimTip = { x: 0, y: -12, z: 38 }; 97 | 98 | new Zdog.Shape({ 99 | path: [ 100 | { x: 0, y: -12, z: 12 }, 101 | brimTip, 102 | ], 103 | addTo: hat, 104 | }); 105 | 106 | var brimBridge = new Zdog.Shape({ 107 | path: [ 108 | { x: -16, y: 4, z: 12 }, 109 | { x: -16, y: 4, z: 22 }, 110 | { bezier: [ 111 | { x: -16, y: 4, z: 34 }, 112 | { x: -14, y: -12, z: 38 }, 113 | brimTip 114 | ]}, 115 | ], 116 | addTo: hat, 117 | }); 118 | brimBridge.copy({ 119 | scale: { x: - 1}, 120 | }); 121 | 122 | // glasses front top 123 | 124 | new Zdog.Shape({ 125 | path: [ 126 | { x: -1 }, 127 | { x: 1 }, 128 | ], 129 | addTo: hat, 130 | translate: { y: 8, z: 12 }, 131 | scale: { x: 16 }, 132 | }); 133 | 134 | // glass lens 135 | var lensScale = (quarterView - 1) * 0.75 + 1; 136 | var glassLens = new Zdog.Shape({ 137 | path: [ 138 | { x: 0, y: -3 }, 139 | { x: 0, y: 0 }, 140 | { arc: [ 141 | { x: 0, y: 5 }, 142 | { x: 5, y: 5 }, 143 | ]}, 144 | { arc: [ 145 | { x: 10, y: 5 }, 146 | { x: 10, y: 0 }, 147 | ]}, 148 | { x: 10, y: -3 }, 149 | ], 150 | addTo: hat, 151 | translate: { x: -16, y: 11, z: 12 }, 152 | scale: { x: lensScale }, 153 | }); 154 | 155 | glassLens.copy({ 156 | translate: { x: 16, y: 11, z: 12 }, 157 | scale: { x: -lensScale }, 158 | }); 159 | 160 | var glassesArm = new Zdog.Shape({ 161 | path: [ 162 | { x: 12, y: 0 }, 163 | { x: -1, y: 0 }, 164 | { arc: [ 165 | { x: -1 - 8*quarterView, y: 0 }, 166 | { x: -1 - 8*quarterView, y: 8 }, 167 | ]}, 168 | ], 169 | addTo: hat, 170 | translate: { x: -16, y: 8 }, 171 | rotate: { y: TAU/4 }, 172 | // only see one arm at time 173 | backface: false, 174 | }); 175 | glassesArm.copy({ 176 | scale: { x: -1 }, 177 | translate: { x: 16, y: 8 }, 178 | rotate: { y: -TAU/4 }, 179 | }); 180 | 181 | // -- animate --- // 182 | 183 | var t = 0; 184 | var cycleFrame = 240; 185 | 186 | function animate() { 187 | update(); 188 | render(); 189 | requestAnimationFrame( animate ); 190 | } 191 | 192 | animate(); 193 | 194 | // -- update -- // 195 | 196 | 197 | function update() { 198 | 199 | 200 | if ( isSpinning ) { 201 | t += 1/cycleFrame; 202 | t = t % 1; 203 | var isFirstHalf = t < 0.5; 204 | var halfT = isFirstHalf ? t : 1 - t; 205 | halfT /= 0.5; 206 | var easeT = Zdog.easeInOut( halfT, 3 ); 207 | hat.rotate.y = easeT*TAU/4 - TAU/8; 208 | var rxDirection = isFirstHalf ? 1 : 0; 209 | hat.rotate.x = (Math.cos( halfT * TAU ) * -0.5 + 0.5 ) * -TAU/16 * rxDirection; 210 | } 211 | 212 | // normalize camera angle 213 | hat.normalizeRotate(); 214 | 215 | var rx = hat.rotate.x; 216 | isRotateXFlat = rx < TAU/16 || rx > TAU * 15/16; 217 | // flip cap top 218 | var isRotateXTopSide = rx < TAU/4 || rx > TAU * 3/4; 219 | capTop.scale.y = isRotateXTopSide ? 1 : -1; 220 | 221 | illo.updateGraph(); 222 | } 223 | 224 | // -- render -- // 225 | 226 | function render() { 227 | var ctx = illo.ctx; 228 | ctx.globalCompositeOperation = 'source-over'; 229 | illo.renderGraph(); 230 | 231 | // render gradient 232 | ctx.globalCompositeOperation = 'source-in'; 233 | var gradient = ctx.createLinearGradient( 0, 0, 0, illo.height ); 234 | gradient.addColorStop( 0.2, '#F00' ); 235 | gradient.addColorStop( 0.75, '#19F' ); 236 | ctx.fillStyle = gradient; 237 | ctx.fillRect( 0, 0, illo.width, illo.height ); 238 | } 239 | 240 | // ----- inputs ----- // 241 | 242 | document.querySelector('.reset-button').onclick = function() { 243 | hat.rotate.set( initialHatRotate ); 244 | }; 245 | -------------------------------------------------------------------------------- /demo/santorini/make-building.js: -------------------------------------------------------------------------------- 1 | /* jshint unused: false */ 2 | /* globals makeWindow */ 3 | 4 | // translate 5 | // width, 6 | // height 7 | // depth 8 | // nsWindows: function() {} 9 | // ewWindows: function() {} 10 | // gable: flat, ew, ns, slantS, slandN 11 | 12 | var TAU = Zdog.TAU; 13 | // colors 14 | var white = 'white'; 15 | var southWall = white; 16 | var westWall = '#CDE'; 17 | var eastWall = '#8AD'; 18 | var roof = '#06B'; 19 | var northWall = '#58C'; 20 | var navy = '#037'; 21 | var midnight = '#024'; 22 | 23 | 24 | function makeBuilding( options ) { 25 | 26 | var wallX = options.width/2; 27 | var wallY = options.height; 28 | var wallZ = options.depth/2; 29 | 30 | // south/noth walls 31 | [ true, false ].forEach( function( isSouth ) { 32 | var wallTZ = isSouth ? -wallZ : wallZ; 33 | var wallGroup = new Zdog.Group({ 34 | addTo: options.addTo, 35 | translate: { z: wallTZ }, 36 | }); 37 | 38 | var wallPath = [ 39 | { x: -wallX, y: -wallY } 40 | ]; 41 | 42 | if ( options.gable == 'ns' ) { 43 | wallPath.push({ x: 0, y: -wallY - wallX }); 44 | } else if ( options.gable == 'slantS' && !isSouth ) { 45 | wallPath.push({ x: -wallX, y: -wallY - wallZ*2 }); 46 | wallPath.push({ x: wallX, y: -wallY - wallZ*2 }); 47 | } 48 | 49 | wallPath = wallPath.concat([ 50 | { x: wallX, y: -wallY }, 51 | { x: wallX, y: 0 }, 52 | { x: -wallX, y: 0 }, 53 | ]); 54 | 55 | // wall 56 | new Zdog.Shape({ 57 | path: wallPath, 58 | addTo: wallGroup, 59 | color: isSouth ? southWall : northWall, 60 | }); 61 | 62 | var windowColor = isSouth ? navy : midnight; 63 | handleWindows( options.nsWindows, wallGroup, windowColor ); 64 | 65 | // cap border 66 | if ( options.gable == 'cap' ) { 67 | new Zdog.Rect({ 68 | width: options.width, 69 | height: 2, 70 | addTo: wallGroup, 71 | translate: { y: -wallY - 1 }, 72 | color: isSouth ? roof : midnight, 73 | }); 74 | } 75 | 76 | }); 77 | 78 | // east/west wall 79 | [ true, false ].forEach( function( isWest ) { 80 | var wallGroup = new Zdog.Group({ 81 | addTo: options.addTo, 82 | translate: { x: isWest ? -wallX : wallX }, 83 | rotate: { y: TAU/4 }, 84 | }); 85 | 86 | var wallPath = [ 87 | { x: -wallZ, y: -wallY } 88 | ]; 89 | 90 | if ( options.gable == 'ew' ) { 91 | wallPath.push({ x: 0, y: -wallY - wallZ }); 92 | } else if ( options.gable == 'slantS' ) { 93 | wallPath.push({ x: wallZ, y: -wallY - wallZ*2 }); 94 | } 95 | 96 | wallPath = wallPath.concat([ 97 | { x: wallZ, y: -wallY }, 98 | { x: wallZ, y: 0 }, 99 | { x: -wallZ, y: 0 }, 100 | ]); 101 | 102 | // wall 103 | new Zdog.Shape({ 104 | path: wallPath, 105 | addTo: wallGroup, 106 | color: isWest ? westWall : eastWall, 107 | }); 108 | 109 | var windowColor = isWest ? navy : midnight; 110 | handleWindows( options.ewWindows, wallGroup, windowColor ); 111 | 112 | // cap border 113 | if ( options.gable == 'cap' ) { 114 | new Zdog.Rect({ 115 | width: options.depth, 116 | height: 2, 117 | addTo: wallGroup, 118 | translate: { y: -wallY - 1 }, 119 | color: isWest ? roof : midnight, 120 | }); 121 | } 122 | 123 | }); 124 | 125 | 126 | var roofMakers = { 127 | ns: function() { 128 | var y0 = -wallY - wallX; 129 | var roofPanel = new Zdog.Shape({ 130 | path: [ 131 | { x: 0, y: y0, z: -wallZ }, 132 | { x: 0, y: y0, z: wallZ }, 133 | { x: wallX, y: -wallY, z: wallZ }, 134 | { x: wallX, y: -wallY, z: -wallZ }, 135 | ], 136 | addTo: options.addTo, 137 | color: roof, 138 | }); 139 | roofPanel.copy({ 140 | scale: { x: -1 }, 141 | }); 142 | }, 143 | 144 | ew: function() { 145 | var y0 = -wallY - wallZ; 146 | var roofPanel = new Zdog.Shape({ 147 | path: [ 148 | { z: 0, y: y0, x: -wallX }, 149 | { z: 0, y: y0, x: wallX }, 150 | { z: wallZ, y: -wallY, x: wallX }, 151 | { z: wallZ, y: -wallY, x: -wallX }, 152 | ], 153 | addTo: options.addTo, 154 | color: roof, 155 | }); 156 | roofPanel.copy({ 157 | scale: { z: -1 }, 158 | }); 159 | }, 160 | 161 | slantS: function() { 162 | var roofY0 = -wallY; 163 | var roofY1 = -wallY - wallZ*2; 164 | new Zdog.Shape({ 165 | path: [ 166 | { x: -wallX, y: roofY0, z: -wallZ }, 167 | { x: wallX, y: roofY0, z: -wallZ }, 168 | { x: wallX, y: roofY1, z: wallZ }, 169 | { x: -wallX, y: roofY1, z: wallZ }, 170 | ], 171 | addTo: options.addTo, 172 | color: roof, 173 | }); 174 | }, 175 | 176 | flat: function() { 177 | new Zdog.Rect({ 178 | width: options.width, 179 | height: options.depth, 180 | addTo: options.addTo, 181 | translate: { y: -wallY }, 182 | rotate: { x: TAU/4 }, 183 | color: roof, 184 | }); 185 | }, 186 | 187 | cap: function() { 188 | new Zdog.Rect({ 189 | width: options.width, 190 | height: options.depth, 191 | addTo: options.addTo, 192 | translate: { y: -wallY - 2 }, 193 | rotate: { x: TAU/4 }, 194 | color: roof, 195 | }); 196 | }, 197 | }; 198 | 199 | var roofMaker = roofMakers[ options.gable ]; 200 | if ( roofMaker ) { 201 | roofMaker(); 202 | } 203 | 204 | } 205 | 206 | 207 | function handleWindows( windows, wallGroup, color ) { 208 | windows = windows || []; 209 | windows.forEach( function( windowOption ) { 210 | var x = windowOption.x || 0; 211 | var y = windowOption.y || -5; 212 | var height = windowOption.height || 4; 213 | makeWindow({ 214 | style: windowOption.style, 215 | addTo: wallGroup, 216 | height: height, 217 | translate: { x: x, y: y }, 218 | color: color, 219 | }); 220 | }); 221 | } 222 | -------------------------------------------------------------------------------- /demo/solid-shifter/shifter.js: -------------------------------------------------------------------------------- 1 | var navy = '#369'; 2 | var green = '#692'; 3 | var egg = '#FED'; 4 | var ochre = '#E83'; 5 | 6 | var TAU = Zdog.TAU; 7 | 8 | [ Zdog.Shape, Zdog.Rect, Zdog.Ellipse, Zdog.Cylinder, Zdog.Cone ] 9 | .forEach( function( ItemClass ) { 10 | ItemClass.defaults.fill = true; 11 | ItemClass.defaults.stroke = false; 12 | } 13 | ); 14 | 15 | 16 | // triangle 17 | var isoTriangle = new Zdog.Shape({ 18 | path: [ 19 | { x: 1, y: 1 }, 20 | { x: -1, y: 1 }, 21 | { x: 0, y: -1 }, 22 | ], 23 | color: egg, 24 | }); 25 | 26 | function Shifter( options ) { 27 | 28 | var shifterAnchor = this.anchor = new Zdog.Anchor( options ); 29 | 30 | this.pyramid = ( function() { 31 | var pyramid = new Zdog.Group({ 32 | addTo: shifterAnchor, 33 | visible: false, 34 | // translate: { x: -3, y: -3 }, 35 | updateSort: true, 36 | }); 37 | 38 | var base = new Zdog.Rect({ 39 | addTo: pyramid, 40 | width: 2, 41 | height: 2, 42 | translate: { y: 1 }, 43 | rotate: { x: -TAU/4 }, 44 | color: navy, 45 | }); 46 | 47 | 48 | var triangle = new Zdog.Shape({ 49 | addTo: base, 50 | path: [ 51 | { x: 1, y: -1, z: 0 }, 52 | { x: -1, y: -1, z: 0 }, 53 | { x: 0, y: 0, z: -2 }, 54 | ], 55 | color: ochre, 56 | }); 57 | triangle.copy({ 58 | rotate: { z: TAU/4 }, 59 | }); 60 | triangle.copy({ 61 | rotate: { z: TAU/2 }, 62 | }); 63 | triangle.copy({ 64 | rotate: { z: TAU * 3/4 }, 65 | }); 66 | 67 | return pyramid; 68 | })(); 69 | 70 | // cylinder 1 71 | this.cylinder1 = new Zdog.Cylinder({ 72 | addTo: shifterAnchor, 73 | visible: false, 74 | diameter: 2, 75 | length: 2, 76 | // translate: { x: 0, y: -3 }, 77 | rotate: { y: TAU/4 }, 78 | color: navy, 79 | backface: egg, 80 | }); 81 | 82 | // cone 1 83 | // isoTriangle.copy({ 84 | // translate: { x: 3, y: -3, z: -2 }, 85 | // color: green, 86 | // }); 87 | 88 | this.cone = ( function() { 89 | var anchor = new Zdog.Group({ 90 | addTo: shifterAnchor, 91 | visible: false, 92 | // translate: { x: 3, y: -3 }, 93 | updateSort: true, 94 | }); 95 | 96 | new Zdog.Cone({ 97 | addTo: anchor, 98 | diameter: 2, 99 | length: 2, 100 | rotate: { x: TAU/4 }, 101 | translate: { y: 1 }, 102 | color: ochre, 103 | backface: egg, 104 | }); 105 | 106 | return anchor; 107 | })(); 108 | 109 | // triangular prism 110 | 111 | this.prism = ( function() { 112 | var prism = new Zdog.Group({ 113 | addTo: shifterAnchor, 114 | visible: false, 115 | // translate: { x: -3, y: 0 }, 116 | updateSort: true, 117 | }); 118 | 119 | var triangle = isoTriangle.copy({ 120 | addTo: prism, 121 | scale: { y: -1 }, 122 | rotate: { y: TAU/4 }, 123 | translate: { x: -1 }, 124 | color: ochre, 125 | }); 126 | triangle.copy({ 127 | translate: { x: 1 }, 128 | }); 129 | 130 | var angleFace = new Zdog.Shape({ 131 | addTo: prism, 132 | path: [ 133 | { x: -1, y: -1, z: 1 }, 134 | { x: 1, y: -1, z: 1 }, 135 | { x: 1, y: 1, z: 0 }, 136 | { x: -1, y: 1, z: 0 }, 137 | ], 138 | color: navy, 139 | }); 140 | angleFace.copy({ 141 | scale: { z: -1 }, 142 | }); 143 | 144 | // base 145 | new Zdog.Rect({ 146 | addTo: prism, 147 | width: 2, 148 | height: 2, 149 | rotate: { x: TAU/4 }, 150 | translate: { y: -1 }, 151 | color: green, 152 | }); 153 | 154 | return prism; 155 | })(); 156 | 157 | // eccentric cylinder, triangle contour 158 | 159 | this.triCylinder = ( function() { 160 | var cylinder = new Zdog.Group({ 161 | addTo: shifterAnchor, 162 | visible: false, 163 | // translate: { x: 3 }, 164 | }); 165 | 166 | isoTriangle.copy({ 167 | translate: {}, 168 | addTo: cylinder, 169 | color: ochre, 170 | }); 171 | 172 | var tilt = Math.atan(1/2); 173 | 174 | var capAnchor = new Zdog.Anchor({ 175 | addTo: cylinder, 176 | translate: { x: -0.5 }, 177 | rotate: { y: TAU/4 }, 178 | }); 179 | 180 | 181 | // left outside cap 182 | var cap = new Zdog.Ellipse({ 183 | addTo: capAnchor, 184 | diameter: 2, 185 | color: egg, 186 | rotate: { x: tilt }, 187 | scale: { y: 1/Math.cos( tilt ) }, 188 | backface: false, 189 | }); 190 | cap.copy({ // left inside cap 191 | rotate: { y: TAU/2, x: tilt }, 192 | color: ochre, 193 | }); 194 | 195 | capAnchor.copyGraph({ 196 | translate: { x: 0.5 }, 197 | rotate: { y: -TAU/4 }, 198 | }); 199 | 200 | return cylinder; 201 | })(); 202 | 203 | this.cylinder2 = this.cylinder1.copy({ 204 | translate: {}, 205 | visible: false, 206 | rotate: { x: TAU/4 }, 207 | }); 208 | 209 | } 210 | 211 | Shifter.prototype.update = function( t ) { 212 | 213 | var turn = Math.floor( t % 6 ); 214 | 215 | var easeT = Zdog.easeInOut( t % 1, 4 ) * TAU/4; 216 | this.pyramid.rotate.x = easeT; 217 | this.cylinder1.rotate.y = easeT + TAU/4; 218 | this.cone.rotate.x = easeT + TAU/4; 219 | this.prism.rotate.y = easeT + TAU/4; 220 | this.cylinder2.rotate.x = easeT + TAU/4; 221 | this.triCylinder.rotate.y = easeT + TAU/4; 222 | 223 | if ( turn === 0 ) { 224 | this.triCylinder.visible = false; 225 | this.pyramid.visible = true; 226 | } else if ( turn == 1) { 227 | this.pyramid.visible = false; 228 | this.cylinder1.visible = true; 229 | } else if ( turn == 2 ) { 230 | this.cylinder1.visible = false; 231 | this.cone.visible = true; 232 | } else if ( turn == 3 ) { 233 | this.cone.visible = false; 234 | this.prism.visible = true; 235 | } else if ( turn == 4 ) { 236 | this.prism.visible = false; 237 | this.cylinder2.visible = true; 238 | } else if ( turn == 5 ) { 239 | this.cylinder2.visible = false; 240 | this.triCylinder.visible = true; 241 | } 242 | }; 243 | -------------------------------------------------------------------------------- /demo/castle/castle.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 24; 5 | var minWindowSize = Math.min( window.innerWidth - 20, window.innerHeight - 40 ); 6 | var zoom = Math.floor( minWindowSize / illoSize ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | [ Zdog.Shape, Zdog.Rect ].forEach( function( ItemClass ) { 11 | ItemClass.defaults.fill = true; 12 | ItemClass.defaults.backface = false; 13 | ItemClass.defaults.stroke = 1/zoom; 14 | }); 15 | 16 | var white = 'white'; 17 | var black = '#333'; 18 | var isSpinning = true; 19 | var TAU = Zdog.TAU; 20 | var initRotate = { y: TAU/4 }; 21 | 22 | var illo = new Zdog.Illustration({ 23 | element: illoElem, 24 | zoom: zoom, 25 | rotate: initRotate, 26 | dragRotate: true, 27 | onDragStart: function() { 28 | isSpinning = false; 29 | }, 30 | }); 31 | 32 | // -- illustration shapes --- // 33 | 34 | function makeWall( options ) { 35 | var rotor = new Zdog.Anchor({ 36 | addTo: illo, 37 | rotate: options.rotate, 38 | }); 39 | 40 | // rotor 41 | var wall = new Zdog.Anchor({ 42 | addTo: rotor, 43 | translate: { z: 4 }, 44 | }); 45 | 46 | var topBlock = new Zdog.Anchor({ 47 | addTo: wall, 48 | translate: { x: -4, y: -4 }, 49 | }); 50 | 51 | // side faces 52 | var face = new Zdog.Rect({ 53 | addTo: topBlock, 54 | width: 2, 55 | height: 2, 56 | translate: { z: 1 }, 57 | color: options.outside, 58 | }); 59 | face.copy({ 60 | translate: { x: -1 }, 61 | rotate: { y: TAU/4 }, 62 | color: options.left, 63 | }); 64 | face.copy({ 65 | translate: { x: 1 }, 66 | rotate: { y: -TAU/4 }, 67 | color: options.right, 68 | }); 69 | face.copy({ 70 | translate: { z: -1 }, 71 | rotate: { y: TAU/2 }, 72 | color: options.inside, 73 | }); 74 | // top 75 | face.copy({ 76 | translate: { y: -1 }, 77 | rotate: { x: TAU/4 }, 78 | color: black, 79 | }); 80 | 81 | topBlock.copyGraph({ 82 | translate: { x: 0, y: -4 }, 83 | }); 84 | 85 | var topTile = new Zdog.Rect({ 86 | addTo: wall, 87 | width: 2, 88 | height: 2, 89 | color: black, 90 | rotate: { x: TAU/4 }, 91 | translate: { x: -2, y: -3 }, 92 | }); 93 | topTile.copy({ 94 | translate: { x: 2, y: -3 } 95 | }); 96 | 97 | // outside arch 98 | 99 | // outside arch 100 | var arch = new Zdog.Shape({ 101 | addTo: wall, 102 | path: [ 103 | { x: 0, y: -3 }, 104 | { x: 3, y: -3 }, 105 | { x: 3, y: 2 }, 106 | { arc: [ 107 | { x: 3, y: -1 }, 108 | { x: 0, y: -1 } 109 | ]}, 110 | ], 111 | translate: { z: 1 }, 112 | color: options.outside, 113 | }); 114 | arch.copy({ 115 | scale: { x: -1 }, 116 | }); 117 | 118 | 119 | // inside arch 120 | arch.copy({ 121 | translate: { z: -1 }, 122 | rotate: { y: TAU/2 }, 123 | color: options.inside, 124 | }); 125 | arch.copy({ 126 | translate: { z: -1 }, 127 | rotate: { y: TAU/2 }, 128 | scale: { x: -1 }, 129 | color: options.inside, 130 | }); 131 | 132 | // outside columns 133 | var outsideColumn = new Zdog.Rect({ 134 | addTo: wall, 135 | width: 2, 136 | height: 8, 137 | translate: { x: -4, y: 1, z: 1 }, 138 | color: options.outside, 139 | }); 140 | outsideColumn.copy({ 141 | translate: { x: 4, y: 1, z: 1 }, 142 | }); 143 | 144 | var insideColumn = new Zdog.Rect({ 145 | addTo: wall, 146 | width: 2, 147 | height: 3, 148 | translate: { x: -3, y: 3.5 }, 149 | rotate: { y: -TAU/4 }, 150 | color: options.right, 151 | }); 152 | insideColumn.copy({ 153 | translate: { x: 3, y: 3.5 }, 154 | rotate: { y: TAU/4 }, 155 | color: options.left, 156 | }); 157 | 158 | // under arch, quarter arc 159 | var underArch = new Zdog.Shape({ 160 | addTo: wall, 161 | path: [ 162 | { x: 3, y: 2 }, 163 | { arc: [ 164 | { x: 3, y: -1 }, 165 | { x: 0, y: -1 } 166 | ]}, 167 | { x: 0, y: -1, z: -2 }, 168 | { arc: [ 169 | { x: 3, y: -1, z: -2 }, 170 | { x: 3, y: 2, z: -2 }, 171 | ]}, 172 | ], 173 | translate: { z: 1 }, 174 | backface: true, 175 | color: options.left, 176 | }); 177 | underArch.copyGraph({ 178 | scale: { x: -1 }, 179 | color: options.right, 180 | }); 181 | 182 | // feet soles 183 | new Zdog.Rect({ 184 | addTo: wall, 185 | width: 2, 186 | height: 2, 187 | translate: { x: -4, y: 5, z: 0 }, 188 | rotate: { x: -TAU/4 }, 189 | color: white, 190 | }); 191 | 192 | } 193 | 194 | makeWall({ 195 | rotate: {}, 196 | outside: white, 197 | inside: black, 198 | left: white, 199 | right: black, 200 | }); 201 | 202 | makeWall({ 203 | rotate: { y: -TAU/4 }, 204 | outside: black, 205 | inside: white, 206 | left: white, 207 | right: black, 208 | }); 209 | 210 | makeWall({ 211 | rotate: { y: -TAU/2 }, 212 | outside: black, 213 | inside: white, 214 | left: black, 215 | right: white, 216 | }); 217 | 218 | makeWall({ 219 | rotate: { y: TAU * -3/4 }, 220 | outside: white, 221 | inside: black, 222 | left: black, 223 | right: white, 224 | }); 225 | 226 | 227 | // -- animate --- // 228 | 229 | var ticker = 0; 230 | var cycleCount = 105; 231 | 232 | var keyframes = [ 233 | { x: TAU * 0, y: TAU * 1/4 }, 234 | { x: TAU * -35/360, y: TAU * 5/8 }, 235 | { x: TAU * -1/4, y: TAU * 3/4 }, 236 | { x: TAU * -35/360, y: TAU * 9/8 }, 237 | { x: TAU * 0, y: TAU * 5/4 }, 238 | ]; 239 | 240 | function animate() { 241 | // update 242 | if ( isSpinning ) { 243 | var progress = ticker / cycleCount; 244 | var tween = Zdog.easeInOut( progress % 1, 4 ); 245 | var turnLimit = keyframes.length - 1; 246 | var turn = Math.floor( progress % turnLimit ); 247 | var keyA = keyframes[ turn ]; 248 | var keyB = keyframes[ turn + 1 ]; 249 | illo.rotate.x = Zdog.lerp( keyA.x, keyB.x, tween ); 250 | illo.rotate.y = Zdog.lerp( keyA.y, keyB.y, tween ); 251 | ticker++; 252 | } 253 | 254 | illo.updateRenderGraph(); 255 | requestAnimationFrame( animate ); 256 | } 257 | 258 | animate(); 259 | 260 | -------------------------------------------------------------------------------- /demo/madeline/make-madeline.js: -------------------------------------------------------------------------------- 1 | /* jshint unused: false */ 2 | 3 | var TAU = Zdog.TAU; 4 | 5 | function makeMadeline( isGood, colors, options ) { 6 | 7 | var rotor = new Zdog.Anchor( options ); 8 | 9 | var body = new Zdog.Group({ 10 | addTo: rotor, 11 | rotate: { x: -TAU/8 }, 12 | translate: { z: -48 }, 13 | updateSort: true, 14 | }); 15 | 16 | var head = new Zdog.Anchor({ 17 | addTo: body, 18 | translate: { y: -11, z: -2 }, 19 | rotate: { x: TAU/8 }, 20 | }); 21 | 22 | // face 23 | var face = new Zdog.Ellipse({ 24 | diameter: 6, 25 | addTo: head, 26 | translate: { z: 4 }, 27 | stroke: 8, 28 | color: colors.skin, 29 | }); 30 | 31 | var eyeGroup = new Zdog.Group({ 32 | addTo: face, 33 | translate: { z: face.stroke/2 - 0.5 }, 34 | }); 35 | 36 | 37 | // eyes 38 | [ -1, 1 ].forEach( function( xSide ) { 39 | // cheek blush 40 | if ( isGood ) { 41 | new Zdog.Ellipse({ 42 | width: 2, 43 | height: 1.3, 44 | addTo: eyeGroup, 45 | translate: { x: 4.5*xSide, y: 3, z: -1 }, 46 | rotate: { y: -TAU/16*xSide }, 47 | stroke: 1, 48 | color: '#FA8', 49 | fill: true, 50 | }); 51 | } 52 | 53 | var eyeX = 3.5*xSide; 54 | 55 | // eye 56 | new Zdog.Ellipse({ 57 | width: 0.75, 58 | height: 1.5, 59 | addTo: eyeGroup, 60 | color: colors.eye, 61 | translate: { x: eyeX }, 62 | stroke: 2, 63 | fill: true, 64 | }); 65 | 66 | // eye brow 67 | new Zdog.Ellipse({ 68 | addTo: eyeGroup, 69 | height: 3, 70 | width: 1.2, 71 | quarters: 2, 72 | translate: { x: eyeX, y: -3 }, 73 | rotate: { z: -TAU/4 + 0.15*xSide * (isGood ? 1 : -1) }, 74 | color: colors.hair, 75 | stroke: 1, 76 | fill: false, 77 | closed: true, 78 | }); 79 | 80 | }); 81 | 82 | 83 | // hair ball 84 | new Zdog.Shape({ 85 | path: [ 86 | { x: -1 }, 87 | { x: 1 }, 88 | { z: -4 }, 89 | ], 90 | addTo: head, 91 | translate: { y: -4, z: -1 }, 92 | stroke: 18, 93 | color: colors.hair, 94 | }); 95 | 96 | var bang = new Zdog.Shape({ 97 | path: [ 98 | {}, 99 | { arc: [ 100 | { z: 4, y: 4 }, 101 | { z: 0, y: 8 }, 102 | ]}, 103 | ], 104 | addTo: head, 105 | translate: { x: 2, y: -7.5, z: 6 }, 106 | rotate: { x: 0.5, z: -0.5 }, 107 | stroke: 4, 108 | color: colors.hair, 109 | closed: false, 110 | }); 111 | bang.copy({ 112 | translate: { x: 5, y: -6, z: 5 }, 113 | rotate: { x: -0.3, z: -0.5 }, 114 | }); 115 | bang.copy({ 116 | translate: { x: 5, y: -6, z: 3 }, 117 | rotate: { y: -0.7, z: -1 }, 118 | }); 119 | 120 | // left side 121 | bang.copy({ 122 | translate: { x: -2, y: -7.5, z: 6 }, 123 | rotate: { x: 0, z: TAU/16*6 }, 124 | }); 125 | bang.copy({ 126 | translate: { x: -5, y: -6, z: 5 }, 127 | rotate: { x: 0, z: TAU/4 }, 128 | }); 129 | bang.copy({ 130 | translate: { x: -5, y: -6, z: 3 }, 131 | rotate: { y: 0.7, z: 1 }, 132 | }); 133 | 134 | // hair cover 135 | new Zdog.Shape({ 136 | path: [ 137 | { x: -3 }, 138 | { x: 3 }, 139 | ], 140 | addTo: head, 141 | stroke: 7, 142 | translate: { y: -8, z: 5 }, 143 | color: colors.hair, 144 | }); 145 | 146 | // trail locks 147 | 148 | var trailLock = new Zdog.Shape({ 149 | path: [ 150 | { y: -4, z: 0 }, 151 | { bezier: [ 152 | { y: -10, z: -14 }, 153 | { y: 0, z: -16 }, 154 | { y: 0, z: -26 } 155 | ]}, 156 | ], 157 | addTo: head, 158 | translate: { z: -4, y: 0 }, 159 | stroke: 10, 160 | color: colors.hair, 161 | closed: false, 162 | }); 163 | 164 | trailLock.copy({ 165 | translate: { x: -3, z: -4 }, 166 | rotate: { z: -TAU/8 }, 167 | stroke: 8, 168 | }); 169 | trailLock.copy({ 170 | translate: { x: 3, z: -4 }, 171 | rotate: { z: TAU/8 }, 172 | stroke: 8, 173 | }); 174 | trailLock.copy({ 175 | translate: { y: 2 }, 176 | // rotate: { z: TAU/2 }, 177 | scale: { y: 0.5 }, 178 | stroke: 8, 179 | }); 180 | 181 | // ----- torso ----- // 182 | 183 | // 2nd rib 184 | var torsoRib = new Zdog.Ellipse({ 185 | width: 12, 186 | height: 10, 187 | addTo: body, 188 | rotate: { x: -TAU/4 }, 189 | translate: { y: -1 }, 190 | stroke: 6, 191 | color: colors.parkaLight, 192 | fill: true, 193 | }); 194 | // neck rib 195 | torsoRib.copy({ 196 | width: 6, 197 | height: 6, 198 | translate: { y: -5 }, 199 | }); 200 | // 3rd rib 201 | torsoRib.copy({ 202 | translate: { y: 3 }, 203 | }); 204 | // 4th rib 205 | torsoRib.copy({ 206 | translate: { y: 7 }, 207 | color: colors.parkaDark, 208 | }); 209 | // waist 210 | new Zdog.Ellipse({ 211 | width: 10, 212 | height: 8, 213 | addTo: body, 214 | rotate: { x: -TAU/4 }, 215 | translate: { y: 11 }, 216 | stroke: 4, 217 | color: colors.tight, 218 | fill: true, 219 | }); 220 | 221 | // arms 222 | [ -1, 1 ].forEach( function( xSide ) { 223 | var isLeft = xSide == 1; 224 | // shoulder ball 225 | new Zdog.Shape({ 226 | addTo: body, 227 | stroke: 6, 228 | translate: { x: 6*xSide, y: -5, z: -1 }, 229 | color: colors.parkaLight, 230 | }); 231 | 232 | var shoulderJoint = new Zdog.Anchor({ 233 | addTo: body, 234 | translate: { x: 9*xSide, y: -3, z: -2 }, 235 | rotate: isLeft ? { x: TAU/8*3, z: -TAU/32 } : { z: TAU/16*2, x: -TAU/16*2 }, 236 | }); 237 | 238 | // top shoulder rib 239 | var armRib = new Zdog.Ellipse({ 240 | diameter: 2, 241 | rotate: { x: -TAU/4 }, 242 | addTo: shoulderJoint, 243 | translate: { x: 0*xSide }, 244 | stroke: 6, 245 | color: colors.parkaLight, 246 | fill: true, 247 | }); 248 | armRib.copy({ 249 | translate: { y: 4 }, 250 | }); 251 | 252 | var elbowJoint = new Zdog.Anchor({ 253 | addTo: shoulderJoint, 254 | translate: { y: 8 }, 255 | rotate: isLeft ? {} : { z: TAU/8 }, 256 | }); 257 | 258 | armRib.copy({ 259 | addTo: elbowJoint, 260 | translate: { x: 0, y: 0 }, 261 | }); 262 | armRib.copy({ 263 | addTo: elbowJoint, 264 | translate: { y: 4 }, 265 | color: colors.parkaDark, 266 | }); 267 | 268 | // hand 269 | new Zdog.Shape({ 270 | addTo: elbowJoint, 271 | translate: { y: 9, z: -1 }, 272 | stroke: 8, 273 | color: colors.skin, 274 | }); 275 | 276 | // ----- legs ----- // 277 | var knee = { y: 7 }; 278 | var thigh = new Zdog.Shape({ 279 | path: [ { y: 0 }, knee ], 280 | addTo: body, 281 | translate: { x: 4*xSide, y: 13 }, 282 | rotate: isLeft ? {} : { x: TAU/16*3, z: TAU/16 }, 283 | stroke: 8, 284 | color: colors.tight, 285 | }); 286 | 287 | var shin = new Zdog.Shape({ 288 | path: [ { y: 0 }, { y: 8 } ], 289 | addTo: thigh, 290 | stroke: 6, 291 | translate: knee, 292 | rotate: isLeft ? {} : { x: -TAU/16*5 }, 293 | color: colors.tight, 294 | }); 295 | 296 | }); 297 | 298 | // butt 299 | new Zdog.Shape({ 300 | path: [ 301 | { x: -3 }, 302 | { x: 3 }, 303 | ], 304 | visible: false, 305 | addTo: body, 306 | translate: { y: 11, z: -2 }, 307 | stroke: 8, 308 | color: colors.tight, 309 | }); 310 | 311 | } 312 | -------------------------------------------------------------------------------- /demo/mega-man/mega-man.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 72; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.floor( minWindowSize / illoSize ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | var isSpinning = true; 10 | var TAU = Zdog.TAU; 11 | 12 | var illo = new Zdog.Illustration({ 13 | element: illoElem, 14 | zoom: zoom, 15 | dragRotate: true, 16 | onDragStart: function() { 17 | isSpinning = false; 18 | }, 19 | }); 20 | 21 | // colors 22 | var lightBlue = '#7CF'; 23 | var darkBlue = '#25C'; 24 | var skin = '#FCA'; 25 | 26 | // -- illustration shapes --- // 27 | 28 | // keep track of pupils to change position 29 | var pupils = {}; 30 | 31 | // head 32 | 33 | var head = new Zdog.Shape({ 34 | translate: { y: -20 }, 35 | rotate: { y: 0.5 }, 36 | stroke: 21, 37 | color: darkBlue, 38 | addTo: illo, 39 | }); 40 | 41 | // helmet details 42 | [ 1, 3, 4, 5, 6, 7, 8, 9 ].forEach( function( i ) { 43 | new Zdog.Shape({ 44 | path: [ 45 | { x: -1.25, y: -1.5, z: 11.25 }, 46 | { x: 1.25, y: -1.5, z: 11.25 }, 47 | { x: 1.25, y: 1.5, z: 11.25 }, 48 | { x: -1.25, y: 1.5, z: 11.25 }, 49 | ], 50 | rotate: { x: TAU/20 * i }, 51 | stroke: 2, 52 | fill: true, 53 | color: lightBlue, 54 | addTo: head, 55 | }); 56 | }); 57 | 58 | 59 | // upper body 60 | new Zdog.Shape({ 61 | path: [ 62 | { x: -2, y: -1.25 }, 63 | { x: 0, y: -1.5 }, 64 | { x: 2, y: -1.25 }, 65 | { x: 1.7, y: 0.5 }, 66 | { x: -1.7, y: 0.5 }, 67 | ], 68 | translate: { y: -4 }, 69 | stroke: 11, 70 | color: lightBlue, 71 | fill: true, 72 | addTo: illo, 73 | }); 74 | 75 | // undies 76 | 77 | var undieX = 4.5; 78 | var undieY0 = -1; 79 | var undieY1 = 0; 80 | var undieZ = 2.5; 81 | 82 | // front undie panel 83 | var undiePanel = new Zdog.Shape({ 84 | path: [ 85 | { x: -undieX, y: undieY0 }, 86 | { x: undieX, y: undieY0 }, 87 | { x: undieX, y: undieY1 }, 88 | { x: 0, y: 1.5 }, 89 | { x: -undieX, y: undieY1 }, 90 | ], 91 | translate: { y: 4, z: undieZ }, 92 | stroke: 5, 93 | color: darkBlue, 94 | fill: true, 95 | addTo: illo, 96 | }); 97 | 98 | undiePanel.copy({ 99 | translate: { y: 4, z: -undieZ }, 100 | }); 101 | 102 | // right undie panel 103 | var sideUndiePanel = new Zdog.Shape({ 104 | path: [ 105 | { y: undieY0, z: undieZ }, 106 | { y: undieY0, z: -undieZ }, 107 | { y: undieY1, z: -undieZ }, 108 | { y: undieY1, z: undieZ }, 109 | ], 110 | translate: { x: -undieX, y: 4, }, 111 | stroke: 5, 112 | color: darkBlue, 113 | fill: true, 114 | addTo: illo, 115 | }); 116 | // left 117 | sideUndiePanel.copy({ 118 | translate: { x: undieX, y: 4, }, 119 | }); 120 | 121 | // 122 | var shoulderX = 5; 123 | var shoulderY = -7; 124 | 125 | // right upper arm 126 | var rightUpperArm = new Zdog.Shape({ 127 | path: [ 128 | { x: 0 }, 129 | { x: -7 }, 130 | ], 131 | translate: { x: -shoulderX, y: shoulderY }, 132 | rotate: { z: -0.8, y: -0.6 }, 133 | stroke: 6, 134 | color: lightBlue, 135 | addTo: illo, 136 | }); 137 | 138 | var rightForeArm = new Zdog.Shape({ 139 | path: [ 140 | { x: -4 }, 141 | { x: -8 }, 142 | ], 143 | translate: rightUpperArm.path[1], 144 | rotate: { z: 1.4 }, 145 | stroke: 10, 146 | color: darkBlue, 147 | addTo: rightUpperArm, 148 | }); 149 | 150 | new Zdog.Shape({ 151 | path: [ 152 | { x: -4 }, 153 | ], 154 | translate: rightForeArm.path[1], 155 | rotate: { z: 0.3 }, 156 | stroke: 11, 157 | color: darkBlue, 158 | addTo: rightForeArm, 159 | }); 160 | 161 | // left arm, the gun arm 162 | var leftUpperArm = new Zdog.Shape({ 163 | path: [ 164 | { x: 0 }, 165 | { x: 11 }, 166 | ], 167 | translate: { x: shoulderX, y: shoulderY-0.5 }, 168 | rotate: { z: -0.2, y: 0.3 }, 169 | stroke: 6, 170 | color: lightBlue, 171 | addTo: illo, 172 | }); 173 | 174 | var leftForeArm = new Zdog.Shape({ 175 | path: [ 176 | { x: 5 }, 177 | { x: 10 }, 178 | ], 179 | translate: leftUpperArm.path[1], 180 | rotate: { z: -TAU/4 - leftUpperArm.rotate.z }, 181 | stroke: 11, 182 | color: darkBlue, 183 | addTo: leftUpperArm, 184 | }); 185 | 186 | new Zdog.Shape({ 187 | path: [ { x: 4 } ], 188 | translate: leftForeArm.path[1], 189 | stroke: 7, 190 | color: darkBlue, 191 | addTo: leftForeArm, 192 | }); 193 | 194 | [ -1, 1 ].forEach( function( xSide ) { 195 | 196 | var facePanelGroup = new Zdog.Group({ 197 | addTo: head, 198 | }); 199 | 200 | var facePanel = new Zdog.Shape({ 201 | addTo: facePanelGroup, 202 | path: [ 203 | { x: 4*xSide, y: -4, z: -1 }, // top inside brow 204 | { arc: [ 205 | { x: 0*xSide, y: -4, z: 0.5 }, 206 | { x: 0*xSide, y: 1, z: 1 }, // widows peak 207 | ]}, 208 | { x: 0*xSide, y: 1, z: 1 }, // nose 209 | { x: 0*xSide, y: 5.5, z: -1 }, // chin front 210 | { arc: [ 211 | { x: 7*xSide, y: 5.5, z: -4 }, // jaw 212 | { x: 7*xSide, y: 0, z: -4 }, // far side 213 | ]}, 214 | { arc: [ 215 | { x: 7*xSide, y: -4, z: -4 }, // top back brow 216 | { x: 4*xSide, y: -4, z: -1 }, // top inside brow 217 | ]}, 218 | ], 219 | translate: { y: 4, z: 8.5 }, 220 | fill: true, 221 | stroke: 1, 222 | color: skin, 223 | }); 224 | 225 | // eye whites 226 | var eyeWhite = new Zdog.Ellipse({ 227 | addTo: facePanel, 228 | width: 4, 229 | height: 5, 230 | translate: { x: 3.75*xSide, y: -0.5, z: 0.5 }, 231 | rotate: { y: -0.2*xSide }, 232 | stroke: 1, 233 | fill: true, 234 | color: 'white', 235 | backface: false, 236 | }); 237 | 238 | // pupils 239 | var pupil = new Zdog.Ellipse({ 240 | addTo: eyeWhite, 241 | width: 1, 242 | height: 4, 243 | translate: { x: -0.4*xSide, y: -0.2, z: 1 }, 244 | rotate: { y: 0.2*xSide }, 245 | stroke: 1, 246 | fill: true, 247 | color: '#128', 248 | backface: false, 249 | }); 250 | // add to hash 251 | pupils[ xSide ] = pupil; 252 | 253 | // ear cone outer 254 | var earCone = new Zdog.Ellipse({ 255 | diameter: 5.5, 256 | translate: { x: 10*xSide, y: 3, z: -1 }, 257 | rotate: { y: (TAU/4+0.2)*-xSide, x: TAU/4, z: 1 }, 258 | fill: false, 259 | stroke: 2.5, 260 | color: lightBlue, 261 | addTo: head, 262 | }); 263 | 264 | // ear cone inner inner 265 | new Zdog.Ellipse({ 266 | diameter: 5, 267 | addTo: earCone, 268 | translate: { z: -1 }, 269 | color: '#C11', 270 | stroke: false, 271 | fill: true, 272 | }); 273 | 274 | // thigh 275 | var thigh = new Zdog.Shape({ 276 | path: [ { y: 0 }, { y: 3 } ], 277 | translate: { x: 4.5*xSide, y: 8 }, 278 | rotate: { z: -0.35*xSide, x: -0.1 }, 279 | stroke: 6, 280 | color: lightBlue, 281 | addTo: illo, 282 | }); 283 | 284 | // shin 285 | var shin = new Zdog.Shape({ 286 | path: [ 287 | { y: 5, z: 0 }, 288 | { y: 14, z: 2 }, 289 | { y: 14, z: -1 }, 290 | ], 291 | translate: thigh.path[1], 292 | rotate: { y: -0.5*xSide }, 293 | fill: true, 294 | stroke: 11, 295 | color: darkBlue, 296 | addTo: thigh, 297 | }); 298 | 299 | // sole 300 | new Zdog.Shape({ 301 | path: [ 302 | { y: 2.5, x: (0.5 + 2)*xSide, z: -3 }, 303 | { y: 2.5, x: (0.5 + -2)*xSide, z: -3 }, 304 | { y: 2.5, x: (0.5 + -1)*xSide, z: 5 }, 305 | { y: 2.5, x: (0.5 + 1)*xSide, z: 5 }, 306 | ], 307 | translate: shin.path[1], 308 | rotate: { z: 0.4*xSide, x: -0.1 }, 309 | fill: true, 310 | stroke: 7, 311 | color: darkBlue, 312 | addTo: shin, 313 | }); 314 | 315 | }); 316 | 317 | // -- animate --- // 318 | 319 | var isSpinning = true; 320 | 321 | function animate() { 322 | update(); 323 | illo.renderGraph(); 324 | requestAnimationFrame( animate ); 325 | } 326 | 327 | animate(); 328 | 329 | // -- update -- // 330 | 331 | function update() { 332 | illo.rotate.y += isSpinning ? -TAU/150 : 0; 333 | illo.normalizeRotate(); 334 | 335 | // change pupil position 336 | var isAngleXFlip = illo.rotate.x > TAU/4 && illo.rotate.x < TAU * 3/4; 337 | var angleXOffset = isAngleXFlip ? 0 : TAU/2; 338 | // angleXFlip *= 339 | var headAngleY = Zdog.modulo( illo.rotate.y + head.rotate.y + angleXOffset, TAU ); 340 | var headAngleX = Zdog.modulo( illo.rotate.x + angleXOffset, TAU ); 341 | var stareX = (headAngleY / TAU * 2 - 1) * 8; 342 | var stareY = (headAngleX / TAU * 2 - 1) * 8; 343 | stareX = Math.max( -2, Math.min( 2, stareX ) ); 344 | stareY = Math.max( -1, Math.min( 1, stareY ) ); 345 | stareY = isAngleXFlip ? -stareY : stareY; 346 | // console.log( stareX ); 347 | pupils[-1].translate.x = 0.4 + stareX; 348 | pupils[1].translate.x = -0.4 + stareX; 349 | pupils[-1].translate.y = -0.2 + stareY; 350 | pupils[1].translate.y = -0.2 + stareY; 351 | 352 | // rotate 353 | illo.updateGraph(); 354 | } 355 | 356 | -------------------------------------------------------------------------------- /demo/truck-flight/truck-flight.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var sceneSize = 88; 5 | var zoom = 5; 6 | var illoSize = sceneSize * zoom; 7 | illoElem.setAttribute( 'width', illoSize ); 8 | illoElem.setAttribute( 'height', illoSize ); 9 | var TAU = Zdog.TAU; 10 | var initRotate = { x: TAU/16, y: TAU/8 }; 11 | 12 | var illo = new Zdog.Illustration({ 13 | element: illoElem, 14 | zoom: zoom, 15 | rotate: initRotate, 16 | dragRotate: true, 17 | }); 18 | 19 | // colors 20 | var light = '#FFF'; 21 | var dark = '#333'; 22 | 23 | var darkStroke = { 24 | addTo: illo, 25 | color: dark, 26 | stroke: 2, 27 | fill: false, 28 | }; 29 | 30 | var lightFill = { 31 | addTo: illo, 32 | color: light, 33 | stroke: false, 34 | fill: true, 35 | }; 36 | 37 | var allDark = { 38 | addTo: illo, 39 | color: dark, 40 | fill: true, 41 | stroke: 2, 42 | }; 43 | 44 | // -- illustration shapes --- // 45 | 46 | var bedSidePath = [ 47 | { x: -32, y: -4 }, 48 | { x: -8, y: -4 }, 49 | { x: -8, y: 8 }, 50 | { x: -32, y: 8 }, 51 | ]; 52 | 53 | var darkStrokeSide = Zdog.extend( {translate: { z: 12 }}, darkStroke ); 54 | var lightFillSide = Zdog.extend( {translate: { z: 12 }}, lightFill ); 55 | var allDarkSide = Zdog.extend( {translate: { z: -12 }}, allDark ); 56 | 57 | // sides, outer 58 | [ lightFillSide, darkStrokeSide, allDarkSide ].forEach( function( sideOptions ) { 59 | 60 | // door 61 | new Zdog.Shape( Zdog.extend( { 62 | path: [ 63 | { x: -8, y: -14 }, 64 | { x: 10, y: -14 }, 65 | { x: 20, y: -4 }, 66 | { x: 20, y: 8 }, 67 | { x: -8, y: 8 }, 68 | ], 69 | }, sideOptions ) ); 70 | 71 | // bed side 72 | new Zdog.Shape( Zdog.extend( { 73 | path: bedSidePath, 74 | }, sideOptions ) ); 75 | 76 | // front side 77 | new Zdog.Shape( Zdog.extend( { 78 | path: [ 79 | { x: 20, y: -4 }, 80 | { x: 32, y: -4 }, 81 | { x: 32, y: 8 }, 82 | { x: 20, y: 8 }, 83 | ], 84 | }, sideOptions ) ); 85 | 86 | }); 87 | 88 | // inside bed 89 | // side, dark 90 | new Zdog.Shape( Zdog.extend( { 91 | path: bedSidePath, 92 | translate: { z: 11 } 93 | }, allDark )); 94 | // side light 95 | new Zdog.Shape( Zdog.extend( { 96 | path: bedSidePath, 97 | translate: { z: -11 } 98 | }, lightFill )); 99 | new Zdog.Shape( Zdog.extend( { 100 | path: bedSidePath, 101 | translate: { z: -11 } 102 | }, darkStroke )); 103 | 104 | // underside 105 | 106 | // back underside 107 | new Zdog.Shape( Zdog.extend( { 108 | path: [ 109 | { x: -32, z: 12 }, 110 | { x: -8, z: 12 }, 111 | { x: -8, z: -12 }, 112 | { x: -32, z: -12 }, 113 | ], 114 | translate: { y: 8 }, 115 | }, allDark ) ); 116 | // door underside 117 | new Zdog.Shape( Zdog.extend( { 118 | path: [ 119 | { x: -8, z: 12 }, 120 | { x: 20, z: 12 }, 121 | { x: 20, z: -12 }, 122 | { x: -8, z: -12 }, 123 | ], 124 | translate: { y: 8 }, 125 | }, allDark ) ); 126 | // front underside 127 | new Zdog.Shape( Zdog.extend( { 128 | path: [ 129 | { x: 20, z: 12 }, 130 | { x: 32, z: 12 }, 131 | { x: 32, z: -12 }, 132 | { x: 20, z: -12 }, 133 | ], 134 | translate: { y: 8 }, 135 | }, allDark ) ); 136 | 137 | // roof 138 | var roof = new Zdog.Shape( Zdog.extend( { 139 | path: [ 140 | { x: -8, z: 12 }, 141 | { x: 10, z: 12 }, 142 | { x: 10, z: -12 }, 143 | { x: -8, z: -12 }, 144 | ], 145 | translate: { y: -14 }, 146 | }, lightFill ) ); 147 | roof.copy( darkStroke ); 148 | 149 | // windshield 150 | new Zdog.Shape( Zdog.extend( { 151 | path: [ 152 | { x: 10, y: -14, z: 12 }, 153 | { x: 10, y: -14, z: -12 }, 154 | { x: 20, y: -4, z: -12 }, 155 | { x: 20, y: -4, z: 12 }, 156 | ], 157 | }, allDark ) ); 158 | 159 | // hood 160 | var hood = new Zdog.Shape( Zdog.extend( { 161 | path: [ 162 | { x: 20, z: 12 }, 163 | { x: 32, z: 12 }, 164 | { x: 32, z: -12 }, 165 | { x: 20, z: -12 }, 166 | ], 167 | translate: { y: -4 }, 168 | }, lightFill ) ); 169 | hood.copy( darkStroke ); 170 | 171 | var frontGroup = new Zdog.Group({ 172 | addTo: illo, 173 | translate: { x: 32, y: 2 }, 174 | rotate: { y: -TAU/4 }, 175 | // translate: { z: 1 } 176 | }); 177 | 178 | // front 179 | new Zdog.Rect({ 180 | addTo: frontGroup, 181 | width: 24, 182 | height: 12, 183 | color: dark, 184 | fill: true, 185 | stroke: 2, 186 | }); 187 | 188 | var frontDetails = new Zdog.Anchor({ 189 | addTo: frontGroup, 190 | translate: { z: 0.5 }, 191 | }); 192 | 193 | // front details 194 | var headlight = new Zdog.Rect({ 195 | width: 2, 196 | height: 2, 197 | addTo: frontDetails, 198 | translate: { x: -9, y: -3 }, 199 | color: light, 200 | stroke: 2, 201 | }); 202 | headlight.copy({ 203 | translate: { x: 9, y: -3 }, 204 | }); 205 | 206 | // top line 207 | var grillLine = new Zdog.Shape({ 208 | path: [ 209 | { x: -4 }, 210 | { x: 4 }, 211 | ], 212 | addTo: frontDetails, 213 | translate: { y: -4 }, 214 | color: light, 215 | closed: false, 216 | stroke: 2, 217 | }); 218 | grillLine.copy({ 219 | translate: { y: 0 }, 220 | }); 221 | grillLine.copy({ 222 | path: [ 223 | { x: -10 }, 224 | { x: 10 }, 225 | ], 226 | translate: { y: 4 }, 227 | }); 228 | 229 | // tail 230 | var tail = new Zdog.Rect( Zdog.extend({ 231 | width: 24, 232 | height: 12, 233 | addTo: illo, 234 | translate: { x: -32, y: 2 }, 235 | rotate: { y: TAU/4 }, 236 | }, lightFill )); 237 | tail.copy( darkStroke ); 238 | // tail inside 239 | tail.copy({ 240 | color: dark, 241 | translate: { x: -31, y: 2 }, 242 | }); 243 | 244 | var tailGroup = new Zdog.Group({ 245 | addTo: tail, 246 | translate: { z: -0 }, 247 | }); 248 | 249 | // back details 250 | var backlight = new Zdog.Rect({ 251 | width: 4, 252 | height: 4, 253 | addTo: tailGroup, 254 | translate: { x: -10, y: -4 }, 255 | color: dark, 256 | stroke: 2, 257 | fill: true, 258 | }); 259 | backlight.copy({ 260 | translate: { x: 10, y: -4 }, 261 | }); 262 | // back bumper 263 | new Zdog.Shape({ 264 | path: [ 265 | { x: -11 }, 266 | { x: 11 }, 267 | { move: { z: 64 } }, // 'nother hack 268 | ], 269 | addTo: tailGroup, 270 | translate: { y: 5, z: 1 }, 271 | color: dark, 272 | stroke: 4, 273 | closed: false, 274 | }); 275 | 276 | // cab back 277 | var cabBackTop = new Zdog.Shape({ 278 | path: [ 279 | { y: -14, z: 12 }, 280 | { y: -4, z: 12 }, 281 | { y: -4, z: -12 }, 282 | { y: -14, z: -12 }, 283 | ], 284 | addTo: illo, 285 | translate: { x: -8 }, 286 | color: light, 287 | stroke: false, 288 | fill: true, 289 | }); 290 | cabBackTop.copy({ 291 | color: dark, 292 | fill: false, 293 | stroke: 2, 294 | }); 295 | 296 | var cabBackBottom = new Zdog.Shape({ 297 | path: [ 298 | { y: -4, z: 12 }, 299 | { y: 8, z: 12 }, 300 | { y: 8, z: -12 }, 301 | { y: -4, z: -12 }, 302 | ], 303 | addTo: illo, 304 | translate: { x: -8 }, 305 | color: light, 306 | stroke: false, 307 | fill: true, 308 | }); 309 | cabBackBottom.copy({ 310 | color: dark, 311 | fill: false, 312 | stroke: 2, 313 | }); 314 | 315 | // WHEELS 316 | 317 | // front light 318 | var lightFillWheel = new Zdog.Shape( Zdog.extend({ 319 | path: [ 320 | { x: 0, y: -6 }, 321 | { arc: [ // top right 322 | { x: 6, y: -6 }, 323 | { x: 6, y: 0 }, 324 | ]}, 325 | { arc: [ // bottom right 326 | { x: 6, y: 6 }, 327 | { x: 0, y: 6 }, 328 | ]}, 329 | { arc: [ // bottom left 330 | { x: -6, y: 6 }, 331 | { x: -6, y: 0 }, 332 | ]}, 333 | { arc: [ // bottom left 334 | { x: -6, y: -6 }, 335 | { x: 0, y: -6 }, 336 | ]}, 337 | // hack, add a big move up to fix z-sort bug 338 | { move: { x: 0, y: -64, z: 64 } }, 339 | ], 340 | closed: false, 341 | translate: { x: 18, y: 8, z: 14 }, 342 | }, lightFill )); 343 | var darkStrokeWheel = lightFillWheel.copy({ 344 | fill: false, 345 | stroke: 4, 346 | color: dark, 347 | }); 348 | var darkWheel = new Zdog.Ellipse({ 349 | diameter: 12, 350 | addTo: illo, 351 | translate: { x: 18, y: 8, z: 10 }, 352 | color: dark, 353 | stroke: 4, 354 | fill: true, 355 | }); 356 | 357 | 358 | // back light 359 | lightFillWheel.copy({ 360 | translate: { x: -18, y: 8, z: 14 } 361 | }); 362 | darkStrokeWheel.copy({ 363 | translate: { x: -18, y: 8, z: 14 } 364 | }); 365 | darkWheel.copy({ 366 | translate: { x: -18, y: 8, z: 10 }, 367 | }); 368 | 369 | // front dark 370 | darkWheel.copy({ 371 | translate: { x: 18, y: 8, z: -14 } 372 | }); 373 | darkWheel.copy({ 374 | translate: { x: 18, y: 8, z: -10 } 375 | }); 376 | 377 | // back dark 378 | darkWheel.copy({ 379 | translate: { x: -18, y: 8, z: -14 } 380 | }); 381 | darkWheel.copy({ 382 | translate: { x: -18, y: 8, z: -10 } 383 | }); 384 | 385 | // -- animate --- // 386 | 387 | function animate() { 388 | illo.updateRenderGraph(); 389 | requestAnimationFrame( animate ); 390 | } 391 | 392 | animate(); 393 | 394 | // ----- inputs ----- // 395 | 396 | document.querySelector('.quarter-twist-button').onclick = function() { 397 | illo.rotate.set( initRotate ); 398 | }; 399 | -------------------------------------------------------------------------------- /demo/mario/mario.js: -------------------------------------------------------------------------------- 1 | // -------------------------- demo -------------------------- // 2 | 3 | var illoElem = document.querySelector('.illo'); 4 | var illoSize = 72; 5 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 6 | var zoom = Math.min( 6, Math.floor( minWindowSize / illoSize ) ); 7 | illoElem.setAttribute( 'width', illoSize * zoom ); 8 | illoElem.setAttribute( 'height', illoSize * zoom ); 9 | 10 | var isSpinning = true; 11 | var TAU = Zdog.TAU; 12 | 13 | var illo = new Zdog.Illustration({ 14 | element: illoElem, 15 | zoom: zoom, 16 | dragRotate: true, 17 | onDragStart: function() { 18 | isSpinning = false; 19 | }, 20 | }); 21 | 22 | // colors 23 | var colors = { 24 | eye: '#333', 25 | white: '#FFF', 26 | hair: '#631', 27 | overalls: '#24D', 28 | cloth: '#E11', 29 | skin: '#FC9', 30 | leather: '#A63', 31 | }; 32 | 33 | // -- illustration shapes --- // 34 | 35 | // head 36 | var head = new Zdog.Shape({ 37 | addTo: illo, 38 | translate: { y: -12, z: 1 }, 39 | color: colors.skin, 40 | stroke: 23, 41 | }); 42 | 43 | // nose 44 | new Zdog.Shape({ 45 | addTo: head, 46 | translate: { y: 5, z: 13 }, 47 | color: colors.skin, 48 | stroke: 7, 49 | }); 50 | 51 | 52 | 53 | // chin 54 | var chin = new Zdog.Shape({ 55 | addTo: head, 56 | path: [ 57 | { x: -5, y: 6, z: 4 }, 58 | { x: 0, y: 8.5, z: 6 } 59 | ], 60 | color: colors.skin, 61 | stroke: 10, 62 | }); 63 | chin.copy({ 64 | scale: { x: -1 }, 65 | }); 66 | 67 | // mouth 68 | new Zdog.Shape({ 69 | path: [ 70 | { x: -3, y: -3 }, 71 | { x: -1, y: -1 }, 72 | { x: 1, y: -1 }, 73 | { x: 3, y: -3 }, 74 | ], 75 | translate: { y: 12, z: 9 }, 76 | color: colors.cloth, 77 | fill: true, 78 | stroke: 2, 79 | addTo: head, 80 | }); 81 | 82 | 83 | var hat = new Zdog.Anchor({ 84 | addTo: head, 85 | translate: { y: -8 }, 86 | }); 87 | 88 | // hat front 89 | var hatFrontA = new Zdog.Vector({ x: -8, y: 0, z: 5 }); 90 | var hatFrontB = new Zdog.Vector({ x: -4, y: -3, z: 7 }); 91 | var hatFrontC = hatFrontB.copy().multiply({ x: -1 }); 92 | var hatFrontD = hatFrontA.copy().multiply({ x: -1 }); 93 | 94 | // hat front 95 | new Zdog.Shape({ 96 | path: [ 97 | hatFrontA, 98 | hatFrontB, 99 | hatFrontC, 100 | hatFrontD, 101 | ], 102 | color: colors.cloth, 103 | closed: false, 104 | fill: false, 105 | stroke: 11, 106 | addTo: hat, 107 | }); 108 | 109 | var hatTopFront = new Zdog.Vector({ x: 10, y: 1, z: 5 }); 110 | var hatTopBackA = new Zdog.Vector({ x: 7, y: 3, z: -10 }); 111 | var hatTopBackB = hatTopBackA.copy().multiply({ x: -1 }); 112 | 113 | // hat top 114 | new Zdog.Shape({ 115 | path: [ 116 | hatTopFront.copy().multiply({ x: -1 }), 117 | hatTopFront, 118 | hatTopBackA, 119 | hatTopBackB, 120 | ], 121 | color: colors.cloth, 122 | fill: true, 123 | stroke: 9, 124 | addTo: hat, 125 | }); 126 | // hat top back 127 | new Zdog.Shape({ 128 | path: [ 129 | hatTopBackA, 130 | hatTopBackB, 131 | ], 132 | color: colors.cloth, 133 | stroke: 9, 134 | addTo: hat, 135 | }); 136 | 137 | // hat top side 138 | var hatTopSide = new Zdog.Shape({ 139 | path: [ 140 | hatTopFront, 141 | hatTopBackA, 142 | ], 143 | color: colors.cloth, 144 | stroke: 9, 145 | addTo: hat, 146 | }); 147 | hatTopSide.copy({ 148 | scale: { x: -1 }, 149 | }); 150 | 151 | 152 | // hat top cover 153 | new Zdog.Shape({ 154 | path: [ 155 | { x: -3, y: 0, z: -8 }, 156 | { x: 3, y: 0, z: -8 }, 157 | { x: 3, y: -3, z: 4 }, 158 | { x: -3, y: -3, z: 4 }, 159 | ], 160 | color: colors.cloth, 161 | stroke: 6, 162 | addTo: hat, 163 | }); 164 | 165 | // hat brim 166 | // brim has left & right side 167 | var hatBrim = new Zdog.Shape({ 168 | path: [ 169 | { x: 10, y: 4, z: -0 }, 170 | { x: 8, y: 4, z: 5 }, 171 | { x: 0, y: 2, z: 9 }, 172 | { x: 0, y: 1, z: 2 }, 173 | ], 174 | translate: { z: 7 }, 175 | color: colors.cloth, 176 | fill: true, 177 | stroke: 4, 178 | addTo: hat, 179 | }); 180 | hatBrim.copy({ 181 | scale: { x: -1 }, 182 | }); 183 | 184 | // eyes pupil 185 | var eye = new Zdog.Shape({ 186 | path: [ 187 | { y: 2 }, 188 | { y: 4 }, 189 | ], 190 | translate: { x: 5, z: 9 }, 191 | color: colors.eye, 192 | stroke: 3, 193 | addTo: head, 194 | }); 195 | eye.copy({ 196 | translate: { x: -5, z: 9 }, 197 | }); 198 | 199 | var brow = new Zdog.Shape({ 200 | path: [ 201 | { x: 3, y: 0, z: -0 }, 202 | { x: 1.5, y: -0.5, z: 1 }, 203 | { x: 0, y: 0, z: 1 }, 204 | ], 205 | translate: { x: 4, y: -1.5, z: 9 }, 206 | color: colors.hair, 207 | closed: false, 208 | stroke: 2.5, 209 | addTo: head, 210 | }); 211 | brow.copy({ 212 | scale: { x: -1 }, 213 | translate: { x: -4, y: -1.5, z: 9 }, 214 | }); 215 | 216 | var mustache = new Zdog.Group({ 217 | addTo: head, 218 | translate: { y: 6.5, z: 10 }, 219 | }); 220 | // mustache line 221 | new Zdog.Shape({ 222 | path: [ 223 | { x: 2, y: 1, z: 1.5 }, 224 | { x: 6.5, y: 0, z: -0 }, 225 | ], 226 | color: colors.hair, 227 | stroke: 3, 228 | addTo: mustache, 229 | }); 230 | // mustache sections 231 | var mustacheSection = new Zdog.Shape({ 232 | translate: { x: 1.75, y: 1.5, z: 1 }, 233 | color: colors.hair, 234 | stroke: 4, 235 | addTo: mustache, 236 | }); 237 | mustacheSection.copy({ 238 | translate: { x: 4.5, y: 1, z: 0.75 } 239 | }); 240 | 241 | mustache.copyGraph({ 242 | scale: { x: -1 }, 243 | }); 244 | 245 | var sideburns = new Zdog.Shape({ 246 | path: [ 247 | { y: 0, z: 0 }, 248 | { y: -4, z: 1.5 }, 249 | { y: -4, z: 1 }, 250 | { y: -1, z: 2 }, 251 | ], 252 | translate: { x: 10, y: 3, z: 2 }, 253 | color: colors.hair, 254 | closed: false, 255 | fill: true, 256 | stroke: 3, 257 | addTo: head, 258 | }); 259 | sideburns.copy({ 260 | translate: sideburns.translate.copy().multiply({ x: -1 }), 261 | }); 262 | 263 | var ear = new Zdog.Shape({ 264 | path: [ 265 | { x: 0, y: 0, z: -0 }, 266 | { x: 0, y: -4, z: -0 }, 267 | { x: 1, y: -4, z: -2 }, 268 | { x: 0, y: 0, z: -1 }, 269 | ], 270 | translate: { x: 10, y: 4, z: -2 }, 271 | color: colors.skin, 272 | fill: true, 273 | stroke: 4, 274 | addTo: head, 275 | }); 276 | ear.copy({ 277 | scale: { x: -1 }, 278 | translate: ear.translate.copy().multiply({ x: -1 }), 279 | }); 280 | 281 | var sideHair = new Zdog.Anchor({ 282 | addTo: head, 283 | }); 284 | 285 | // hair side panel 286 | new Zdog.Shape({ 287 | path: [ 288 | { x: 4, y: -7, z: -1 }, 289 | { x: 3, y: 0, z: -0 }, 290 | { x: 0, y: 0, z: -5 }, 291 | { x: 2, y: -6.5, z: -6 }, 292 | ], 293 | translate: { x: 5, y: 7, z: -5 }, 294 | color: colors.hair, 295 | fill: true, 296 | stroke: 3, 297 | addTo: sideHair, 298 | }); 299 | // hair balls 300 | var hairBall = new Zdog.Shape({ 301 | translate: { x: 6, y: 8, z: -8 }, 302 | color: colors.hair, 303 | stroke: 6, 304 | addTo: sideHair, 305 | }); 306 | hairBall.copy({ 307 | translate: { x: 2, y: 8, z: -10 }, 308 | }); 309 | 310 | sideHair.copyGraph({ 311 | scale: { x: -1 }, 312 | }); 313 | 314 | // hair back panel 315 | new Zdog.Shape({ 316 | path: [ 317 | { x: 5, y: 0, z: -0 }, 318 | { x: 6, y: -6.5, z: -1 }, 319 | { x: -6, y: -6.5, z: -1 }, 320 | { x: -5, y: 0, z: -0 }, 321 | ], 322 | translate: { y: 7, z: -10 }, 323 | color: colors.hair, 324 | fill: true, 325 | stroke: 3, 326 | addTo: head, 327 | }); 328 | 329 | 330 | var body = new Zdog.Shape({ 331 | translate: { x: 0, y: 10, z: 1 }, 332 | color: colors.overalls, 333 | stroke: 20, 334 | addTo: illo, 335 | }); 336 | 337 | // right arm 338 | var rightShoulder = { x: -8, y: -8, z: -3 }; 339 | var rightWrist = new Zdog.Vector({ x: -14, y: -17, z: -0 }); 340 | new Zdog.Shape({ 341 | path: [ 342 | rightShoulder, 343 | rightWrist, 344 | ], 345 | color: colors.cloth, 346 | stroke: 8, 347 | addTo: body, 348 | }); 349 | 350 | // right hand 351 | new Zdog.Shape({ 352 | path: [ 353 | { x: -17, y: -23, z: 1 }, 354 | ], 355 | color: colors.white, 356 | stroke: 12, 357 | addTo: body, 358 | }); 359 | 360 | // left arm 361 | var leftShoulder = { x: 6, y: -7, z: -4 }; 362 | var leftElbow = { x: 8, y: -4, z: -8 }; 363 | new Zdog.Shape({ 364 | path: [ 365 | leftShoulder, 366 | leftElbow, 367 | ], 368 | color: colors.cloth, 369 | stroke: 8, 370 | addTo: body, 371 | }); 372 | new Zdog.Shape({ 373 | path: [ 374 | leftElbow, 375 | { x: 12, y: -2, z: -9 }, 376 | ], 377 | color: colors.cloth, 378 | stroke: 8, 379 | addTo: body, 380 | }); 381 | // left hand 382 | new Zdog.Shape({ 383 | path: [ 384 | { x: 17, y: 1, z: -8 }, 385 | ], 386 | color: colors.white, 387 | stroke: 12, 388 | addTo: body, 389 | }); 390 | 391 | new Zdog.Shape({ 392 | path: [ 393 | leftShoulder, 394 | rightShoulder, 395 | ], 396 | color: colors.cloth, 397 | stroke: 8, 398 | addTo: body, 399 | }); 400 | 401 | // right leg 402 | var rightLeg = new Zdog.Shape({ 403 | path: [ 404 | { y: 4, z: 2 }, 405 | { y: 10, z: 1 }, 406 | { y: 12, z: -0 } 407 | ], 408 | translate: { x: -5 }, 409 | closed: false, 410 | color: colors.overalls, 411 | stroke: 10, 412 | addTo: body, 413 | }); 414 | 415 | var shoe = new Zdog.Rect({ 416 | addTo: rightLeg, 417 | width: 4, 418 | height: 7, 419 | translate: { y: 15.5, z: -4 }, 420 | fill: true, 421 | color: colors.leather, 422 | stroke: 6, 423 | }); 424 | 425 | // toe ball 426 | new Zdog.Shape({ 427 | addTo: shoe, 428 | translate: { y: 3, z: 2.5 }, 429 | color: colors.leather, 430 | stroke: 11, 431 | }); 432 | 433 | // left leg 434 | var leftLeg = new Zdog.Shape({ 435 | path: [ 436 | { y: 4, z: 2 }, 437 | { y: 2, z: 7 }, 438 | { y: 3, z: 11 }, 439 | ], 440 | translate: { x: 5 }, 441 | closed: false, 442 | color: colors.overalls, 443 | stroke: 10, 444 | addTo: body, 445 | }); 446 | 447 | shoe.copyGraph({ 448 | addTo: leftLeg, 449 | translate: { y: 2, z: 18 }, 450 | rotate: { x: TAU * (160/360) }, 451 | }); 452 | 453 | // -- animate --- // 454 | 455 | function animate() { 456 | illo.rotate.y += isSpinning ? -0.05 : 0; 457 | illo.updateRenderGraph(); 458 | requestAnimationFrame( animate ); 459 | } 460 | 461 | animate(); 462 | 463 | -------------------------------------------------------------------------------- /demo/santorini/santorini.js: -------------------------------------------------------------------------------- 1 | /* globals makeBuilding, oneStoryBuilding, twoStoryBuilding, oneStorySlanter, makeRock */ 2 | 3 | // -------------------------- demo -------------------------- // 4 | 5 | var illoElem = document.querySelector('.illo'); 6 | var w = 192; 7 | var h = 164; 8 | var minWindowSize = Math.min( window.innerWidth, window.innerHeight ); 9 | var zoom = Math.min( 7, Math.floor( minWindowSize / w ) ); 10 | var zoom = 5; 11 | illoElem.setAttribute( 'width', w * zoom ); 12 | illoElem.setAttribute( 'height', h * zoom ); 13 | var isSpinning = false; 14 | var TAU = Zdog.TAU; 15 | var initRotate = { y: TAU/8 }; 16 | 17 | var illo = new Zdog.Illustration({ 18 | element: illoElem, 19 | zoom: zoom, 20 | rotate: initRotate, 21 | dragRotate: true, 22 | onDragStart: function() { 23 | isSpinning = false; 24 | }, 25 | }); 26 | 27 | // colors 28 | // var white = 'white'; 29 | // var southWall = white; 30 | // var westWall = '#CDE'; 31 | // var eastWall = '#8AD'; 32 | var roof = '#06B'; 33 | // var northWall = roof; 34 | // var navy = '#037'; 35 | // var midnight = '#024'; 36 | 37 | // default to flat, filled shapes 38 | [ Zdog.Shape, Zdog.Rect, Zdog.Ellipse ].forEach( function( ItemClass ) { 39 | ItemClass.defaults.fill = true; 40 | ItemClass.defaults.stroke = false; 41 | }); 42 | 43 | var island = new Zdog.Anchor({ 44 | addTo: illo, 45 | scale: { x: 1/Math.sin(TAU/8), z: -1/Math.sin(TAU/8) } 46 | }); 47 | 48 | // -- illustration shapes --- // 49 | 50 | // lil house in front, center 51 | oneStoryBuilding({ 52 | addTo: island, 53 | translate: { x: 17, z: -24 }, 54 | gable: 'ns' 55 | }); 56 | 57 | // lil house to the east 58 | oneStoryBuilding({ 59 | addTo: island, 60 | translate: { x: 47, z: -16 }, 61 | gable: 'ns' 62 | }); 63 | 64 | // 2 story gable, east end 65 | twoStoryBuilding({ 66 | addTo: island, 67 | translate: { x: 55, z: -4 }, 68 | gable: 'ns' 69 | }); 70 | 71 | // 2 story gable, center west 72 | twoStoryBuilding({ 73 | addTo: island, 74 | translate: { x: 14, y: -2, z: -13 }, 75 | gable: 'ew', 76 | }); 77 | 78 | 79 | // 2 story gable, west end 80 | twoStoryBuilding({ 81 | addTo: island, 82 | translate: { x: -14, z: -25 }, 83 | gable: 'ew', 84 | }); 85 | 86 | 87 | // 1 story slantS, west 88 | oneStorySlanter({ 89 | addTo: island, 90 | translate: { x: 0, z: -26 }, 91 | gable: 'slantS', 92 | }); 93 | 94 | 95 | 96 | // ----- ----- // 97 | 98 | // 2.5 story slantS, east 99 | var buildAnchor4 = new Zdog.Anchor({ 100 | addTo: island, 101 | translate: { x: 42, z: -6 }, 102 | }); 103 | 104 | makeBuilding({ 105 | width: 14, 106 | height: 20, 107 | depth: 6, 108 | gable: 'slantS', 109 | addTo: buildAnchor4, 110 | nsWindows: [ 111 | { x: -4, y: -17 }, 112 | { x: 0, y: -17 }, 113 | { x: 4, y: -17 }, 114 | ], 115 | ewWindows: [ 116 | { x: 0, y: -17 } 117 | ], 118 | }); 119 | 120 | // ----- cathedral ----- // 121 | 122 | var cathBaseAnchor = new Zdog.Anchor({ 123 | addTo: island, 124 | translate: { x: 28, z: -12 }, 125 | }); 126 | 127 | // cathedral base 128 | makeBuilding({ 129 | width: 10, 130 | height: 12, 131 | depth: 18, 132 | gable: 'cap', 133 | addTo: cathBaseAnchor, 134 | nsWindows: [ 135 | { x: -2, y: -3 }, 136 | { x: 2, y: -3 }, 137 | { x: -2, y: -9 }, 138 | { x: 2, y: -9 }, 139 | ], 140 | ewWindows: [ 141 | { style: 'circle', x: -6, y: -9 }, 142 | { style: 'circle', x: -2, y: -9 }, 143 | { style: 'circle', x: 2, y: -9 }, 144 | { style: 'circle', x: 6, y: -9 }, 145 | { height: 6, x: -6, y: -5 }, 146 | { height: 6, x: -2, y: -5 }, 147 | { height: 6, x: 2, y: -5 }, 148 | { height: 6, x: 6, y: -5 }, 149 | ], 150 | }); 151 | 152 | // cathedral 2nd story 153 | var cath2ndAnchor = new Zdog.Anchor({ 154 | addTo: cathBaseAnchor, 155 | translate: { y: -14 }, 156 | }); 157 | 158 | makeBuilding({ 159 | width: 8, 160 | height: 8, 161 | depth: 8, 162 | gable: 'cap', 163 | addTo: cath2ndAnchor, 164 | nsWindows: [ 165 | { x: 0, y: -5 }, 166 | ], 167 | ewWindows: [ 168 | { x: 0, y: -5 }, 169 | ], 170 | }); 171 | 172 | // cathedral 3rd story 173 | 174 | var cath3rdAnchor = new Zdog.Anchor({ 175 | addTo: cathBaseAnchor, 176 | translate: { y: -24 }, 177 | }); 178 | 179 | makeBuilding({ 180 | width: 6, 181 | height: 6, 182 | depth: 6, 183 | addTo: cath3rdAnchor, 184 | gable: 'flat', 185 | nsWindows: [ 186 | { x: 0, y: -3 }, 187 | ], 188 | ewWindows: [ 189 | { x: 0, y: -3 }, 190 | ], 191 | }); 192 | 193 | // cathedral dome 194 | var dome = new Zdog.Hemisphere({ 195 | addTo: cathBaseAnchor, 196 | diameter: 6, 197 | translate: { y: -30 }, 198 | rotate: { x: TAU/4 }, 199 | color: roof, 200 | stroke: false, 201 | }); 202 | 203 | // ----- ----- // 204 | 205 | // 2 story gable, east, behind cathdral on hill 206 | var anchor6 = new Zdog.Anchor({ 207 | addTo: island, 208 | translate: { x: 27, z: 6, y: -14 }, 209 | }); 210 | 211 | makeBuilding({ 212 | width: 8, 213 | height: 16, 214 | depth: 10, 215 | gable: 'ns', 216 | addTo: anchor6, 217 | nsWindows: [ 218 | { style: 'circle', x: 0, y: -13 }, 219 | ], 220 | ewWindows: [ 221 | { style: 'circle', x: -2, y: -7 }, 222 | { style: 'circle', x: 2, y: -7 }, 223 | { x: -2, y: -13 }, 224 | { x: 2, y: -13 }, 225 | ], 226 | }); 227 | 228 | // ----- west side ----- // 229 | 230 | 231 | // shack, west end 232 | var anchor9 = new Zdog.Anchor({ 233 | addTo: island, 234 | translate: { x: -13, z: -34 }, 235 | }); 236 | 237 | makeBuilding({ 238 | width: 8, 239 | height: 8, 240 | depth: 6, 241 | gable: 'ns', 242 | addTo: anchor9, 243 | nsWindows: [ 244 | { x: 0, y: -5 }, 245 | ], 246 | ewWindows: [ 247 | { style: 'circle' }, 248 | ], 249 | }); 250 | 251 | // 2 story, west center, 1st hill 252 | var anchor10 = new Zdog.Anchor({ 253 | addTo: island, 254 | translate: { x: 3, z: -10, y: -8 }, 255 | }); 256 | 257 | makeBuilding({ 258 | width: 8, 259 | height: 16, 260 | depth: 10, 261 | gable: 'ns', 262 | addTo: anchor10, 263 | nsWindows: [ 264 | { x: 0, y: -13 }, 265 | ], 266 | ewWindows: [ 267 | { x: -2, y: -13 }, 268 | { x: 2, y: -13 }, 269 | { x: -2, y: -5 }, 270 | { x: 2, y: -5 }, 271 | ], 272 | }); 273 | 274 | // west mansion 275 | var mansionAnchor = new Zdog.Anchor({ 276 | addTo: island, 277 | translate: { x: -14, z: -14, y: -8 }, 278 | }); 279 | 280 | makeBuilding({ 281 | width: 14, 282 | height: 18, 283 | depth: 10, 284 | gable: 'cap', 285 | addTo: mansionAnchor, 286 | nsWindows: [ 287 | { x: -4, y: -15, style: 'circle' }, 288 | { x: 0, y: -15, style: 'circle' }, 289 | { x: 4, y: -15, style: 'circle' }, 290 | { x: -4, y: -11, height: 10 }, 291 | { x: 0, y: -11, height: 10 }, 292 | { x: 4, y: -11, height: 10 }, 293 | ], 294 | ewWindows: [ 295 | { x: -2, y: -15 }, 296 | { x: 2, y: -15 }, 297 | { x: -2, y: -9, height: 8 }, 298 | { x: 2, y: -9, height: 8 }, 299 | ], 300 | }); 301 | 302 | // mansion rock 303 | makeRock({ 304 | width: 19, 305 | depth: 14, 306 | height: 8, 307 | addTo: island, 308 | translate: { x: -13, z: -14, y: 1 }, 309 | southOffset: -2, 310 | }); 311 | 312 | // ----- central tower ----- // 313 | 314 | var centralTowerAnchor = new Zdog.Anchor({ 315 | addTo: island, 316 | translate: { y: -14 }, 317 | }); 318 | 319 | makeBuilding({ 320 | width: 6, 321 | depth: 6, 322 | height: 18, 323 | addTo: centralTowerAnchor, 324 | gable: 'cap', 325 | nsWindows: [ 326 | { x: 0, y: -7, style: 'circle' } 327 | ], 328 | ewWindows: [ 329 | { x: 0, y: -13, style: 'circle' } 330 | ], 331 | }); 332 | 333 | // central tower 2nd story 334 | var centralTower2ndAnchor = new Zdog.Anchor({ 335 | addTo: centralTowerAnchor, 336 | translate: { y: -20 }, 337 | }); 338 | 339 | makeBuilding({ 340 | width: 6, 341 | depth: 6, 342 | height: 8, 343 | addTo: centralTower2ndAnchor, 344 | gable: 'flat', 345 | nsWindows: [ 346 | { x: 0, y: -5 } 347 | ], 348 | ewWindows: [ 349 | { x: 0, y: -5 } 350 | ], 351 | }); 352 | 353 | dome.copy({ 354 | diameter: 4, 355 | addTo: centralTower2ndAnchor, 356 | translate: { y: -8 }, 357 | }); 358 | 359 | // ----- temple ----- // 360 | 361 | var templeAnchor = new Zdog.Anchor({ 362 | addTo: island, 363 | translate: { x: -20, y: -14, z: 1 }, 364 | }); 365 | 366 | makeBuilding({ 367 | width: 12, 368 | depth: 12, 369 | height: 8, 370 | gable: 'cap', 371 | addTo: templeAnchor, 372 | nsWindows:[ 373 | { x: -2, height: 6 }, 374 | { x: 2, height: 6 }, 375 | ], 376 | ewWindows:[ 377 | { x: -2, height: 6 }, 378 | { x: 2, height: 6 }, 379 | ], 380 | }); 381 | 382 | var temple2ndFloor = new Zdog.Anchor({ 383 | addTo: templeAnchor, 384 | translate: { y: -10 }, 385 | }); 386 | 387 | makeBuilding({ 388 | width: 8, 389 | depth: 8, 390 | height: 8, 391 | gable: 'cap', 392 | addTo: temple2ndFloor, 393 | nsWindows:[ 394 | { height: 6 }, 395 | ], 396 | ewWindows:[ 397 | { height: 6 }, 398 | ], 399 | }); 400 | 401 | var temple3rdFloor = new Zdog.Anchor({ 402 | addTo: temple2ndFloor, 403 | translate: { y: -10 }, 404 | }); 405 | 406 | makeBuilding({ 407 | width: 6, 408 | depth: 6, 409 | height: 6, 410 | gable: 'flat', 411 | addTo: temple3rdFloor, 412 | nsWindows:[ 413 | { y: -3 }, 414 | ], 415 | ewWindows:[ 416 | { y: -3 }, 417 | ], 418 | }); 419 | 420 | dome.copy({ 421 | diameter: 4, 422 | addTo: temple3rdFloor, 423 | translate: { y: -6 }, 424 | }); 425 | 426 | // ----- west perch ----- // 427 | 428 | var westPerchAnchor = new Zdog.Anchor({ 429 | addTo: island, 430 | translate: { x: -39, z: 11, y: -44 } 431 | }); 432 | 433 | makeBuilding({ 434 | width: 6, 435 | depth: 6, 436 | height: 6, 437 | gable: 'flat', 438 | addTo: westPerchAnchor, 439 | nsWindows:[ 440 | { y: -3, style: 'circle', }, 441 | ], 442 | ewWindows:[ 443 | { y: -3, style: 'circle', }, 444 | ], 445 | }); 446 | 447 | dome.copy({ 448 | diameter: 6, 449 | addTo: westPerchAnchor, 450 | translate: { y: -6 }, 451 | }); 452 | 453 | // perch rock 454 | makeRock({ 455 | width: 19, 456 | depth: 9, 457 | height: 10, 458 | addTo: island, 459 | translate: { x: -36, z: 13, y: -33 }, 460 | westOffset: -1, 461 | eastOffset: -7, 462 | northOffset: -3, 463 | southOffset: 0, 464 | }); 465 | 466 | // beneath perch rock & 2 story 467 | 468 | makeRock({ 469 | width: 24, 470 | depth: 22, 471 | height: 8, 472 | addTo: island, 473 | translate: { x: -35, z: 19, y: -25 }, 474 | westOffset: -1.5, 475 | eastOffset: -3, 476 | northOffset: -2, 477 | // southOffset: 0, 478 | }); 479 | 480 | // perch staircase 481 | 482 | var staircaseAnchor = new Zdog.Shape({ 483 | addTo: island, 484 | visible: false, 485 | translate: { x: -35, y: -14, z: 5 }, 486 | }); 487 | 488 | makeBuilding({ 489 | width: 6, 490 | depth: 4, 491 | height: 22, 492 | gable: 'slantS', 493 | addTo: staircaseAnchor, 494 | nsWindows: [ 495 | { y: -19 }, 496 | { y: -12 }, 497 | { y: -5 }, 498 | ] 499 | }); 500 | 501 | // ----- hill buildings ----- // 502 | 503 | // center behind cathedral 504 | oneStorySlanter({ 505 | addTo: island, 506 | translate: { x: -14, y: -26, z: 18 }, 507 | gable: 'slantS', 508 | }); 509 | 510 | // behind west perch 511 | twoStoryBuilding({ 512 | addTo: island, 513 | translate: { x: -38, y: -34, z: 23 }, 514 | gable: 'ns', 515 | }); 516 | 517 | oneStoryBuilding({ 518 | addTo: island, 519 | translate: { x: 9, y: -32, z: 24 }, 520 | gable: 'ew', 521 | }); 522 | 523 | // ----- back tower ----- // 524 | 525 | var backTowerAnchor = new Zdog.Anchor({ 526 | addTo: island, 527 | translate: { x: -15, y: -18, z: 35 } 528 | }); 529 | 530 | makeBuilding({ 531 | width: 6, 532 | height: 30, 533 | depth: 6, 534 | gable: 'flat', 535 | addTo: backTowerAnchor, 536 | nsWindows: [ { y: -27 } ], 537 | ewWindows: [ { y: -27 } ], 538 | }); 539 | 540 | dome.copy({ 541 | addTo: backTowerAnchor, 542 | translate: { y: -30 }, 543 | diameter: 4, 544 | }); 545 | 546 | // -- animate --- // 547 | 548 | function animate() { 549 | illo.rotate.y += isSpinning ? TAU/150 : 0; 550 | illo.updateRenderGraph(); 551 | requestAnimationFrame( animate ); 552 | } 553 | 554 | animate(); 555 | 556 | // ----- inputs ----- // 557 | 558 | document.querySelector('.reset-button').onclick = function() { 559 | illo.rotate.set( initRotate ); 560 | }; 561 | --------------------------------------------------------------------------------