├── .gitignore
├── .jshintrc
├── .netlify
└── state.json
├── .tm_properties
├── README.md
├── assets
└── favicon.ico
├── base
├── .jshintrc
├── base.css
├── boilerplate.js
├── fonts.css
├── init.js
└── syntax-highlight.css
├── content
├── 404.hbs
├── api.hbs
├── extras.hbs
├── getting-started.hbs
├── index.hbs
├── modeling.hbs
└── shapes.hbs
├── data
└── made_with_examples.json
├── demos
├── .jshintrc
├── api-demos
│ ├── anchor-copy-graph.js
│ ├── anchor-copy.js
│ ├── anchor-transform.js
│ ├── dragger-rotate-sync.js
│ ├── illo-drag-rotate-item.js
│ ├── illo-element.js
│ ├── illo-on-prerender.js
│ ├── illo-resize.js
│ ├── path-arc.js
│ ├── path-bezier.js
│ ├── shape-backface.js
│ ├── shape-option.js
│ ├── shape-update-path.js
│ └── utils-ease-in-out.js
├── extras-demos
│ ├── composite-scale-bug.js
│ ├── kid-kit.js
│ ├── one-pixel-gap-fix-zoom.js
│ ├── one-pixel-gap-fix.js
│ ├── z-fight-dot-cracker.js
│ ├── z-fight-dot-sandwich.js
│ └── z-fight-intro.js
├── modeling-demos
│ ├── child-shapes.js
│ ├── group-eye.js
│ ├── group-wall.js
│ ├── model-arms.js
│ ├── model-body-core.js
│ ├── model-head.js
│ ├── model-legs.js
│ ├── model-rotate-legs.js
│ ├── model-rotate-spine.js
│ └── tasty-burger.js
└── starter-demos
│ ├── starter-drag-rotate-spin.js
│ ├── starter-drag-rotate.js
│ ├── starter-initial.js
│ ├── starter-rect.js
│ └── starter-zoom.js
├── gulpfile.js
├── modules
├── .jshintrc
├── container
│ └── container.css
├── docs
│ ├── api-anchor.hbs
│ ├── api-dragger.hbs
│ ├── api-group.hbs
│ ├── api-illo.hbs
│ ├── api-shape.hbs
│ ├── api-utils.hbs
│ ├── api-vector.hbs
│ ├── child-shapes-add-to.hbs
│ ├── copy-example.hbs
│ ├── copy-graph-example.hbs
│ ├── group-concept.hbs
│ ├── modeling-concepts.hbs
│ ├── modeling-tutorial.hbs
│ ├── shapes-basic.hbs
│ ├── shapes-composite.hbs
│ ├── shapes-shape.hbs
│ └── vector-objects.hbs
├── edit-demo
│ ├── edit-demo.css
│ └── edit-demo.hbs
├── example
│ ├── eval-shape-demo.js
│ ├── eval-spin-demo.js
│ └── example.css
├── gh-button
│ ├── gh-button.css
│ ├── gh-button.hbs
│ └── gh-button.js
├── grid4
│ └── grid4.css
├── hashed-header
│ └── hashed-header.css
├── hero
│ ├── hero.css
│ └── hero.hbs
├── illo-showcase
│ ├── illo-showcase.css
│ ├── illo-showcase.hbs
│ └── illo-showcase.js
├── illo
│ └── illo.css
├── made-with-showcase
│ ├── made-with-showcase.css
│ └── made-with-showcase.hbs
├── masthead
│ └── masthead.css
├── nav
│ └── nav.css
├── page-nav
│ └── page-nav.css
├── site-footer
│ ├── site-footer.css
│ └── site-footer.hbs
├── site-nav
│ ├── site-nav.css
│ ├── site-nav.hbs
│ └── site-nav.js
├── socks-promo
│ ├── socks-promo.css
│ └── socks-promo.hbs
└── zdog-logo
│ ├── zdog-logo.css
│ ├── zdog-logo.hbs
│ └── zdog-logo.js
├── netlify.toml
├── package-lock.json
├── package.json
├── tasks
├── assets.js
├── content.js
├── css.js
├── hint.js
├── js.js
└── utils
│ ├── get-glob-paths.js
│ ├── highlight-code-block.js
│ └── page-nav.js
└── templates
└── page.hbs
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | bower_components/
3 | build/
4 | **/fonts/*
5 | notes.md
6 | assets/img/*
7 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esversion": 6,
3 | "node": true,
4 | "undef": true,
5 | "unused": true
6 | }
7 |
--------------------------------------------------------------------------------
/.netlify/state.json:
--------------------------------------------------------------------------------
1 | {
2 | "siteId": "a957cda4-9613-41ff-9b1d-b16843df6be8"
3 | }
--------------------------------------------------------------------------------
/.tm_properties:
--------------------------------------------------------------------------------
1 | softTabs = true
2 | tabSize = 2
3 | excludeInFileChooser = "{$exclude,build,bower_components,node_modules}"
4 | excludeInFolderSearch = "{$exclude,build,bower_components,node_modules}"
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Zdog docs
2 |
3 | Documentation site for [Zdog](https://github.com/metafizzy/zdog) - Flat, round, designer-friendly pseudo 3D engine
4 |
5 | [zzz.dog](https://zzz.dog)
6 |
7 | ## Install
8 |
9 | Install dependencies with npm.
10 |
11 | ``` bash
12 | npm install
13 | ```
14 |
15 | ## Tasks
16 |
17 | + `gulp` - build the production site, concatenate CSS and JS, minify JS
18 | + `gulp dev` - build the site, but use separate CSS and JS files for debugging
19 | + `gulp hint` - Lint JavaScript and JSON files
20 |
21 | ## Structure
22 |
23 | + `assets/` - files that get copied into `build/`. Fonts and images have been ignored from the repo
24 | + `base/` - boilerplate CSS and JS files
25 | + `build/` - where static site gets built
26 | + `content/` - page content
27 | + `data/` - site data
28 | + `demos/` - in-page demo modules, similar to modules
29 | + `modules/` - See Modules below
30 | + `tasks/` - Gulp tasks to build the site
31 | + `templates/` - page templates
32 |
33 | ## Modules
34 |
35 | Modules are re-usable components used throughout the site. A module may consist of template, JS, and CSS files.
36 |
37 | modules/
38 | page-nav/
39 | page-nav.css
40 | page-nav.js
41 | page-nav.hbs
42 |
43 | [BEM](https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) is used for CSS code style.
44 |
45 | ``` css
46 | .page-nav {} /* block */
47 | .page-nav__item {} /* element, child */
48 | .page-nav--dark {} /* modifier */
49 | ```
50 |
51 | JavaScript can be initialized for each element with `data-js` attribute.
52 |
53 | ``` html
54 |
55 | ```
56 |
57 | ``` js
58 | ZdogDocs.pageNav = function( elem ) {
59 | // do something with elem
60 | };
61 | ```
62 |
63 | ---
64 |
65 | Made by [Metafizzy](https://metafizzy.co) 🌈🐻
66 |
--------------------------------------------------------------------------------
/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/metafizzy/zdog-docs/f3c5b98ea516a9cd34a60adb5994ba41e48a8d4f/assets/favicon.ico
--------------------------------------------------------------------------------
/base/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "unused": true,
4 | "undef": true,
5 | "globals": {
6 | "Zdog": false,
7 | "ZdogDocs": false
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/base/base.css:
--------------------------------------------------------------------------------
1 | /* base
2 | ------------------------- */
3 |
4 | * { box-sizing: border-box; }
5 |
6 | body {
7 | font-family: 'Texta', sans-serif;
8 | color: #534;
9 | line-height: 1.5;
10 | margin: 0;
11 | padding: 1.0rem 0;
12 | }
13 |
14 | /* font size on html for rem */
15 | html { font-size: 17px; }
16 |
17 | /* ---- links ---- */
18 |
19 | a {
20 | color: #E62;
21 | text-decoration: none;
22 | }
23 |
24 | a:visited { color: #C25; }
25 |
26 | a:hover {
27 | color: #636;
28 | background: #FDB;
29 | }
30 |
31 | a:focus, a:active {
32 | background: #EA0;
33 | }
34 |
35 | /* ---- code ---- */
36 |
37 | pre, code, kbd {
38 | font-family: Consolas, Menlo, monospace;
39 | font-size: 13px;
40 | background: #FFF4E8;
41 | white-space: pre-wrap;
42 | }
43 |
44 | pre {
45 | padding: 10px;
46 | border-radius: 6px;
47 | overflow: auto;
48 | }
49 |
50 | code {
51 | padding: 2px 3px 1px;
52 | line-height: 1.2;
53 | border-radius: 3px;
54 | }
55 |
56 | pre code {
57 | padding: 0;
58 | line-height: 1.5;
59 | background: none;
60 | border: none;
61 | }
62 |
63 | /* ---- ---- */
64 |
65 | @media screen and ( min-width: 768px ) {
66 |
67 | html { font-size: 19px; }
68 |
69 | pre, code, kbd {
70 | font-size: 15px;
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/base/boilerplate.js:
--------------------------------------------------------------------------------
1 | // boilerplate
2 |
3 | /* globals IntersectionObserver */
4 |
5 | ( function() {
6 |
7 | // v1.0.2 hotfix
8 | Zdog.Anchor.prototype.renderGraphSvg = function( svg ) {
9 | if ( !svg ) {
10 | throw new Error( 'svg is ' + svg + '. ' +
11 | 'SVG required for render. Check .renderGraphSvg( svg ).' );
12 | }
13 | this.flatGraph.forEach( function( item ) {
14 | item.render( svg, Zdog.SvgRenderer );
15 | });
16 | };
17 |
18 | // global namespace
19 | window.ZdogDocs = {};
20 |
21 | // global convience variables
22 | window.TAU = Zdog.TAU;
23 | // colors
24 | window.offWhite = '#FED';
25 | window.yellow = '#ED0';
26 | window.gold = '#EA0';
27 | window.orange = '#E62';
28 | window.garnet = '#C25';
29 | window.eggplant = '#636';
30 |
31 | // ----- shapeDemo ----- //
32 |
33 | ZdogDocs.shapeDemo = function( callback ) {
34 | return function( canvas, data ) {
35 | var isAnimating = false;
36 |
37 | var illo = new Zdog.Illustration({
38 | element: canvas,
39 | dragRotate: true,
40 | onDragStart: function() {
41 | isAnimating = true;
42 | animate();
43 | },
44 | onDragEnd: function() {
45 | isAnimating = false;
46 | },
47 | });
48 |
49 | callback( canvas, data, illo );
50 |
51 | function animate() {
52 | illo.updateRenderGraph();
53 | if ( isAnimating ) {
54 | requestAnimationFrame( animate );
55 | }
56 | }
57 |
58 | animate();
59 |
60 | };
61 | };
62 |
63 | // ----- IntersectionObserver ----- //
64 |
65 | ZdogDocs.supportsIntObs = typeof IntersectionObserver == 'function';
66 |
67 | // ----- IntersectionObserver ----- //
68 |
69 | ZdogDocs.observeIntersect = function( options ) {
70 | if ( !ZdogDocs.supportsIntObs ) {
71 | return;
72 | }
73 |
74 | var obsOptions = {
75 | threshold: options.threshold || 0.2,
76 | };
77 |
78 | var onIntersect = function( entries ) {
79 | var entry = entries[0];
80 | var isIntersect = entry.intersectionRatio > obsOptions.threshold;
81 | options.onIntersect( isIntersect );
82 | };
83 |
84 | var observer = new IntersectionObserver( onIntersect, obsOptions );
85 | observer.observe( options.element );
86 | observer.takeRecords();
87 |
88 | };
89 |
90 | // ----- spinDemo ----- //
91 |
92 | ZdogDocs.spinDemo = function( callback ) {
93 | return function( canvas, data ) {
94 |
95 | var isSpinning = true;
96 | var isDragging = false;
97 | var didDrag = false;
98 |
99 | var illo = new Zdog.Illustration({
100 | element: canvas,
101 | dragRotate: true,
102 | onDragStart: function() {
103 | isSpinning = false;
104 | isDragging = true;
105 | didDrag = true;
106 | animate();
107 | },
108 | onDragEnd: function() {
109 | isDragging = false;
110 | },
111 | });
112 |
113 | callback( canvas, data, illo );
114 |
115 | function animate() {
116 | if ( isSpinning ) {
117 | illo.rotate.y += 0.03;
118 | }
119 | illo.updateRenderGraph();
120 | if ( isSpinning || isDragging ) {
121 | requestAnimationFrame( animate );
122 | }
123 | }
124 |
125 | // ----- IntersectionObserver ----- //
126 |
127 | // start animation if no IntObs
128 | if ( !ZdogDocs.supportsIntObs ) {
129 | animate();
130 | }
131 |
132 | ZdogDocs.observeIntersect({
133 | element: canvas,
134 | onIntersect: function( isIntersect ) {
135 | if ( didDrag ) {
136 | return;
137 | }
138 | isSpinning = isIntersect;
139 | if ( isSpinning ) {
140 | animate();
141 | }
142 | }
143 | });
144 |
145 | };
146 | };
147 |
148 | })();
149 |
--------------------------------------------------------------------------------
/base/fonts.css:
--------------------------------------------------------------------------------
1 | /* fonts
2 | ------------------------- */
3 |
4 | @import url("https://hello.myfonts.net/count/2d333f");
5 |
6 | /* Texta Heavy */
7 | @font-face {
8 | font-family: 'Texta';
9 | font-weight: bold;
10 | font-style: normal;
11 | src: url('../assets/fonts/2D333F_0_0.woff2') format('woff2'),
12 | url('../assets/fonts/2D333F_0_0.woff') format('woff');
13 | }
14 |
15 | /* Texta Italic */
16 | @font-face {
17 | font-family: 'Texta';
18 | font-weight: normal;
19 | font-style: italic;
20 | src: url('../assets/fonts/2D333F_1_0.woff2') format('woff2'),
21 | url('../assets/fonts/2D333F_1_0.woff') format('woff');
22 | }
23 |
24 | /* Texta Regular */
25 | @font-face {
26 | font-family: 'Texta';
27 | src: url('../assets/fonts/2D333F_2_0.woff2') format('woff2'),
28 | url('../assets/fonts/2D333F_2_0.woff') format('woff');
29 | }
30 |
--------------------------------------------------------------------------------
/base/init.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | // init all modules, based on their data-js attribute
4 | var jsModuleElems = document.querySelectorAll('[data-js]');
5 | for ( var i=0; i < jsModuleElems.length; i++ ) {
6 | var elem = jsModuleElems[i];
7 | var moduleName = elem.getAttribute('data-js');
8 | var module = ZdogDocs[ moduleName ];
9 | if ( module ) {
10 | // turn data-attributes into data
11 | var attrData = getAttrData( elem );
12 | module( elem, attrData );
13 | }
14 | }
15 |
16 | // get data-attribute and add to object
17 | function getAttrData( elem ) {
18 | var data = {};
19 | for ( var i=0; i < elem.attributes.length; i++ ) {
20 | var attr = elem.attributes[i];
21 | var keyMatch = attr.name.match( /data\-(\w+)/i );
22 | var key = keyMatch && keyMatch[1];
23 | if ( key ) {
24 | data[ key ] = attr.value;
25 | }
26 | }
27 | return data;
28 | }
29 |
30 | })();
31 |
--------------------------------------------------------------------------------
/base/syntax-highlight.css:
--------------------------------------------------------------------------------
1 | /* syntax highlight
2 | ------------------------- */
3 |
4 | code .string,
5 | code .tag .value { color: #0A2; }
6 | code .number, /* integer */
7 | code .literal { color: #07D; } /*boolean*/
8 | code .keyword { color: #E31; } /* keyword */
9 | code .attribute, /* HTML attribute */
10 | code .attr { color: #818; } /* JS Object key */
11 | code .title { color: #39A; }
12 | code .params { color: #98D; }
13 | code .subst { color: #081; } /* JS substring `${substr}` */
14 |
15 | /* comment */
16 | code .comment { color: #999; font-style: italic; }
17 |
18 | code .tag { color: #37B; } /* Markup open tag */
19 |
20 | code .id { color: #567; } /* css id */
21 | code .class { color: #B27; } /* CSS class */
22 | code .rules { color: #431; }
23 | code .value { color: #555; } /* CSS value */
24 | code .pseudo { color: #38D; } /* CSS pseudo selector */
25 | code .hexcolor { color: #F63; }
26 | code .at_rule { color: #088; }
27 |
28 | code .built_in { color: #E08; }
29 |
30 | code .zdog_class { color: #C25; } /* Zdog classes */
31 | code .demo_var { color: #096; }
32 |
--------------------------------------------------------------------------------
/content/404.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: Page not found
3 | ---
4 |
5 |
Sorry about that!
6 |
7 |
Instead, here is the character model for the game I never made.
8 |
9 |
11 |
--------------------------------------------------------------------------------
/content/api.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: API
3 | ---
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
Classes
8 |
9 |
Zdog’s API consists mostly of creating and using instances of its classes.
10 |
11 | ``` js
12 | let illo = new Zdog.Illustration({
13 | element: '.zdog-canvas',
14 | });
15 |
16 | let anchor = new Zdog.Anchor({
17 | addTo: illo,
18 | translate: { y: 10 },
19 | });
20 |
21 | let rect = new Zdog.Rect({
22 | addTo: anchor,
23 | });
24 |
25 | illo.updateRenderGraph();
26 | ```
27 |
28 | {{! --------------------------------------------- }}
29 |
30 |
Properties
31 |
32 |
Set initial properties with an object.
33 |
34 | ``` js
35 | let rect = new Zdog.Rect({
36 | addTo: illo,
37 | width: 80,
38 | height: 60,
39 | rotate: { y: -2 },
40 | color: '#E62',
41 | });
42 | ```
43 |
44 |
Get and re-set properties on the returned instance.
45 |
46 | ``` js
47 | // get option
48 | console.log( rect.rotate.y );
49 | // => -2
50 |
51 | // re-set option
52 | rect.rotate.y = 3;
53 | ```
54 |
55 | {{! --------------------------------------------- }}
56 |
57 |
Inheritance
58 |
59 |
Some Zdog classes inherit functionality from other classes. For example, Rect
inherits from Shape
and Shape
inherits from Anchor
. This means that Rect
can use all the properties and methods from Shape
and Anchor
.
60 |
61 | {{! --------------------------------------------- }}
62 |
63 | {{> api-anchor }}
64 | {{> api-shape }}
65 | {{> api-group }}
66 | {{> api-dragger }}
67 | {{> api-illo }}
68 | {{> api-vector }}
69 | {{> api-utils }}
70 |
--------------------------------------------------------------------------------
/content/extras.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: Extras
3 | ---
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
Z-fighting
8 |
9 |
10 |
11 |
Z-fighting is when two shapes pop-over one another as they appear to fight for position. In polygonal 3D engines, z-fighting happens when two polygons are coplanar. In Zdog, z-fighting happens when any shapes occupy the same space.
12 |
13 |
14 |
16 | {{> edit-demo penSlug="QRmWgd"}}
17 |
18 |
19 |
20 |
Z-fighting in Zdog is the natural result of its pseudo-3D engine. Zdog’s 3D shapes are actually 2D projections, rendered without any accounting for collisions with other shapes.
21 |
22 |
Rather than fighting against this effect, the best course is to accept it. Z-fighting is one of Zdog’s charms . Embrace it.
23 |
24 |
That said, there are some techniques to address z-fighting.
25 |
26 |
27 |
28 |
A simple solution is to use the same color for multiple shapes.
29 |
30 |
31 |
33 | {{> edit-demo penSlug="GaxRMg"}}
34 |
35 |
36 |
37 |
38 |
39 |
For shapes of similar size, move the shapes away from one another so their stroke volume do not overlap.
40 |
41 |
42 |
44 | {{> edit-demo penSlug="mYxdqd"}}
45 |
46 |
47 |
48 |
49 |
50 |
Use a Group
for groups of shapes that collectively cover the same area as a larger shape. In this demo, the gold dots are in a Group
, whereas the purple dots are individual shapes.
51 |
52 |
53 |
55 | {{> edit-demo penSlug="wbmvpW"}}
56 |
57 |
58 |
59 |
Use a Shape
with visible: false
in a Group
to balance out its z-index. Shape
z-index is calculated as the average of all the shape’s path points. Group
z-index is calcuated as the average of all the grouped shapes' z-indexes. So you can affect the z-index of a Group
by adding or moving invisible shapes.
60 |
61 |
In the demo below, the gold dot has a counter-balanced invisible shape in its group.
62 |
63 |
64 |
65 | ``` js
66 | let group = new Zdog.Group({...});
67 | // dot
68 | new Zdog.Shape({
69 | addTo: group,
70 | stroke: 20,
71 | translate: { x: 45, y: -45 },
72 | color: '#EA0',
73 | });
74 | // invisible Shape to counter-balance group z-index
75 | new Zdog.Shape({
76 | addTo: group,
77 | visible: false,
78 | translate: { x: -45, y: 45 },
79 | });
80 | ```
81 |
82 |
83 |
85 | {{> edit-demo penSlug="OYvJQN"}}
86 |
87 |
88 |
89 | {{! --------------------------------------------- }}
90 |
91 |
Known bugs
92 |
93 | {{! --------------------------------------------- }}
94 |
95 |
Hemisphere, Cylinder, & Cone scale bug
96 |
97 |
Due to Zdog’s underlying math, Hemisphere
, Cylinder
, and Cone
shapes cannot be scaled with a 1- or 2-dimensional Vector
.
98 |
99 |
100 |
101 | ``` js
102 | let anchor = new Zdog.Anchor({
103 | // 1-dimensional scale
104 | // will break Hemisphere, Cone, & Cylinder
105 | scale: { y: 2 },
106 | });
107 |
108 | new Zdog.Hemisphere({ addTo: anchor, /*...*/ });
109 | new Zdog.Cylinder({ addTo: anchor, /*...*/ });
110 | new Zdog.Cone({ addTo: anchor, /*...*/ });
111 | ```
112 |
113 |
114 |
116 | {{> edit-demo penSlug="oRqNqO"}}
117 |
118 |
119 |
120 |
However, uniform Vector
options will still work.
121 |
122 |
123 |
124 | ``` js
125 | let anchor = new Zdog.Anchor({
126 | // uniform scale, will be okay
127 | scale: 2,
128 | });
129 |
130 | new Zdog.Hemisphere({ addTo: anchor, /*...*/ });
131 | new Zdog.Cylinder({ addTo: anchor, /*...*/ });
132 | new Zdog.Cone({ addTo: anchor, /*...*/ });
133 | ```
134 |
135 |
136 |
138 | {{> edit-demo penSlug="RmMwJN"}}
139 |
140 |
141 |
142 |
143 | {{! --------------------------------------------- }}
144 |
145 |
One pixel gaps
146 |
147 |
Gaps can appear in between flat polygons of solids.
148 |
149 |
150 |
151 | ``` js
152 | new Zdog.Box({
153 | addTo: illo,
154 | width: 120,
155 | height: 100,
156 | depth: 80,
157 | rotate: { x: -Zdog.TAU/8, y: Zdog.TAU/8 },
158 | stroke: false,
159 | color: '#EA0',
160 | rearFace: '#636',
161 | leftFace: '#636',
162 | bottomFace: '#636',
163 | });
164 | ```
165 |
166 |
167 |
168 | {{> edit-demo penSlug="qGoByv"}}
169 |
170 |
171 |
172 |
You can cover over this gaps by adding a 1-pixel-wide stroke to the polygons.
173 |
174 |
175 |
176 | ``` js
177 | // with an Illustration without zoom set
178 |
179 | new Zdog.Box({
180 | // 1px stroke to cover edge-to-edge gaps
181 | stroke: 1,
182 | // ...
183 | });
184 | ```
185 |
186 |
187 |
188 | {{> edit-demo penSlug="OYvJoX"}}
189 |
190 |
191 |
192 |
193 |
194 | ``` js
195 | // with an Illustration with zoom set
196 | let illo = new Illustration({
197 | zoom: 4,
198 | // ...
199 | });
200 |
201 | new Zdog.Box({
202 | addTo: illo,
203 | stroke: 1 / illo.zoom, // 1px stroke
204 | // ...
205 | });
206 | ```
207 |
208 |
209 |
211 | {{> edit-demo penSlug="qGoBMw"}}
212 |
213 |
214 |
215 | {{! --------------------------------------------- }}
216 |
217 |
Rendering without Illustration
218 |
219 |
You can render Zdog models without using Illustration
, in the case you are directly using a <canvas>
or <svg>
and prefer to handle managing the element yourself.
220 |
221 |
The demos below work by using a generic Anchor
as the scene
object. The scene
’s graph is then updated with updateGraph
and rotated by dragging with a Dragger
.
222 |
223 | {{! --------------------------------------------- }}
224 |
225 |
Rendering with canvas without Illustration
226 |
227 |
Render the scene
’s graph on a <canvas>
with renderGraphCanvas
. Additional code is required to prepare the canvas for rendering. View this demo on CodePen.
228 |
229 | ``` js
230 | // ----- setup ----- //
231 |
232 | // get canvas element and its context
233 | let canvas = document.querySelector('.zdog-canvas');
234 | let ctx = canvas.getContext('2d');
235 | // get canvas size
236 | let canvasWidth = canvas.width;
237 | let canvasHeight = canvas.height;
238 | // illustration variables
239 | const TAU = Zdog.TAU;
240 | const zoom = 4;
241 | let isSpinning = true;
242 |
243 | // create an scene Anchor to hold all items
244 | let scene = new Zdog.Anchor();
245 |
246 | // ----- model ----- //
247 |
248 | // add shapes to scene
249 | new Zdog.Shape({
250 | addTo: scene,
251 | //...
252 | });
253 |
254 | new Zdog.Ellipse({
255 | addTo: scene,
256 | //...
257 | });
258 |
259 | // ----- animate ----- //
260 |
261 | function animate() {
262 | // make changes to model, like rotating scene
263 | scene.rotate.y += isSpinning ? 0.03 : 0;
264 | scene.updateGraph();
265 | render();
266 | requestAnimationFrame( animate );
267 | }
268 |
269 | function render() {
270 | // clear canvas
271 | ctx.clearRect( 0, 0, canvasWidth, canvasHeight );
272 | ctx.save();
273 | // center canvas & zoom
274 | ctx.translate( canvasWidth/2, canvasHeight/2 );
275 | ctx.scale( zoom, zoom );
276 | // set lineJoin and lineCap to round
277 | ctx.lineJoin = 'round';
278 | ctx.lineCap = 'round';
279 | // render scene graph
280 | scene.renderGraphCanvas( ctx );
281 | ctx.restore();
282 | }
283 |
284 | animate();
285 |
286 | // ----- drag ----- //
287 |
288 | let dragStartRX, dragStartRY;
289 | let minSize = Math.min( canvasWidth, canvasHeight );
290 |
291 | // add drag-rotatation with Dragger
292 | new Zdog.Dragger({
293 | startElement: canvas,
294 | onDragStart: function() {
295 | isSpinning = false;
296 | dragStartRX = scene.rotate.x;
297 | dragStartRY = scene.rotate.y;
298 | },
299 | onDragMove: function( pointer, moveX, moveY ) {
300 | scene.rotate.x = dragStartRX - ( moveY / minSize * TAU );
301 | scene.rotate.y = dragStartRY - ( moveX / minSize * TAU );
302 | },
303 | });
304 | ```
305 | {{> edit-demo penSlug="MdVWzV"}}
306 |
307 | {{! --------------------------------------------- }}
308 |
309 |
Rendering with SVG without Illustration
310 |
311 |
Render the scene’s graph on a <svg>
with renderGraphSvg
. Additional code is required to prepare the SVG for rendering. View this demo on CodePen.
312 |
313 | ``` js
314 | // ----- setup ----- //
315 |
316 | // get svg element
317 | let svg = document.querySelector('svg');
318 | // rendering sizes
319 | const zoom = 4;
320 | let sceneWidth = 16;
321 | let sceneHeight = 16;
322 | let viewWidth = sceneWidth * zoom;
323 | let viewHeight = sceneHeight * zoom;
324 | let svgWidth = svg.getAttribute('width');
325 | let svgHeight = svg.getAttribute('height');
326 | // set viewBox using zoom
327 | svg.setAttribute( 'viewBox', `${-viewWidth/2} ${-viewHeight/2} ` +
328 | `${viewWidth} ${viewHeight}` );
329 | // rendering variable
330 | const TAU = Zdog.TAU;
331 | let isSpinning = true;
332 |
333 | // create an scene Anchor to hold all items
334 | let scene = new Zdog.Anchor();
335 |
336 | // ----- model ----- //
337 |
338 | // add shapes to scene
339 | new Zdog.Shape({
340 | addTo: scene,
341 | //...
342 | });
343 |
344 | new Zdog.Ellipse({
345 | addTo: scene,
346 | //...
347 | });
348 |
349 | // ----- animate ----- //
350 |
351 | function animate() {
352 | scene.rotate.y += isSpinning ? 0.03 : 0;
353 | scene.updateGraph();
354 | render();
355 | requestAnimationFrame( animate );
356 | }
357 |
358 | function render() {
359 | empty( svg );
360 | scene.renderGraphSvg( svg );
361 | }
362 |
363 | animate();
364 |
365 | function empty( element ) {
366 | while ( element.firstChild ) {
367 | element.removeChild( element.firstChild );
368 | }
369 | }
370 |
371 | // ----- drag ----- //
372 |
373 | // click drag to rotate
374 | let dragStartRX, dragStartRY;
375 | let minSize = Math.min( svgWidth, svgHeight );
376 |
377 | // add drag-rotatation with Dragger
378 | new Zdog.Dragger({
379 | startElement: svg,
380 | onDragStart: function() {
381 | isSpinning = false;
382 | dragStartRX = scene.rotate.x;
383 | dragStartRY = scene.rotate.y;
384 | },
385 | onDragMove: function( pointer, moveX, moveY ) {
386 | scene.rotate.x = dragStartRX - ( moveY / minSize * TAU );
387 | scene.rotate.y = dragStartRY - ( moveX / minSize * TAU );
388 | },
389 | });
390 | ```
391 | {{> edit-demo penSlug="OYvJqb"}}
392 |
393 | {{! --------------------------------------------- }}
394 |
395 |
Canvas or SVG
396 |
397 |
Should you use <canvas>
or <svg>
? Visually, canvas and SVG output the same exact image with Zdog. In practice, they each have their benefits.
398 |
399 |
Canvas is better for lots of shapes and smaller image sizes . Canvas renders on a flat image, so it doesn't have to manage a DOM. But its rendered with pixels, so it can be slower with larger sizes — particularly with high-resolution screens.
400 |
401 |
SVG is better for fewer shapes and larger image sizes. SVG is a vector format, so its resolution independent, perfect for large image sizes. However, all shapes have to be rendered and sorted with individual DOM elements, which can negatively impact performance and get your fan spinning.
402 |
403 | {{! --------------------------------------------- }}
404 |
405 |
Feature requests
406 |
407 |
Help me select new features by adding your 👍 reaction to GitHub issues for features you would like to see added. Hotly requested features include:
408 |
409 |
416 |
417 | {{! --------------------------------------------- }}
418 |
419 |
More Zdog resources
420 |
421 |
Other people’s stuff:
422 |
423 |
431 |
432 |
My stuff:
433 |
434 |
438 |
439 | {{! --------------------------------------------- }}
440 |
--------------------------------------------------------------------------------
/content/getting-started.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting started
3 | ---
4 |
5 |
This page will walk you through how to design, display, and animate a basic 3D model with Zdog.
6 |
7 | {{! --------------------------------------------- }}
8 |
9 |
HTML
10 |
11 | {{! --------------------------------------------- }}
12 |
13 |
Zdog is rendered on a <canvas>
or <svg>
element. Set width
and height
attributes to set the size.
14 |
15 | ``` html
16 |
17 | ```
18 |
19 |
Add the Zdog JavaScript file to your page. For quick demos, add the CDN URL. Finally add a <script>
for your demo’s JS file.
20 |
21 | ``` html
22 |
23 |
24 | ```
25 |
26 | {{! --------------------------------------------- }}
27 |
28 |
Initial static demo
29 |
30 |
Let’s jump in with a basic non-animated demo.
31 |
32 |
33 |
34 | ``` js
35 | // zdog-demo.js
36 |
37 | // create illo
38 | let illo = new Zdog.Illustration({
39 | // set canvas with selector
40 | element: '.zdog-canvas',
41 | });
42 |
43 | // add circle
44 | new Zdog.Ellipse({
45 | addTo: illo,
46 | diameter: 80,
47 | stroke: 20,
48 | color: '#636',
49 | });
50 |
51 | // update & render
52 | illo.updateRenderGraph();
53 | ```
54 |
55 |
56 |
58 | {{> edit-demo penSlug="RmLyyq"}}
59 |
60 |
61 |
62 |
Let’s break it down. The Zdog API mostly consists by creating instances of Zdog’s classes .
63 |
64 |
Illustration
is the top-level class that handles dealing with the <canvas>
or <svg>
element, holding all the shapes in the scene, and displaying those shapes in the element. We set the rendering HTML element by setting element
to its matching selector '.zdog-canvas'
. The Illustration
instance is then set as a variable illo
.
65 |
66 |
Ellipse
is a shape class. We added it to the scene with addTo: illo
. So the circle shape is a child of illo
— part of it’s descendant graph . We set other properties for the circle to set its size, shape, and color: diameter: 80, stroke: 20, color: '#636'.
67 |
68 |
Finally, to display the scene, we call illo.updateRenderGraph()
to update all the display properties, then render shapes on to the element.
69 |
70 |
And we get ... a 80px wide purple circle. Exciting!
71 |
72 | {{! --------------------------------------------- }}
73 |
74 |
Animating
75 |
76 |
To animate our scene we need to re-render illo
every frame.
77 |
78 |
79 |
80 | ``` js
81 | function animate() {
82 | // rotate illo each frame
83 | illo.rotate.y += 0.03;
84 | illo.updateRenderGraph();
85 | // animate next frame
86 | requestAnimationFrame( animate );
87 | }
88 | // start animation
89 | animate();
90 | ```
91 |
92 |
93 |
95 | {{> edit-demo penSlug="YbrLvO"}}
96 |
97 |
98 |
99 |
So we wrap illo.updateRenderGraph()
within a requestAnimationFrame
loop. Now we can manipulate the scene and see its changes animated. We change the rotation of the scene by incrementally increasing illo.rotate.y
.
100 |
101 |
And now the animated circle is ... kind of lame. It is rotating, but being all alone and sitting in direct center, the visual effect is weak. Let’s add another shape, a Rect
, and position the shapes in 3D space.
102 |
103 |
104 |
105 | ``` js
106 | // circle
107 | new Zdog.Ellipse({
108 | addTo: illo,
109 | diameter: 80,
110 | // position closer
111 | translate: { z: 40 },
112 | stroke: 20,
113 | color: '#636',
114 | });
115 |
116 | // square
117 | new Zdog.Rect({
118 | addTo: illo,
119 | width: 80,
120 | height: 80,
121 | // position further back
122 | translate: { z: -40 },
123 | stroke: 12,
124 | color: '#E62',
125 | fill: true,
126 | });
127 | ```
128 |
129 |
130 |
132 | {{> edit-demo penSlug="vwejaQ"}}
133 |
134 |
135 |
136 |
Now we're cooking. The shapes are positioned by setting translate
. The circle has translate: { z: 40 }
, so its original position is moved 40 pixels closer up front. The square is 40 pixels further back. The shapes are separated from another so, when rotating, they orbit around the center.
137 |
138 | {{! --------------------------------------------- }}
139 |
140 |
Zoom
141 |
142 |
Zdog requires setting lots of numbers. I like to keep my numbers smaller. Setting zoom
will scale the whole scene proportionally.
143 |
144 |
145 |
146 | ``` js
147 | let illo = new Zdog.Illustration({
148 | element: '.zdog-canvas',
149 | // zoom up 4x
150 | zoom: 4,
151 | });
152 |
153 | new Zdog.Ellipse({
154 | diameter: 20,
155 | translate: { z: 10 },
156 | stroke: 5,
157 | ...
158 | });
159 |
160 | new Zdog.Rect({
161 | width: 20,
162 | height: 20,
163 | translate: { z: -10 },
164 | stroke: 3,
165 | ...
166 | });
167 | ```
168 |
169 |
170 |
172 | {{> edit-demo penSlug="qGPYMo"}}
173 |
174 |
175 |
176 | {{! --------------------------------------------- }}
177 |
178 |
Drag rotate
179 |
180 |
Enable rotation with dragging by setting dragRotate: true
on the Illustration
.
181 |
182 |
183 |
184 | ``` js
185 | let illo = new Zdog.Illustration({
186 | element: '.zdog-canvas',
187 | zoom: 4,
188 | // enable rotating scene with dragging
189 | dragRotate: true,
190 | });
191 | ```
192 |
193 |
194 |
196 | {{> edit-demo penSlug="EzwLdw"}}
197 |
198 |
199 |
200 |
We can add back the regular rotation and stop it for dragging with onDragStart
.
201 |
202 |
203 |
204 | ``` js
205 | // rotating flag variable
206 | let isSpinning = true;
207 |
208 | let illo = new Zdog.Illustration({
209 | element: '.zdog-canvas',
210 | zoom: 4,
211 | dragRotate: true,
212 | // stop rotation when dragging starts
213 | onDragStart: function() {
214 | isSpinning = false;
215 | },
216 | });
217 |
218 | // add shapes...
219 |
220 | function animate() {
221 | // rotate
222 | if ( isSpinning ) {
223 | illo.rotate.y += 0.03;
224 | }
225 | illo.updateRenderGraph();
226 | requestAnimationFrame( animate );
227 | }
228 | animate();
229 | ```
230 |
231 |
232 |
234 | {{> edit-demo penSlug="YbrLaO"}}
235 |
236 |
237 |
238 |
That covers the basics of displaying a 3D model with Zdog. Now you’re ready to learn more about Zdog modeling and shapes .
239 |
240 |
--------------------------------------------------------------------------------
/content/index.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | homepage: true
3 | ---
4 |
5 | {{> illo-showcase }}
6 |
7 | {{! --------------------------------------------------- }}
8 |
9 |
Made with Zdog
10 |
11 | {{> made-with-showcase }}
12 |
13 | {{! --------------------------------------------------- }}
14 |
15 |
What is Zdog?
16 |
17 |
Zdog is a 3D JavaScript engine for <canvas>
and SVG. With Zdog, you can design and render simple 3D models on the Web. Zdog is a pseudo -3D engine. Its geometries exist in 3D space, but are rendered as flat shapes. This makes Zdog special.
18 |
19 |
20 | Zdog is small. 2,100 lines of code for the entire library. 28KB minified.
21 | Zdog is round. All circular shapes are rendered as proper circles with rounded edges. No polygonal jaggies.
22 | Zdog is friendly. Modeling is done with a straight-forward declarative API.
23 |
24 |
25 |
Zdog was designed to bring the simplicity of vector illustration into 3D. Drawing circles and squares is easy and fun. Zdog just adds another dimension.
26 |
27 | {{! --------------------------------------------------- }}
28 |
29 |
Install
30 |
31 |
Download
32 |
33 |
37 |
38 |
CDN
39 |
40 |
Link directly to Zdog JS on unpkg .
41 |
42 | ``` html
43 |
44 | ```
45 |
46 |
Package managers
47 |
48 |
49 | Install with npm: npm install zdog
50 | Install with Bower: bower install zdog --save
51 |
52 |
53 | {{! --------------------------------------------------- }}
54 |
55 |
Hello world demo
56 |
57 |
Create 3D models with Zdog by adding shapes. See Getting started for a walk-through of this demo.
58 |
59 |
60 |
61 | ``` js
62 | let isSpinning = true;
63 |
64 | let illo = new Zdog.Illustration({
65 | element: '.zdog-canvas',
66 | dragRotate: true,
67 | // stop spinning when drag starts
68 | onDragStart: function() {
69 | isSpinning = false;
70 | },
71 | });
72 |
73 | // circle
74 | new Zdog.Ellipse({
75 | addTo: illo,
76 | diameter: 80,
77 | translate: { z: 40 },
78 | stroke: 20,
79 | color: '#636',
80 | });
81 |
82 | // square
83 | new Zdog.Rect({
84 | addTo: illo,
85 | width: 80,
86 | height: 80,
87 | translate: { z: -40 },
88 | stroke: 12,
89 | color: '#E62',
90 | fill: true,
91 | });
92 |
93 | function animate() {
94 | illo.rotate.y += isSpinning ? 0.03 : 0;
95 | illo.updateRenderGraph();
96 | requestAnimationFrame( animate );
97 | }
98 | animate();
99 | ```
100 |
101 |
102 |
104 | {{> edit-demo penSlug="YbrLaO"}}
105 |
106 |
107 |
108 | {{! --------------------------------------------------- }}
109 |
110 |
About Zdog
111 |
112 |
Hi! Dave here . I wanted to make a video game. I needed a 3D engine, but most engines were too powerful and complex for me. I made Zdog so I could design and display simple 3D models without a lot of overhead.
113 |
114 |
Zdog is directly inspired by Dogz , a virtual pet game by P.F. Magic released in 1995. It used flat 2D circle sprites to render the Dogz’ models, but in a 3D scene. See Dogz playthrough video here. Dogz were fully animated in real time, running, flopping, scratching (on Windows 3.1!). It was remarkable.
115 |
116 |
Zdog uses the same principal. It renders all shapes using 2D drawing API in <canvas>
or <svg>
. Spheres are actually dots. Toruses are actually circles . Capsules are actually thick lines. It’s a simple, but effective trick. The underlying 3D math comes from Rotating 3D Shapes by Peter Collingridge .
117 |
118 |
Zdog is pronounced “Zee-dog” in American parlance or “Zed-dog” in British.
119 |
120 |
Beta!
121 |
122 |
Zdog v1 is a beta-release, of sorts. This is my first time creating a 3D engine, so I probably got some stuff wrong. Expect lots of changes for v2. Provide input and select new features on the Zdog issue tracker on GitHub .
123 |
--------------------------------------------------------------------------------
/content/modeling.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: Modeling
3 | ---
4 |
5 | {{> modeling-concepts }}
6 | {{> modeling-tutorial }}
7 |
--------------------------------------------------------------------------------
/content/shapes.hbs:
--------------------------------------------------------------------------------
1 | ---
2 | title: Shapes
3 | ---
4 |
5 |
Shapes are the visible items rendered in a Zdog model. All shape classes inherit Anchor
and Shape
properties and methods.
6 |
7 | {{> shapes-basic }}
8 | {{> shapes-shape }}
9 | {{> shapes-composite }}
10 |
--------------------------------------------------------------------------------
/data/made_with_examples.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "image": "davey-nippu.png",
4 | "link": "https://codepen.io/desandro/pen/RerqWW"
5 | },
6 | {
7 | "image": "happy-town.png",
8 | "link": "https://codepen.io/desandro/pen/vdwMyW"
9 | },
10 | {
11 | "image": "rgb-birdie.png",
12 | "link": "https://codepen.io/desandro/pen/VOzXzW"
13 | },
14 | {
15 | "image": "solid-shifter.png",
16 | "link": "https://codepen.io/desandro/pen/WLeKbg"
17 | },
18 | {
19 | "image": "mario.png",
20 | "link": "https://codepen.io/desandro/pen/qxjmKM"
21 | },
22 | {
23 | "image": "cone-ball.png",
24 | "link": "https://codepen.io/desandro/pen/aGOqjy"
25 | },
26 | {
27 | "image": "tri-prism.png",
28 | "link": "https://codepen.io/desandro/pen/gZMEBN"
29 | },
30 | {
31 | "image": "madeline.png",
32 | "link": "https://codepen.io/desandro/pen/RQeYYp"
33 | },
34 | {
35 | "image": "little-forest.png",
36 | "link": "https://codepen.io/desandro/pen/YebMXQ"
37 | },
38 | {
39 | "image": "solids.png",
40 | "link": "https://codepen.io/desandro/pen/MXPXGj"
41 | },
42 | {
43 | "image": "castle.png",
44 | "link": "https://codepen.io/desandro/pen/OryyEm"
45 | },
46 | {
47 | "image": "kirby.png",
48 | "link": "https://codepen.io/desandro/pen/aqYXoa"
49 | }
50 | ]
--------------------------------------------------------------------------------
/demos/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "unused": true,
4 | "undef": true,
5 | "globals": {
6 | "offWhite": false,
7 | "yellow": false,
8 | "gold": false,
9 | "orange": false,
10 | "garnet": false,
11 | "eggplant": false,
12 | "TAU": false,
13 | "Zdog": false,
14 | "ZdogDocs": false
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/demos/api-demos/anchor-copy-graph.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.anchorCopyGraph = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var rect = new Zdog.Rect({
4 | addTo: illo,
5 | width: 64,
6 | height: 64,
7 | translate: { x: -48 },
8 | stroke: 16,
9 | color: gold,
10 | });
11 |
12 | new Zdog.Shape({
13 | addTo: rect,
14 | translate: { z: 20 },
15 | stroke: 32,
16 | color: eggplant,
17 | });
18 |
19 | rect.copyGraph({
20 | translate: { x: 48 },
21 | color: garnet,
22 | });
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/demos/api-demos/anchor-copy.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.anchorCopy = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var rect = new Zdog.Rect({
4 | addTo: illo,
5 | width: 64,
6 | height: 64,
7 | translate: { x: -48 },
8 | stroke: 16,
9 | color: gold,
10 | });
11 |
12 | rect.copy({
13 | translate: { x: 48 },
14 | color: garnet,
15 | });
16 |
17 | });
18 |
--------------------------------------------------------------------------------
/demos/api-demos/anchor-transform.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.anchorTransform = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | // read transform from attribute and set anchor
4 | var anchorOptions = {
5 | addTo: illo,
6 | };
7 |
8 | if ( data.options ) {
9 | data.options = JSON.parse( data.options );
10 | Zdog.extend( anchorOptions, data.options );
11 | }
12 |
13 | var anchor = new Zdog.Anchor( anchorOptions );
14 |
15 | // circle
16 | new Zdog.Ellipse({
17 | addTo: anchor,
18 | diameter: 80,
19 | translate: { z: -40 },
20 | stroke: 20,
21 | color: eggplant,
22 | });
23 |
24 | // triangle
25 | new Zdog.Shape({
26 | addTo: anchor,
27 | path: [
28 | { x: 0, y: -32 },
29 | { x: 32, y: 32 },
30 | { x: -32, y: 32 },
31 | ],
32 | translate: { z: 40 },
33 | color: orange,
34 | stroke: 12,
35 | fill: true,
36 | });
37 |
38 | });
39 |
--------------------------------------------------------------------------------
/demos/api-demos/dragger-rotate-sync.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.draggerRotateSync = function( canvas ) {
2 |
3 | var isAnimating = false;
4 |
5 | var illo = new Zdog.Illustration({
6 | element: canvas,
7 | });
8 |
9 | // circle
10 | var circle = new Zdog.Ellipse({
11 | addTo: illo,
12 | diameter: 70,
13 | translate: { x: -50 },
14 | stroke: 20,
15 | color: eggplant,
16 | });
17 |
18 | // triangle
19 | var triangle = new Zdog.Shape({
20 | addTo: illo,
21 | path: [
22 | { x: 0, y: -32 },
23 | { x: 32, y: 32 },
24 | { x: -32, y: 32 },
25 | ],
26 | translate: { x: 50 },
27 | color: orange,
28 | stroke: 12,
29 | fill: true,
30 | });
31 |
32 | var viewRotation = new Zdog.Vector();
33 | var dragStartRX, dragStartRY;
34 |
35 | new Zdog.Dragger({
36 | startElement: canvas,
37 | onDragStart: function() {
38 | circle.color = garnet;
39 | triangle.color = gold;
40 | dragStartRX = viewRotation.x;
41 | dragStartRY = viewRotation.y;
42 | isAnimating = true;
43 | animate();
44 | },
45 | onDragMove: function( pointer, moveX, moveY ) {
46 | var moveRX = moveY / illo.width * TAU;
47 | var moveRY = moveX / illo.width * TAU;
48 | viewRotation.x = dragStartRX - moveRX;
49 | viewRotation.y = dragStartRY - moveRY;
50 | },
51 | onDragEnd: function() {
52 | circle.color = eggplant;
53 | triangle.color = orange;
54 | isAnimating = false;
55 | },
56 | });
57 |
58 | function animate() {
59 | circle.rotate.set( viewRotation );
60 | triangle.rotate.set( viewRotation );
61 | illo.updateRenderGraph();
62 | if ( isAnimating ) {
63 | requestAnimationFrame( animate );
64 | }
65 | }
66 |
67 | animate();
68 |
69 | };
70 |
--------------------------------------------------------------------------------
/demos/api-demos/illo-drag-rotate-item.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.illoDragRotateItem = function( canvas ) {
2 |
3 | var isAnimating = false;
4 |
5 | var triangle = new Zdog.Shape({
6 | path: [
7 | { x: 0, y: -32 },
8 | { x: 32, y: 32 },
9 | { x: -32, y: 32 },
10 | ],
11 | translate: { z: 40 },
12 | // rotate: { y: TAU/4 },
13 | color: orange,
14 | stroke: 12,
15 | fill: true,
16 | });
17 |
18 | var illo = new Zdog.Illustration({
19 | element: canvas,
20 | dragRotate: triangle,
21 | onDragStart: function() {
22 | isAnimating = true;
23 | animate();
24 | },
25 | onDragEnd: function() {
26 | isAnimating = false;
27 | },
28 | });
29 |
30 | illo.addChild( triangle );
31 |
32 | // circle
33 | new Zdog.Ellipse({
34 | addTo: illo,
35 | diameter: 80,
36 | translate: { z: -40 },
37 | stroke: 20,
38 | color: eggplant,
39 | });
40 |
41 | function animate() {
42 | illo.updateRenderGraph();
43 | if ( isAnimating ) {
44 | requestAnimationFrame( animate );
45 | }
46 | }
47 |
48 | animate();
49 |
50 | };
51 |
--------------------------------------------------------------------------------
/demos/api-demos/illo-element.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.illoElement = ZdogDocs.shapeDemo( function( elem, data, illo ) {
2 |
3 | if ( data.options ) {
4 | data.options = JSON.parse( data.options );
5 | illo.setOptions( data.options );
6 | }
7 |
8 | // circle
9 | new Zdog.Ellipse({
10 | addTo: illo,
11 | diameter: 80,
12 | translate: { z: -40 },
13 | stroke: 20,
14 | color: eggplant,
15 | });
16 |
17 | // triangle
18 | new Zdog.Shape({
19 | addTo: illo,
20 | path: [
21 | { x: 0, y: -32 },
22 | { x: 32, y: 32 },
23 | { x: -32, y: 32 },
24 | ],
25 | translate: { z: 40 },
26 | color: orange,
27 | stroke: 12,
28 | fill: true,
29 | });
30 |
31 | });
32 |
--------------------------------------------------------------------------------
/demos/api-demos/illo-on-prerender.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.illoOnPrerender = function( elem ) {
2 |
3 | var isAnimating = false;
4 |
5 | var illo = new Zdog.Illustration({
6 | element: elem,
7 | dragRotate: true,
8 | onDragStart: function() {
9 | isAnimating = true;
10 | animate();
11 | },
12 | onDragEnd: function() {
13 | isAnimating = false;
14 | },
15 | onPrerender: function( ctx ) {
16 | ctx.fillStyle = gold;
17 | ctx.fillRect( -1, -120, 2, 240 );
18 | ctx.fillRect( -120, -1, 240, 2 );
19 | },
20 | });
21 |
22 | // triangle
23 | new Zdog.Shape({
24 | addTo: illo,
25 | path: [
26 | { x: 0, y: -32 },
27 | { x: 32, y: 32 },
28 | { x: -32, y: 32 },
29 | ],
30 | translate: { z: 40 },
31 | color: orange,
32 | stroke: 12,
33 | fill: true,
34 | });
35 |
36 | // circle
37 | new Zdog.Ellipse({
38 | addTo: illo,
39 | diameter: 80,
40 | translate: { z: -40 },
41 | stroke: 20,
42 | color: eggplant,
43 | });
44 |
45 | function animate() {
46 | illo.updateRenderGraph();
47 | if ( isAnimating ) {
48 | requestAnimationFrame( animate );
49 | }
50 | }
51 |
52 | animate();
53 |
54 | };
55 |
--------------------------------------------------------------------------------
/demos/api-demos/illo-resize.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.illoResize = function( elem, data ) {
2 |
3 | var isAnimating = false;
4 |
5 | var illo = new Zdog.Illustration({
6 | element: elem,
7 | zoom: 1.5,
8 | resize: true,
9 | dragRotate: true,
10 | onDragStart: function() {
11 | isAnimating = true;
12 | animate();
13 | },
14 | onDragEnd: function() {
15 | isAnimating = false;
16 | },
17 | onResize: function( width ) {
18 | if ( data.onresize ) {
19 | this.zoom = width / 400;
20 | }
21 | // render on resize because may not be animating
22 | if ( this.isCanvas && this.children.length ) {
23 | this.updateRenderGraph();
24 | }
25 | },
26 | });
27 |
28 | // triangle
29 | new Zdog.Shape({
30 | addTo: illo,
31 | path: [
32 | { x: 0, y: -32 },
33 | { x: 32, y: 32 },
34 | { x: -32, y: 32 },
35 | ],
36 | translate: { z: 40 },
37 | // rotate: { y: TAU/4 },
38 | color: orange,
39 | stroke: 12,
40 | fill: true,
41 | });
42 |
43 | // circle
44 | new Zdog.Ellipse({
45 | addTo: illo,
46 | diameter: 80,
47 | translate: { z: -40 },
48 | stroke: 20,
49 | color: eggplant,
50 | });
51 |
52 | function animate() {
53 | illo.updateRenderGraph();
54 | if ( isAnimating ) {
55 | requestAnimationFrame( animate );
56 | }
57 | }
58 |
59 | animate();
60 |
61 | };
62 |
--------------------------------------------------------------------------------
/demos/api-demos/path-arc.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.pathArc = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | function graphArc( start, corner, end ) {
4 | // arc
5 | new Zdog.Shape({
6 | addTo: illo,
7 | path: [
8 | start,
9 | { arc: [ corner, end ] },
10 | ],
11 | closed: false,
12 | stroke: 20,
13 | color: eggplant,
14 | });
15 | // corner dot
16 | new Zdog.Shape({
17 | addTo: illo,
18 | translate: corner,
19 | stroke: 12,
20 | color: orange,
21 | });
22 | // start line
23 | var line = new Zdog.Shape({
24 | addTo: illo,
25 | path: [ start, corner ],
26 | stroke: 2,
27 | color: orange,
28 | });
29 | // end line
30 | line.copy({
31 | path: [ corner, end ],
32 | });
33 | }
34 |
35 | graphArc(
36 | { x: -60, y: -60 },
37 | { x: 20, y: -60 },
38 | { x: 20, y: 20 }
39 | );
40 |
41 | graphArc(
42 | { x: 20, y: 20 },
43 | { x: 20, y: 60 },
44 | { x: 60, y: 60 }
45 | );
46 |
47 | });
48 |
--------------------------------------------------------------------------------
/demos/api-demos/path-bezier.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.pathBezier = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var start = { x: -60, y: -60 };
4 | var startControl = { x: 20, y: -60 };
5 | var endControl = { x: 20, y: 60 };
6 | var end = { x: 60, y: 60 };
7 |
8 | // curve
9 | new Zdog.Shape({
10 | addTo: illo,
11 | path: [
12 | start,
13 | { bezier: [ startControl, endControl, end ] },
14 | ],
15 | closed: false,
16 | stroke: 20,
17 | color: eggplant,
18 | });
19 |
20 | var controlDot = new Zdog.Shape({
21 | addTo: illo,
22 | translate: startControl,
23 | stroke: 12,
24 | color: orange,
25 | });
26 | controlDot.copy({
27 | translate: endControl,
28 | });
29 |
30 | var controlLine = new Zdog.Shape({
31 | addTo: illo,
32 | path: [ start, startControl ],
33 | stroke: 2,
34 | color: orange,
35 | });
36 | controlLine.copy({
37 | path: [ end, endControl ],
38 | });
39 |
40 | });
41 |
--------------------------------------------------------------------------------
/demos/api-demos/shape-backface.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.shapeBackface = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | illo.rotate.x = -TAU/16;
4 |
5 | var rotor = new Zdog.Anchor({
6 | addTo: illo,
7 | });
8 |
9 | new Zdog.Rect({
10 | addTo: rotor,
11 | width: 80,
12 | height: 60,
13 | translate: { z: 50 },
14 | stroke: 8,
15 | fill: true,
16 | color: gold,
17 | backface: data.backface,
18 | });
19 |
20 | rotor.copyGraph({
21 | rotate: { y: TAU * 1/4 },
22 | });
23 | rotor.copyGraph({
24 | rotate: { y: TAU * 2/4 },
25 | });
26 | rotor.copyGraph({
27 | rotate: { y: TAU * 3/4 },
28 | });
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/demos/api-demos/shape-option.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.shapeOption = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var options = {
4 | addTo: illo,
5 | path: [
6 | { x: 0, y: -50 },
7 | { x: 50, y: 50 },
8 | { x: -50, y: 50 },
9 | ],
10 | color: orange,
11 | stroke: 10,
12 | };
13 |
14 | if ( data.options ) {
15 | data.options = JSON.parse( data.options );
16 | Zdog.extend( options, data.options );
17 | }
18 |
19 | new Zdog.Shape( options );
20 |
21 | });
22 |
--------------------------------------------------------------------------------
/demos/api-demos/shape-update-path.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.shapeUpdatePath = function( elem ) {
2 | var isAnimating = false;
3 |
4 | var illo = new Zdog.Illustration({
5 | element: elem,
6 | });
7 |
8 | var triangle = new Zdog.Shape({
9 | addTo: illo,
10 | path: [
11 | { x: 0, y: -50 },
12 | { x: 50, y: 50 },
13 | { x: -50, y: 50 },
14 | ],
15 | color: orange,
16 | stroke: 10,
17 | fill: true,
18 | });
19 | // change position of first path point
20 | var trianglePoint = triangle.path[0];
21 | var dragStartX, dragStartY;
22 |
23 | new Zdog.Dragger({
24 | startElement: elem,
25 | onDragStart: function() {
26 | dragStartX = trianglePoint.x;
27 | dragStartY = trianglePoint.y;
28 | isAnimating = true;
29 | animate();
30 | },
31 | onDragMove: function( pointer, moveX, moveY ) {
32 | trianglePoint.x = dragStartX + moveX;
33 | trianglePoint.y = dragStartY + moveY;
34 | triangle.updatePath();
35 | },
36 | onDragEnd: function() {
37 | isAnimating = false;
38 | },
39 | });
40 |
41 | function animate() {
42 | illo.updateRenderGraph();
43 | if ( isAnimating ) {
44 | requestAnimationFrame( animate );
45 | }
46 | }
47 |
48 | animate();
49 | };
50 |
--------------------------------------------------------------------------------
/demos/api-demos/utils-ease-in-out.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.utilsEaseInOut = function( elem ) {
2 |
3 | // start animation if IntObs not supported
4 | var isAnimating = !ZdogDocs.supportsIntObs;
5 |
6 | // ----- Zdog ----- //
7 |
8 | var illo = new Zdog.Illustration({
9 | element: elem,
10 | });
11 |
12 | // triangle
13 | new Zdog.Shape({
14 | addTo: illo,
15 | path: [
16 | { x: 0, y: -32 },
17 | { x: 32, y: 32 },
18 | { x: -32, y: 32 },
19 | ],
20 | translate: { z: 40 },
21 | color: orange,
22 | stroke: 12,
23 | fill: true,
24 | });
25 |
26 | // circle
27 | new Zdog.Ellipse({
28 | addTo: illo,
29 | diameter: 80,
30 | translate: { z: -40 },
31 | stroke: 20,
32 | color: eggplant,
33 | });
34 |
35 | var ticker = 0;
36 | var cycleCount = 150;
37 |
38 | function animate() {
39 | var progress = ticker / cycleCount;
40 | // apply easing to rotation
41 | var tween = Zdog.easeInOut( progress % 1, 3 );
42 | illo.rotate.y = tween * Zdog.TAU;
43 | ticker++;
44 | illo.updateRenderGraph();
45 | if ( isAnimating ) {
46 | requestAnimationFrame( animate );
47 | }
48 | }
49 |
50 | animate();
51 |
52 | // ----- IntersectionObserver ----- //
53 |
54 | ZdogDocs.observeIntersect({
55 | element: elem,
56 | onIntersect: function( isIntersect ) {
57 | isAnimating = isIntersect;
58 | if ( isAnimating ) {
59 | animate();
60 | }
61 | }
62 | });
63 |
64 | };
65 |
--------------------------------------------------------------------------------
/demos/extras-demos/composite-scale-bug.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.compositeScaleBug = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | var anchor = new Zdog.Anchor({
4 | addTo: illo,
5 | scale: JSON.parse( data.scale ),
6 | });
7 |
8 | new Zdog.Hemisphere({
9 | addTo: anchor,
10 | diameter: 30,
11 | translate: { y: -35 },
12 | color: garnet,
13 | backface: gold,
14 | stroke: false,
15 | });
16 |
17 | new Zdog.Cylinder({
18 | addTo: anchor,
19 | diameter: 30,
20 | length: 30,
21 | color: gold,
22 | backface: orange,
23 | stroke: false,
24 | });
25 |
26 | new Zdog.Cone({
27 | addTo: anchor,
28 | diameter: 30,
29 | length: 30,
30 | translate: { y: 35 },
31 | color: eggplant,
32 | backface: garnet,
33 | stroke: false,
34 | });
35 |
36 | });
37 |
--------------------------------------------------------------------------------
/demos/extras-demos/kid-kit.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.kidKit = function( elem ) {
2 |
3 | var illoSize = 80;
4 | var containerSize = Math.min( elem.parentNode.offsetWidth,
5 | window.innerHeight - 100 );
6 | var zoom = ( containerSize * 2 / illoSize ) / 2;
7 | var isSpinning = true;
8 |
9 | elem.setAttribute( 'width', illoSize * zoom );
10 | elem.setAttribute( 'height', illoSize * zoom );
11 |
12 | var illo = new Zdog.Illustration({
13 | element: elem,
14 | zoom: zoom,
15 | dragRotate: true,
16 | onDragStart: function() {
17 | isSpinning = false;
18 | },
19 | });
20 |
21 | // body center
22 | new Zdog.Shape({
23 | path: [
24 | { x: -3, y: 10 },
25 | { x: 0, y: 14 },
26 | { x: 3, y: 10 },
27 | ],
28 | addTo: illo,
29 | color: offWhite,
30 | stroke: 13,
31 | });
32 |
33 | // head circle
34 | new Zdog.Shape({
35 | addTo: illo,
36 | translate: { y: -12 },
37 | color: gold,
38 | stroke: 32,
39 | });
40 |
41 | // nose
42 | var nose = new Zdog.Anchor({
43 | addTo: illo,
44 | translate: { y: -7, z: 17 },
45 | });
46 | new Zdog.Shape({
47 | path: [
48 | { x: -1 },
49 | { x: 1 },
50 | ],
51 | addTo: nose,
52 | color: eggplant,
53 | stroke: 3,
54 | });
55 | new Zdog.Shape({
56 | path: [
57 | { y: 0 },
58 | { y: 1 },
59 | ],
60 | addTo: nose,
61 | color: eggplant,
62 | stroke: 3,
63 | });
64 |
65 | // snout
66 | new Zdog.Shape({
67 | path: [
68 | { x: -2, y: -5, z: 11 },
69 | { x: 2, y: -5, z: 11 },
70 | { x: 2, y: -3, z: 7 },
71 | { x: -2, y: -3, z: 7 },
72 | ],
73 | addTo: illo,
74 | color: gold,
75 | stroke: 12,
76 | });
77 |
78 | // eyes
79 | var eye = new Zdog.Shape({
80 | path: [
81 | { y: -12 },
82 | { y: -9 },
83 | ],
84 | addTo: illo,
85 | translate: { x: -8, z: 11 },
86 | color: eggplant,
87 | stroke: 4,
88 | });
89 | eye.copy({
90 | translate: { x: 8, z: 11 },
91 | });
92 |
93 |
94 | // ears
95 | var frontEarZ = 4;
96 | var topEarY = -30;
97 | var earColor = gold;
98 |
99 | var earAnchor = new Zdog.Anchor({
100 | addTo: illo,
101 | translate: { y: topEarY, z: frontEarZ },
102 | });
103 |
104 | var earA = { x: 14, y: 12, z: -4 };
105 | var earB = { x: 14, y: 0, z: 0 };
106 | var earC = { x: 7, y: 11, z: -14 };
107 | var earD = { x: 10, y: 0, z: 0 };
108 | var earE = { x: 3, y: 5, z: 0 };
109 | // outer ear
110 | new Zdog.Shape({
111 | path: [ earA, earB, earC ],
112 | addTo: earAnchor,
113 | color: earColor,
114 | fill: true,
115 | stroke: 4,
116 | });
117 | new Zdog.Shape({
118 | path: [ earB, earC, earD ],
119 | addTo: earAnchor,
120 | color: earColor,
121 | fill: true,
122 | stroke: 4,
123 | });
124 | new Zdog.Shape({
125 | path: [ earC, earD, earE ],
126 | addTo: earAnchor,
127 | color: earColor,
128 | fill: true,
129 | stroke: 4,
130 | });
131 | // inner ear
132 | var innerEarXShift = 4;
133 | new Zdog.Shape({
134 | path: [
135 | { x: earA.x - innerEarXShift , y: earA.y-3 },
136 | { x: earD.x, y: earD.y+5 },
137 | { x: earE.x + innerEarXShift, y: earE.y+2 },
138 | ],
139 | addTo: earAnchor,
140 | color: offWhite,
141 | fill: true,
142 | stroke: 3,
143 | });
144 |
145 | earAnchor.copyGraph({
146 | scale: { x: -1 },
147 | });
148 |
149 |
150 | // whiskers
151 | var whisker = new Zdog.Shape({
152 | path: [
153 | { x: 10, y: -6 },
154 | { x: 10, y: -2 },
155 | { x: 17, y: -2 },
156 | ],
157 | addTo: illo,
158 | translate: { z: 6 },
159 | fill: true,
160 | color: gold,
161 | stroke: 3,
162 | });
163 | whisker.copy({
164 | translate: { y: -6, z: 6 },
165 | });
166 | whisker.copy({
167 | scale: { x: -1 },
168 | });
169 | whisker.copy({
170 | scale: { x: -1 },
171 | translate: { y: -6, z: 6 },
172 | });
173 |
174 | // arms
175 |
176 | var armAnchor = new Zdog.Anchor({
177 | addTo: illo,
178 | });
179 |
180 | // shoulder
181 | new Zdog.Shape({
182 | path: [
183 | { x: 11, y: 6, z: -2 },
184 | { x: 12, y: 9, z: -2.5 },
185 | ],
186 | addTo: armAnchor,
187 | closed: true,
188 | color: eggplant,
189 | stroke: 8,
190 | });
191 | // forearm
192 | new Zdog.Shape({
193 | path: [
194 | { x: 12, y: 12, z: -2.5 },
195 | { x: 12, y: 15, z: -2 },
196 | ],
197 | addTo: armAnchor,
198 | color: gold,
199 | stroke: 8,
200 | });
201 | // hand
202 | new Zdog.Shape({
203 | path: [ { x: 11, y: 18, z: -1} ],
204 | addTo: armAnchor,
205 | color: eggplant,
206 | stroke: 10,
207 | });
208 |
209 | armAnchor.copyGraph({
210 | scale: { x: -1 },
211 | });
212 |
213 | // legs
214 | var leg = new Zdog.Shape({
215 | path: [
216 | { y: 20 },
217 | { y: 27 },
218 | ],
219 | addTo: illo,
220 | translate: { x: -6 },
221 | color: eggplant,
222 | stroke: 8,
223 | });
224 | leg.copy({
225 | translate: { x: 6 },
226 | });
227 |
228 | var cloakX0 = 8;
229 | var cloakX1 = 5;
230 |
231 | var cloakY0 = 4;
232 | var cloakY1 = 6;
233 | var cloakY2 = 13;
234 | var cloakY3 = 21;
235 |
236 | var cloakZ0 = 0;
237 | var cloakZ1 = 6;
238 | var cloakZ2 = 8;
239 |
240 | var cloakSide = new Zdog.Anchor({
241 | addTo: illo,
242 | });
243 |
244 | // top straps
245 | var topCloakStrap = new Zdog.Shape({
246 | path: [
247 | { x: cloakX0, y: cloakY0, z: cloakZ0 },
248 | { x: cloakX0, y: cloakY1, z: cloakZ1 },
249 | { x: cloakX1, y: cloakY1, z: cloakZ1 },
250 | ],
251 | addTo: cloakSide,
252 | fill: true,
253 | color: garnet,
254 | stroke: 4,
255 | });
256 |
257 | topCloakStrap.copy({
258 | scale: { x: -1 },
259 | });
260 |
261 | var vNeckY = ( cloakY1+cloakY2 ) / 2;
262 | var vNeckZ = ( cloakZ2+cloakZ1 ) / 2;
263 | new Zdog.Shape({
264 | path: [
265 | { x: -cloakX0, y: cloakY1, z: cloakZ1 },
266 | { x: -cloakX1, y: cloakY1, z: cloakZ1 },
267 | { x: 0, y: vNeckY, z: vNeckZ },
268 | { x: cloakX1, y: cloakY1, z: cloakZ1 },
269 | { x: cloakX0, y: cloakY1, z: cloakZ1 },
270 | { x: cloakX0, y: cloakY2, z: cloakZ2 },
271 | { x: -cloakX0, y: cloakY2, z: cloakZ2 },
272 | ],
273 | addTo: cloakSide,
274 | fill: true,
275 | color: garnet,
276 | stroke: 4,
277 | });
278 | new Zdog.Shape({
279 | path: [
280 | { x: -cloakX0, y: cloakY2 },
281 | { x: cloakX0, y: cloakY2 },
282 | { x: cloakX0, y: cloakY3 },
283 | { x: -cloakX0, y: cloakY3 },
284 | ],
285 | addTo: cloakSide,
286 | translate: { z: cloakZ2 },
287 | fill: true,
288 | color: garnet,
289 | stroke: 4,
290 | });
291 |
292 | cloakSide.copyGraph({
293 | scale: { z: -1 },
294 | });
295 |
296 | var ticker = 0;
297 | var cycleCount = 180;
298 |
299 | function animate() {
300 | if ( isSpinning ) {
301 | var progress = ticker / cycleCount;
302 | illo.rotate.y = Zdog.easeInOut( progress % 1, 3 ) * TAU;
303 | ticker++;
304 | }
305 | illo.updateRenderGraph();
306 | requestAnimationFrame( animate );
307 | }
308 |
309 | animate();
310 |
311 | };
312 |
--------------------------------------------------------------------------------
/demos/extras-demos/one-pixel-gap-fix-zoom.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.onePixelGapFixZoom = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | illo.zoom = 4;
4 |
5 | new Zdog.Box({
6 | addTo: illo,
7 | width: 30,
8 | height: 25,
9 | depth: 20,
10 | rotate: { x: -Zdog.TAU/8, y: Zdog.TAU/8 },
11 | stroke: 1 / illo.zoom, // 1px stroke
12 | color: gold,
13 | rearFace: eggplant,
14 | leftFace: eggplant,
15 | bottomFace: eggplant,
16 | });
17 |
18 | });
19 |
--------------------------------------------------------------------------------
/demos/extras-demos/one-pixel-gap-fix.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.onePixelGapFix = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | new Zdog.Box({
4 | addTo: illo,
5 | width: 120,
6 | height: 100,
7 | depth: 80,
8 | rotate: { x: -Zdog.TAU/8, y: Zdog.TAU/8 },
9 | stroke: 1, // 1px stroke
10 | color: gold,
11 | rearFace: eggplant,
12 | leftFace: eggplant,
13 | bottomFace: eggplant,
14 | });
15 |
16 | });
17 |
--------------------------------------------------------------------------------
/demos/extras-demos/z-fight-dot-cracker.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.zFightDotCracker = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | illo.rotate.x = -TAU/16;
4 |
5 | new Zdog.Rect({
6 | addTo: illo,
7 | width: 120,
8 | height: 120,
9 | stroke: 16,
10 | fill: true,
11 | color: garnet,
12 | });
13 |
14 | [ false, true ].forEach( function( isFixed ) {
15 |
16 | var group = new Zdog.Group({
17 | addTo: illo,
18 | translate: { z: isFixed ? 25 : -25 },
19 | });
20 |
21 | var d = 45;
22 | var x = d * ( isFixed ? -1 : 1 );
23 | // dot
24 | new Zdog.Shape({
25 | addTo: group,
26 | stroke: 20,
27 | translate: { x: x, y: -d },
28 | color: isFixed ? gold : eggplant,
29 | });
30 |
31 | if ( isFixed ) {
32 | new Zdog.Shape({
33 | addTo: group,
34 | translate: { x: -x, y: d },
35 | });
36 | }
37 |
38 | });
39 |
40 | });
41 |
--------------------------------------------------------------------------------
/demos/extras-demos/z-fight-dot-sandwich.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.zFightDotSandwich = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | illo.rotate.x = -TAU/16;
4 |
5 | new Zdog.Rect({
6 | addTo: illo,
7 | width: 120,
8 | height: 120,
9 | stroke: 16,
10 | fill: true,
11 | color: garnet,
12 | });
13 |
14 | [ false, true ].forEach( function( isGroup ) {
15 |
16 | var SliceClass = isGroup ? Zdog.Group : Zdog.Anchor;
17 |
18 | var dotSlice = new SliceClass({
19 | addTo: illo,
20 | translate: { z: isGroup ? 25 : -25 },
21 | });
22 |
23 | var d = 45;
24 |
25 | var dot = new Zdog.Shape({
26 | addTo: dotSlice,
27 | stroke: 20,
28 | color: isGroup ? gold : eggplant,
29 | });
30 | dot.copy({ translate: { x: -d, y: -d } });
31 | dot.copy({ translate: { x: 0, y: -d } });
32 | dot.copy({ translate: { x: d, y: -d } });
33 | dot.copy({ translate: { x: -d, y: 0 } });
34 | dot.copy({ translate: { x: d, y: 0 } });
35 | dot.copy({ translate: { x: -d, y: d } });
36 | dot.copy({ translate: { x: 0, y: d } });
37 | dot.copy({ translate: { x: d, y: d } });
38 |
39 | });
40 |
41 | });
42 |
--------------------------------------------------------------------------------
/demos/extras-demos/z-fight-intro.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.zFightIntro = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 |
5 | illo.rotate.x = -TAU/16;
6 |
7 | var distance = step == 2 ? 80 / Math.sqrt(2) : 40;
8 |
9 | var dot = new Zdog.Shape({
10 | addTo: illo,
11 | translate: { y: -distance },
12 | stroke: 80,
13 | color: eggplant,
14 | });
15 | dot.copy({
16 | translate: { x: -distance },
17 | color: step == 3 ? eggplant : gold,
18 | });
19 | dot.copy({
20 | translate: { z: distance },
21 | color: step == 3 ? eggplant : garnet,
22 | });
23 | dot.copy({
24 | translate: { x: distance },
25 | color: step == 3 ? eggplant : orange,
26 | });
27 | dot.copy({
28 | translate: { z: -distance },
29 | color: step == 3 ? eggplant : garnet,
30 | });
31 | dot.copy({
32 | translate: { y: distance },
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/demos/modeling-demos/child-shapes.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.childShapes = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | // origin dot
4 | new Zdog.Shape({
5 | addTo: illo,
6 | stroke: 8,
7 | color: eggplant,
8 | });
9 |
10 | var step = parseInt( data.step ) || 0;
11 |
12 | var zCircle = new Zdog.Ellipse({
13 | addTo: illo,
14 | diameter: 20,
15 | quarters: 2,
16 | closed: true,
17 | translate: { z: 40 },
18 | rotate: step >= 3 ? { z: -TAU/8 } : null,
19 | scale: step >= 3 ? 1.5 : 1,
20 | stroke: 8,
21 | fill: true,
22 | color: eggplant,
23 | visible: step != 4,
24 | });
25 | // z line
26 | new Zdog.Shape({
27 | addTo: zCircle,
28 | path: [ {}, zCircle.translate.copy().multiply({ z: -1 }) ],
29 | scale: 1/zCircle.scale.z,
30 | stroke: 2,
31 | color: zCircle.color,
32 | });
33 |
34 | var xRect = new Zdog.Rect({
35 | addTo: step >= 2 ? zCircle : illo,
36 | width: 20,
37 | height: 20,
38 | translate: { x: 40 },
39 | rotate: step >= 3 ? { x: TAU/8 } : null,
40 | stroke: 8,
41 | fill: true,
42 | color: garnet,
43 | visible: step != 4,
44 | });
45 | // x line
46 | new Zdog.Shape({
47 | addTo: xRect,
48 | path: [ {}, xRect.translate.copy().multiply({ x: -1 }) ],
49 | stroke: 2,
50 | color: xRect.color,
51 | });
52 |
53 | var yTri = new Zdog.Polygon({
54 | addTo: step >= 2 ? xRect : illo,
55 | radius: 10,
56 | sides: 3,
57 | translate: { y: -60 },
58 | stroke: 8,
59 | fill: true,
60 | color: orange,
61 | });
62 | // y line
63 | new Zdog.Shape({
64 | addTo: yTri,
65 | path: [ {}, yTri.translate.copy().multiply({ y: -1 }) ],
66 | stroke: 2,
67 | color: yTri.color,
68 | });
69 |
70 | });
71 |
--------------------------------------------------------------------------------
/demos/modeling-demos/group-eye.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.groupEye = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var eyeGroup = new Zdog.Group({
4 | addTo: illo,
5 | translate: { z: 20 },
6 | });
7 |
8 | // eye white
9 | new Zdog.Ellipse({
10 | addTo: eyeGroup,
11 | width: 160,
12 | height: 80,
13 | stroke: 8,
14 | fill: true,
15 | color: 'white',
16 | });
17 |
18 | var iris = new Zdog.Ellipse({
19 | addTo: eyeGroup,
20 | diameter: 70,
21 | stroke: 8,
22 | fill: true,
23 | color: gold,
24 | });
25 | // pupil
26 | iris.copy({
27 | diameter: 40,
28 | color: eggplant,
29 | });
30 | // highlight
31 | iris.copy({
32 | diameter: 30,
33 | translate: { x: 15, y: -15 },
34 | color: 'white',
35 | });
36 |
37 | });
38 |
--------------------------------------------------------------------------------
/demos/modeling-demos/group-wall.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.groupWall = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var wallGroup = new Zdog.Group({
4 | addTo: illo,
5 | });
6 |
7 | // wall
8 | var wall = new Zdog.Rect({
9 | addTo: wallGroup,
10 | width: 140,
11 | height: 100,
12 | stroke: 8,
13 | fill: true,
14 | color: orange,
15 | });
16 |
17 | // door
18 | wall.copy({
19 | width: 30,
20 | height: 65,
21 | translate: { x: -30, y: 17.5 },
22 | color: garnet,
23 | });
24 |
25 | // window
26 | new Zdog.Ellipse({
27 | addTo: wallGroup,
28 | diameter: 30,
29 | translate: { x: 30 },
30 | stroke: wall.stroke,
31 | fill: true,
32 | color: eggplant,
33 | });
34 |
35 | });
36 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-arms.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelArms = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 | illo.zoom = 5;
5 |
6 | // ----- model ----- //
7 |
8 | var hipX = 3;
9 | // hips
10 | var hips = new Zdog.Shape({
11 | addTo: illo,
12 | path: [ { x: -hipX }, { x: hipX } ],
13 | // translate: { y: 2 },
14 | stroke: 4,
15 | color: eggplant,
16 | });
17 |
18 | // ----- legs ----- //
19 |
20 | var leg = new Zdog.Shape({
21 | addTo: hips,
22 | path: [ { y: 0 }, { y: 12 } ],
23 | translate: { x: -hipX },
24 | // rotate: { x: TAU/4 },
25 | color: eggplant,
26 | stroke: 4,
27 | });
28 |
29 | // foot
30 | new Zdog.RoundedRect({
31 | addTo: leg,
32 | width: 2,
33 | height: 4,
34 | cornerRadius: 1,
35 | translate: { y: 14, z: 2 },
36 | rotate: { x: TAU/4 },
37 | color: garnet,
38 | fill: true,
39 | stroke: 4,
40 | });
41 |
42 | leg.copyGraph({
43 | translate: { x: hipX },
44 | });
45 |
46 | // ----- upper body ----- //
47 |
48 | var chest = new Zdog.Shape({
49 | addTo: hips,
50 | path: [ { x: -1.5 }, { x: 1.5 } ],
51 | translate: { y: -6.5 },
52 | stroke: 9,
53 | color: garnet,
54 | });
55 |
56 | var head = new Zdog.Shape({
57 | addTo: chest,
58 | stroke: 12,
59 | translate: { y: -9.5 },
60 | color: gold,
61 | });
62 |
63 | var eye = new Zdog.Ellipse({
64 | addTo: head,
65 | diameter: 2,
66 | quarters: 2,
67 | translate: { x: -2, y: 1, z: 4.5 },
68 | rotate: { z: -TAU/4 },
69 | color: eggplant,
70 | stroke: 0.5,
71 | backface: false,
72 | });
73 | eye.copy({
74 | translate: { x: 2, y: 1, z: 4.5 },
75 | });
76 | // smile
77 | new Zdog.Ellipse({
78 | addTo: head,
79 | diameter: 3,
80 | quarters: 2,
81 | translate: { y: 2.5, z: 4.5 },
82 | rotate: { z: TAU/4 },
83 | closed: true,
84 | color: '#FED',
85 | stroke: 0.5,
86 | fill: true,
87 | backface: false,
88 | });
89 |
90 | // ----- arms ----- //
91 |
92 | var armSize = 6;
93 |
94 | // right arm
95 | var upperArm = new Zdog.Shape({
96 | addTo: chest,
97 | path: [ { y: 0 }, { y: armSize } ],
98 | translate: { x: -5, y: -2 },
99 | color: eggplant,
100 | stroke: 4,
101 | });
102 |
103 | var forearm;
104 | if ( step >= 2 ) {
105 | forearm = new Zdog.Shape({
106 | addTo: upperArm,
107 | path: [ { y: 0 }, { y: armSize } ],
108 | translate: { y: armSize },
109 | color: gold,
110 | stroke: 4,
111 | });
112 | }
113 |
114 | // hand
115 | if ( step >= 3 ) {
116 | new Zdog.Shape({
117 | addTo: forearm,
118 | translate: { z: 1, y: armSize },
119 | stroke: 6,
120 | color: gold,
121 | });
122 | }
123 |
124 | // left arm
125 | if ( step >= 4 ) {
126 | upperArm.copyGraph({
127 | translate: { x: 5, y: -2 },
128 | });
129 | }
130 |
131 | });
132 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-body-core.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelBodyCore = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 | illo.zoom = 5;
5 |
6 | if ( step == 4 ) {
7 | illo.rotate.y = -TAU/8;
8 | }
9 |
10 | // ----- model ----- //
11 |
12 | var hipX = 3;
13 | // hips
14 | var hips = new Zdog.Shape({
15 | addTo: illo,
16 | path: [ { x: -hipX }, { x: hipX } ],
17 | // translate: { y: 2 },
18 | rotate: step == 4 ? { x: TAU/8 } : null,
19 | color: eggplant,
20 | stroke: 4,
21 | });
22 |
23 | var chest;
24 | if ( step >= 2 ) {
25 | chest = new Zdog.Shape({
26 | addTo: hips,
27 | path: [ { x: -1.5 }, { x: 1.5 } ],
28 | // position right above hips
29 | // ( hips.stroke + chest.stroke ) / 2
30 | translate: { y: -6.5 },
31 | stroke: 9,
32 | color: garnet,
33 | });
34 | }
35 |
36 | if ( step >= 3 ) {
37 | var head = new Zdog.Shape({
38 | addTo: chest,
39 | stroke: 12,
40 | // position above chest
41 | translate: { y: -9.5 },
42 | color: gold,
43 | });
44 |
45 | var eye = new Zdog.Ellipse({
46 | addTo: head,
47 | diameter: 2,
48 | quarters: 2,
49 | translate: { x: -2, y: 1, z: 4.5 },
50 | rotate: { z: -TAU/4 },
51 | color: eggplant,
52 | stroke: 0.5,
53 | backface: false,
54 | });
55 | eye.copy({
56 | translate: { x: 2, y: 1, z: 4.5 },
57 | });
58 | // smile
59 | new Zdog.Ellipse({
60 | addTo: head,
61 | diameter: 3,
62 | quarters: 2,
63 | translate: { y: 2.5, z: 4.5 },
64 | rotate: { z: TAU/4 },
65 | closed: true,
66 | color: '#FED',
67 | stroke: 0.5,
68 | fill: true,
69 | backface: false,
70 | });
71 | }
72 |
73 |
74 | });
75 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-head.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelHead = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step || 0 );
4 | illo.zoom = 10;
5 |
6 | // -- model --- //
7 |
8 | var head = new Zdog.Shape({
9 | addTo: illo,
10 | stroke: 12,
11 | color: gold,
12 | });
13 |
14 | var eye;
15 |
16 | if ( step > 1 ) {
17 | eye = new Zdog.Ellipse({
18 | addTo: head,
19 | diameter: 2,
20 | quarters: 2,
21 | translate: { x: -2, y: 1, z: 4.5 },
22 | rotate: { z: -TAU/4 },
23 | color: eggplant,
24 | stroke: 0.5,
25 | backface: false,
26 | });
27 | }
28 |
29 | if ( step > 2 ) {
30 | eye.copy({
31 | translate: { x: 2, y: 1, z: 4.5 },
32 | });
33 | }
34 |
35 | if ( step > 3 ) {
36 | // smile
37 | new Zdog.Ellipse({
38 | addTo: head,
39 | diameter: 3,
40 | quarters: 2,
41 | translate: { y: 2.5, z: 4.5 },
42 | rotate: { z: TAU/4 },
43 | closed: true,
44 | color: '#FED',
45 | stroke: 0.5,
46 | fill: true,
47 | backface: false,
48 | });
49 | }
50 |
51 | });
52 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-legs.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelLegs = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 | illo.zoom = 5;
5 |
6 | // ----- model ----- //
7 |
8 | var hipX = 3;
9 | // hips
10 | var hips = new Zdog.Shape({
11 | addTo: illo,
12 | path: [ { x: -hipX }, { x: hipX } ],
13 | // translate: { y: 2 },
14 | stroke: 4,
15 | color: eggplant,
16 | });
17 |
18 | // ----- legs ----- //
19 |
20 | var leg = new Zdog.Shape({
21 | addTo: hips,
22 | path: [ { y: 0 }, { y: 12 } ],
23 | translate: { x: -hipX },
24 | // rotate: { x: TAU/4 },
25 | color: eggplant,
26 | stroke: 4,
27 | });
28 |
29 | // foot
30 | if ( step >= 2 ) {
31 | new Zdog.RoundedRect({
32 | addTo: leg,
33 | width: 2,
34 | height: 4,
35 | cornerRadius: 1,
36 | translate: { y: 14, z: 2 },
37 | rotate: step >= 3 ? { x: TAU/4 } : null,
38 | color: garnet,
39 | fill: true,
40 | stroke: 4,
41 | });
42 | }
43 |
44 | if ( step >= 4 ) {
45 | leg.copyGraph({
46 | translate: { x: hipX },
47 | });
48 | }
49 |
50 | // ----- upper body ----- //
51 |
52 | var chest = new Zdog.Shape({
53 | addTo: hips,
54 | path: [ { x: -1.5 }, { x: 1.5 } ],
55 | translate: { y: -6.5 },
56 | stroke: 9,
57 | color: garnet,
58 | });
59 |
60 | var head = new Zdog.Shape({
61 | addTo: chest,
62 | stroke: 12,
63 | translate: { y: -9.5 },
64 | color: gold,
65 | });
66 |
67 | var eye = new Zdog.Ellipse({
68 | addTo: head,
69 | diameter: 2,
70 | quarters: 2,
71 | translate: { x: -2, y: 1, z: 4.5 },
72 | rotate: { z: -TAU/4 },
73 | color: eggplant,
74 | stroke: 0.5,
75 | backface: false,
76 | });
77 | eye.copy({
78 | translate: { x: 2, y: 1, z: 4.5 },
79 | });
80 | // smile
81 | new Zdog.Ellipse({
82 | addTo: head,
83 | diameter: 3,
84 | quarters: 2,
85 | translate: { y: 2.5, z: 4.5 },
86 | rotate: { z: TAU/4 },
87 | closed: true,
88 | color: '#FED',
89 | stroke: 0.5,
90 | fill: true,
91 | backface: false,
92 | });
93 |
94 | });
95 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-rotate-legs.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelRotateLegs = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 | illo.zoom = 5;
5 | illo.rotate.y = -TAU/8;
6 |
7 | // ----- model ----- //
8 |
9 | var hipX = 3;
10 | // hips
11 | var hips = new Zdog.Shape({
12 | addTo: illo,
13 | path: [ { x: -hipX }, { x: hipX } ],
14 | translate: { y: 2 },
15 | stroke: 4,
16 | color: eggplant,
17 | });
18 |
19 | // ----- legs ----- //
20 |
21 | var leg = new Zdog.Shape({
22 | addTo: hips,
23 | path: [ { y: 0 }, { y: 12 } ],
24 | translate: { x: -hipX },
25 | rotate: step >= 2 ? { x: TAU/4 } : null,
26 | color: eggplant,
27 | stroke: 4,
28 | });
29 |
30 | // foot
31 | var foot = new Zdog.RoundedRect({
32 | addTo: leg,
33 | width: 2,
34 | height: 4,
35 | cornerRadius: 1,
36 | translate: { y: 14, z: 2 },
37 | rotate: { x: TAU/4 },
38 | color: garnet,
39 | fill: true,
40 | stroke: 4,
41 | });
42 |
43 | var standLeg = leg.copy({
44 | translate: { x: hipX },
45 | rotate: step >= 3 ? { x: -TAU/8 } : null,
46 | });
47 |
48 | foot.copy({
49 | addTo: standLeg,
50 | rotate: step >= 4 ? { x: -TAU/8 } : foot.rotate,
51 | });
52 |
53 | // ----- upper body ----- //
54 |
55 | var chest = new Zdog.Shape({
56 | addTo: hips,
57 | path: [ { x: -1.5 }, { x: 1.5 } ],
58 | translate: { y: -6.5 },
59 | stroke: 9,
60 | color: garnet,
61 | });
62 |
63 | var head = new Zdog.Shape({
64 | addTo: chest,
65 | stroke: 12,
66 | translate: { y: -9.5 },
67 | color: gold,
68 | });
69 |
70 | var eye = new Zdog.Ellipse({
71 | addTo: head,
72 | diameter: 2,
73 | quarters: 2,
74 | translate: { x: -2, y: 1, z: 4.5 },
75 | rotate: { z: -TAU/4 },
76 | color: eggplant,
77 | stroke: 0.5,
78 | backface: false,
79 | });
80 | eye.copy({
81 | translate: { x: 2, y: 1, z: 4.5 },
82 | });
83 | // smile
84 | new Zdog.Ellipse({
85 | addTo: head,
86 | diameter: 3,
87 | quarters: 2,
88 | translate: { y: 2.5, z: 4.5 },
89 | rotate: { z: TAU/4 },
90 | closed: true,
91 | color: '#FED',
92 | stroke: 0.5,
93 | fill: true,
94 | backface: false,
95 | });
96 |
97 | // ----- arms ----- //
98 |
99 | var armSize = 6;
100 |
101 | // right arm
102 | var upperArm = new Zdog.Shape({
103 | addTo: chest,
104 | path: [ { y: 0 }, { y: armSize } ],
105 | translate: { x: -5, y: -2 },
106 | color: eggplant,
107 | stroke: 4,
108 | });
109 |
110 | var forearm = new Zdog.Shape({
111 | addTo: upperArm,
112 | path: [ { y: 0 }, { y: armSize } ],
113 | translate: { y: armSize },
114 | color: gold,
115 | stroke: 4,
116 | });
117 |
118 | // hand
119 | new Zdog.Shape({
120 | addTo: forearm,
121 | translate: { z: 1, y: armSize },
122 | stroke: 6,
123 | color: gold,
124 | });
125 |
126 | // left arm
127 | upperArm.copyGraph({
128 | translate: { x: 5, y: -2 },
129 | });
130 |
131 | });
132 |
--------------------------------------------------------------------------------
/demos/modeling-demos/model-rotate-spine.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.modelRotateSpine = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | var step = parseInt( data.step );
4 | illo.zoom = 5;
5 | illo.rotate.y = -TAU/8;
6 |
7 | // ----- model ----- //
8 |
9 | var hipX = 3;
10 | // hips
11 | var hips = new Zdog.Shape({
12 | addTo: illo,
13 | path: [ { x: -hipX }, { x: hipX } ],
14 | translate: { y: 2 },
15 | rotate: step == 1 ? { x: TAU/8 } : null,
16 | stroke: 4,
17 | color: eggplant,
18 | });
19 |
20 | // ----- legs ----- //
21 |
22 | var leg = new Zdog.Shape({
23 | addTo: hips,
24 | path: [ { y: 0 }, { y: 12 } ],
25 | translate: { x: -hipX },
26 | rotate: { x: TAU/4 },
27 | color: eggplant,
28 | stroke: 4,
29 | });
30 |
31 | // foot
32 | var foot = new Zdog.RoundedRect({
33 | addTo: leg,
34 | width: 2,
35 | height: 4,
36 | cornerRadius: 1,
37 | translate: { y: 14, z: 2 },
38 | rotate: { x: TAU/4 },
39 | color: garnet,
40 | fill: true,
41 | stroke: 4,
42 | });
43 |
44 | var standLeg = leg.copy({
45 | translate: { x: hipX },
46 | rotate: { x: -TAU/8 },
47 | });
48 |
49 | foot.copy({
50 | addTo: standLeg,
51 | rotate: { x: -TAU/8 },
52 | });
53 |
54 | // ----- upper body ----- //
55 |
56 | var spine = new Zdog.Anchor({
57 | addTo: hips,
58 | rotate: { x: TAU/8 },
59 | });
60 |
61 | var chest = new Zdog.Shape({
62 | addTo: step >= 2 ? spine : hips,
63 | path: [ { x: -1.5 }, { x: 1.5 } ],
64 | translate: { y: -6.5 },
65 | stroke: 9,
66 | color: garnet,
67 | });
68 |
69 | var head = new Zdog.Shape({
70 | addTo: chest,
71 | stroke: 12,
72 | translate: { y: -9.5 },
73 | color: gold,
74 | });
75 |
76 | var eye = new Zdog.Ellipse({
77 | addTo: head,
78 | diameter: 2,
79 | quarters: 2,
80 | translate: { x: -2, y: 1, z: 4.5 },
81 | rotate: { z: -TAU/4 },
82 | color: eggplant,
83 | stroke: 0.5,
84 | backface: false,
85 | });
86 | eye.copy({
87 | translate: { x: 2, y: 1, z: 4.5 },
88 | });
89 | // smile
90 | new Zdog.Ellipse({
91 | addTo: head,
92 | diameter: 3,
93 | quarters: 2,
94 | translate: { y: 2.5, z: 4.5 },
95 | rotate: { z: TAU/4 },
96 | closed: true,
97 | color: '#FED',
98 | stroke: 0.5,
99 | fill: true,
100 | backface: false,
101 | });
102 |
103 | // ----- arms ----- //
104 |
105 | var armSize = 6;
106 |
107 | // arm on left
108 | var upperArm = new Zdog.Shape({
109 | addTo: chest,
110 | path: [ { y: 0 }, { y: armSize } ],
111 | translate: { x: -5, y: -2 },
112 | rotate: step >= 3 ? { x: -TAU/4 } : null,
113 | color: eggplant,
114 | stroke: 4,
115 | });
116 |
117 | var forearm = new Zdog.Shape({
118 | addTo: upperArm,
119 | path: [ { y: 0 }, { y: armSize } ],
120 | translate: { y: armSize },
121 | rotate: step >= 4 ? { x: TAU/8 } : null,
122 | color: gold,
123 | stroke: 4,
124 | });
125 |
126 | // hand
127 | new Zdog.Shape({
128 | addTo: forearm,
129 | translate: { z: 1, y: armSize },
130 | stroke: 6,
131 | color: gold,
132 | });
133 |
134 | // arm on right
135 | upperArm.copyGraph({
136 | translate: { x: 5, y: -2 },
137 | rotate: step >= 3 ? { x: TAU/4 } : null,
138 | });
139 |
140 | });
141 |
--------------------------------------------------------------------------------
/demos/modeling-demos/tasty-burger.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.tastyBurger = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | illo.rotate.x = -TAU/8;
4 |
5 | var burger = new Zdog.Anchor({
6 | addTo: illo,
7 | translate: { y: 24 },
8 | rotate: { x: TAU/4 },
9 | });
10 |
11 | // top bun
12 | var topBun = new Zdog.Hemisphere({
13 | addTo: burger,
14 | diameter: 96,
15 | translate: { z: 44 },
16 | stroke: 24,
17 | color: orange,
18 | // backface: gold,
19 | });
20 |
21 | // cheese
22 | new Zdog.Rect({
23 | addTo: burger,
24 | width: 92,
25 | height: 92,
26 | translate: { z: 24 },
27 | stroke: 16,
28 | color: yellow,
29 | fill: true,
30 | });
31 |
32 | // patty
33 | new Zdog.Ellipse({
34 | addTo: burger,
35 | diameter: 96,
36 | stroke: 32,
37 | color: garnet,
38 | fill: true,
39 | });
40 |
41 | // bottom bun
42 | new Zdog.Cylinder({
43 | addTo: burger,
44 | diameter: topBun.diameter,
45 | length: 16,
46 | translate: { z: -36 },
47 | stroke: topBun.stroke,
48 | color: topBun.color,
49 | });
50 |
51 | var seedAnchor = new Zdog.Anchor({
52 | addTo: topBun,
53 | });
54 |
55 | var seedZ = ( topBun.diameter + topBun.stroke ) / 2 + 1;
56 | // seed
57 | new Zdog.Shape({
58 | addTo: seedAnchor,
59 | path: [ { y: -3 }, { y: 3 } ],
60 | translate: { z: seedZ },
61 | stroke: 8,
62 | color: gold,
63 | });
64 |
65 | seedAnchor.copyGraph({
66 | rotate: { x: 0.6 },
67 | });
68 | seedAnchor.copyGraph({
69 | rotate: { x: -0.6 },
70 | });
71 | seedAnchor.copyGraph({
72 | rotate: { y: -0.5 },
73 | });
74 | seedAnchor.copyGraph({
75 | rotate: { y: 0.5 },
76 | });
77 |
78 | });
79 |
--------------------------------------------------------------------------------
/demos/starter-demos/starter-drag-rotate-spin.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.starterDragRotateSpin = ZdogDocs.spinDemo( function( canvas, data, illo ) {
2 |
3 | illo.zoom = 4;
4 |
5 | // circle
6 | new Zdog.Ellipse({
7 | addTo: illo,
8 | diameter: 20,
9 | translate: { z: 10 },
10 | stroke: 5,
11 | color: '#636',
12 | });
13 |
14 | // square
15 | new Zdog.Rect({
16 | addTo: illo,
17 | width: 20,
18 | height: 20,
19 | translate: { z: -10 },
20 | stroke: 3,
21 | color: '#E62',
22 | fill: true,
23 | });
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/demos/starter-demos/starter-drag-rotate.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.starterDragRotate = ZdogDocs.shapeDemo( function( canvas, data, illo ) {
2 |
3 | illo.zoom = 4;
4 |
5 | // circle
6 | new Zdog.Ellipse({
7 | addTo: illo,
8 | diameter: 20,
9 | translate: { z: 10 },
10 | stroke: 5,
11 | color: '#636',
12 | });
13 |
14 | // square
15 | new Zdog.Rect({
16 | addTo: illo,
17 | width: 20,
18 | height: 20,
19 | translate: { z: -10 },
20 | stroke: 3,
21 | color: '#E62',
22 | fill: true,
23 | });
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/demos/starter-demos/starter-initial.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.starterInitial = function( elem, data ) {
2 |
3 | var illo = new Zdog.Illustration({
4 | element: elem,
5 | });
6 |
7 | // circle
8 | new Zdog.Ellipse({
9 | addTo: illo,
10 | diameter: 80,
11 | stroke: 20,
12 | color: '#636',
13 | });
14 |
15 | var isSpinning = data.spin;
16 |
17 | function animate() {
18 | illo.updateRenderGraph();
19 | if ( isSpinning ) {
20 | requestAnimationFrame( animate );
21 | illo.rotate.y += 0.03;
22 | }
23 | }
24 | // start animation if no IntObs
25 | if ( !data.spin || !ZdogDocs.supportsIntObs ) {
26 | animate();
27 | }
28 |
29 | // ----- IntersectionObserver ----- //
30 |
31 | if ( data.spin ) {
32 |
33 | ZdogDocs.observeIntersect({
34 | element: elem,
35 | onIntersect: function( isIntersect ) {
36 | isSpinning = isIntersect;
37 | if ( isSpinning ) {
38 | animate();
39 | }
40 | }
41 | });
42 | }
43 |
44 | };
45 |
--------------------------------------------------------------------------------
/demos/starter-demos/starter-rect.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.starterRect = function( elem ) {
2 |
3 | var illo = new Zdog.Illustration({
4 | element: elem,
5 | });
6 |
7 | // circle
8 | new Zdog.Ellipse({
9 | addTo: illo,
10 | diameter: 80,
11 | translate: { z: 40 },
12 | stroke: 20,
13 | color: '#636',
14 | });
15 |
16 | // square
17 | new Zdog.Rect({
18 | addTo: illo,
19 | width: 80,
20 | height: 80,
21 | translate: { z: -40 },
22 | stroke: 12,
23 | color: '#E62',
24 | fill: true,
25 | });
26 |
27 | // ----- animate ----- //
28 |
29 | var isSpinning = true;
30 |
31 | function animate() {
32 | illo.rotate.y += 0.03;
33 | illo.updateRenderGraph();
34 | if ( isSpinning ) {
35 | requestAnimationFrame( animate );
36 | }
37 | }
38 | // start animation if no IntObs
39 | if ( !ZdogDocs.supportsIntObs ) {
40 | animate();
41 | }
42 |
43 | // ----- IntersectionObserver ----- //
44 |
45 | ZdogDocs.observeIntersect({
46 | element: elem,
47 | onIntersect: function( isIntersect ) {
48 | isSpinning = isIntersect;
49 | if ( isSpinning ) {
50 | animate();
51 | }
52 | }
53 | });
54 |
55 | };
56 |
--------------------------------------------------------------------------------
/demos/starter-demos/starter-zoom.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.starterZoom = function( elem ) {
2 |
3 | var illo = new Zdog.Illustration({
4 | element: elem,
5 | zoom: 4,
6 | });
7 |
8 | // circle
9 | new Zdog.Ellipse({
10 | addTo: illo,
11 | diameter: 20,
12 | translate: { z: 10 },
13 | stroke: 5,
14 | color: '#636',
15 | });
16 |
17 | // square
18 | new Zdog.Rect({
19 | addTo: illo,
20 | width: 20,
21 | height: 20,
22 | translate: { z: -10 },
23 | stroke: 3,
24 | color: '#E62',
25 | fill: true,
26 | });
27 |
28 | // ----- animate ----- //
29 |
30 | var isSpinning = true;
31 |
32 | function animate() {
33 | illo.rotate.y += 0.03;
34 | illo.updateRenderGraph();
35 | if ( isSpinning ) {
36 | requestAnimationFrame( animate );
37 | }
38 | }
39 |
40 | // start animation if no IntObs
41 | if ( !ZdogDocs.supportsIntObs ) {
42 | animate();
43 | }
44 |
45 | // ----- IntersectionObserver ----- //
46 |
47 | ZdogDocs.observeIntersect({
48 | element: elem,
49 | onIntersect: function( isIntersect ) {
50 | isSpinning = isIntersect;
51 | if ( isSpinning ) {
52 | animate();
53 | }
54 | }
55 | });
56 | };
57 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var version = require('./package.json').version;
3 |
4 | // ----- site ----- //
5 |
6 | // stuff used across tasks
7 | var site = {
8 | // templating data
9 | data: {
10 | version: version,
11 | description: 'Round, flat, designer-friendly pseudo-3D engine for canvas and SVG',
12 | dev: process.argv[2] == 'dev',
13 | },
14 | };
15 |
16 | // ----- tasks ----- //
17 |
18 | require('./tasks/assets')( site );
19 | require('./tasks/hint')( site );
20 | require('./tasks/js')( site );
21 | require('./tasks/css')( site );
22 | require('./tasks/content')( site );
23 |
24 | // ----- default ----- //
25 |
26 | gulp.task( 'default', gulp.parallel(
27 | 'hint',
28 | 'content',
29 | 'js',
30 | 'css',
31 | 'assets'
32 | ));
33 |
34 | // ----- watch ----- //
35 |
36 | gulp.task( 'dev', gulp.parallel(
37 | 'hint',
38 | 'assets',
39 | 'content'
40 | ));
41 |
--------------------------------------------------------------------------------
/modules/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "browser": true,
3 | "unused": true,
4 | "undef": true,
5 | "globals": {
6 | "offWhite": false,
7 | "yellow": false,
8 | "gold": false,
9 | "orange": false,
10 | "garnet": false,
11 | "eggplant": false,
12 | "TAU": false,
13 | "Zdog": false,
14 | "ZdogDocs": false
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/modules/container/container.css:
--------------------------------------------------------------------------------
1 | /* container
2 | ------------------------- */
3 |
4 | .container {
5 | margin: 0 auto;
6 | padding: 0 10px;
7 | max-width: 1000px;
8 | }
9 |
10 | /* ---- .container__main ---- */
11 |
12 | .container__main > h1 {
13 | font-size: 4.0rem;
14 | line-height: 1.2;
15 | margin: 1.0rem 0;
16 | }
17 |
18 | .container__main > h2 {
19 | position: relative;
20 | font-size: 2.4rem;
21 | line-height: 1.2;
22 | padding-top: 1.5rem;
23 | }
24 |
25 | /* big divider */
26 | .container__big-divider,
27 | .container__main > h2 {
28 | margin: 3.0rem 0 2.0rem;
29 | }
30 |
31 | .container__big-divider,
32 | .container__main > h2::before {
33 | width: 100%;
34 | height: 8px;
35 | background: #FDB;
36 | border: none;
37 | border-radius: 4px;
38 | }
39 |
40 | .container__main > h2::before {
41 | content: '';
42 | display: block;
43 | position: absolute;
44 | top: 0;
45 | }
46 |
47 | .container__main > h3 {
48 | font-size: 1.4rem;
49 | padding-top: 1.2rem;
50 | border-top: 2px solid #FDB;
51 | margin: 3.0rem 0 1.0rem;
52 | }
53 |
54 | .container__main > h2:target,
55 | .container__main > h3:target {
56 | color: #C25;
57 | border-color: #C25;
58 | }
59 |
60 | .container__main > h2:target::before {
61 | background: #C25;
62 | }
63 |
64 |
65 | .container__main p a,
66 | .container__main ul a {
67 | border-bottom: 1px solid;
68 | }
69 |
70 | @media screen and ( min-width: 768px ) {
71 | .container {
72 | display: flex;
73 | }
74 |
75 | .container__sidebar {
76 | flex-basis: 180px;
77 | flex-shrink: 0;
78 | margin-right: 30px;
79 | }
80 |
81 | .container__main {
82 | flex-grow: 1;
83 | }
84 |
85 | }
86 |
--------------------------------------------------------------------------------
/modules/docs/api-anchor.hbs:
--------------------------------------------------------------------------------
1 | {{! --------------------------------------------- }}
2 |
3 |
Anchor
4 |
5 |
An item that can be added to another item, and have other items added to it.
6 |
7 |
Anchor
is the super class of all item and shape classes — Shape
, Group
, Illustration
, Rect
, Ellipse
, Box
, etc. All items that can be added to a Zdog scene act as Anchor
s. All item classes can use Anchor
properties and methods.
8 |
9 |
The Anchor
class itself is an invisible item. Anchors are useful for collecting related shapes and transforming them together.
10 |
11 | ``` js
12 | let anchor = new Zdog.Anchor({
13 | // options
14 | });
15 | ```
16 |
17 | {{! --------------------------------------------- }}
18 |
19 |
addTo
20 |
21 |
Adds item to parent item.
22 |
23 | ``` js
24 | addTo: illo
25 | ```
26 |
27 |
28 |
29 | ``` js
30 | // add anchor to illo
31 | let anchor = new Zdog.Anchor({
32 | addTo: illo,
33 | });
34 | // add triangle to anchor
35 | let triangle = new Zdog.Shape({
36 | addTo: anchor,
37 | translate: { z: 40 },
38 | // ..
39 | });
40 | // add circle to anchor
41 | let circle = new Zdog.Ellipse({
42 | addTo: anchor,
43 | translate: { z: -40 },
44 | // ..
45 | });
46 | ```
47 |
48 |
49 |
51 | {{> edit-demo penSlug="MdOPxQ"}}
52 |
53 |
54 |
55 |
56 | {{> child-shapes-add-to }}
57 |
58 | {{! --------------------------------------------- }}
59 |
60 |
translate
61 |
62 |
Positions the item. Set to a Vector
.
63 |
64 |
65 |
66 | ``` js
67 | translate: { x: 20, y: -40 }
68 | // move right 20px, up 40px
69 | ```
70 |
71 |
72 |
74 | {{> edit-demo penSlug="OYOBGX"}}
75 |
76 |
77 |
78 | {{! --------------------------------------------- }}
79 |
80 |
rotate
81 |
82 |
Rotates the item. Set to a Vector
to rotate the item around the corresponding axis.
83 |
84 |
85 |
86 | ``` js
87 | rotate: { x: Zdog.TAU/8 }
88 | // rotate around horizontal axis
89 | ```
90 |
91 |
92 |
94 | {{> edit-demo penSlug="dEZgLB"}}
95 |
96 |
97 |
98 |
99 |
100 | ``` js
101 | rotate: { y: Zdog.TAU/8 }
102 | // rotate around vertical axis
103 | ```
104 |
105 |
106 |
108 | {{> edit-demo penSlug="zQPmQJ"}}
109 |
110 |
111 |
112 |
113 |
114 | ``` js
115 | rotate: { z: Zdog.TAU/8 }
116 | // rotate around z axis
117 | ```
118 |
119 |
120 |
122 | {{> edit-demo penSlug="vwWVqY"}}
123 |
124 |
125 |
126 | {{! --------------------------------------------- }}
127 |
128 |
scale
129 |
130 |
Enlarges or shrinks item geometry. scale
does not scale stroke
.
131 |
132 |
Set scale
with a number to set x
, y
, & z
scales to the same value.
133 |
134 |
135 |
136 | ``` js
137 | scale: 2
138 | // scale up all coordinates 200%
139 | ```
140 |
141 |
142 |
144 | {{> edit-demo penSlug="gJXBNP"}}
145 |
146 |
147 |
148 |
Set scale
to a Vector
to set coordinate-specific scale.
149 |
150 |
151 |
152 | ``` js
153 | scale: { x: 0.5, y: 1.5 }
154 | // scale x 50%, y 150%
155 | ```
156 |
157 |
158 |
160 | {{> edit-demo penSlug="MdOPMQ"}}
161 |
162 |
163 |
164 | {{! --------------------------------------------- }}
165 |
166 |
copy()
167 |
168 |
Copy an item. copy()
only copies the item, not the item’s graph of descendant items. Use copyGraph()
to copy the item and its graph.
169 |
170 | {{> copy-example }}
171 |
172 | {{! --------------------------------------------- }}
173 |
174 |
copyGraph()
175 |
176 |
Copies item and its descendent items.
177 |
178 | {{> copy-graph-example }}
179 |
180 | {{! --------------------------------------------- }}
181 |
182 |
addChild()
183 |
184 |
Adds child item. addChild()
is useful for moving a child item to a new parent, or creating an item without addTo
.
185 |
186 | ``` js
187 | let anchor = new Zdog.Anchor({
188 | // ...
189 | });
190 |
191 | let shape = new Zdog.Shape({
192 | // no addTo
193 | });
194 | // add shape to anchor
195 | anchor.addChild( shape );
196 | ```
197 |
198 | {{! --------------------------------------------- }}
199 |
200 |
removeChild()
201 |
202 |
Removes child item
203 |
204 | ``` js
205 | let shape = new Zdog.Shape({
206 | addTo: anchor,
207 | });
208 |
209 | anchor.removeChild( shape );
210 | ```
211 |
212 | {{! --------------------------------------------- }}
213 |
214 |
remove()
215 |
216 |
Removes item from parent.
217 |
218 | ``` js
219 | let shape = new Zdog.Shape({
220 | addTo: anchor,
221 | });
222 |
223 | shape.remove();
224 | ```
225 |
226 | {{! --------------------------------------------- }}
227 |
228 |
updateGraph()
229 |
230 |
Updates the items and all its graph of descendant items so they are ready for rendering. Useful for rendering without Illustration
.
231 |
232 | ``` js
233 | anchor.updateGraph();
234 | ```
235 |
236 | {{! --------------------------------------------- }}
237 |
238 |
renderGraphCanvas()
239 |
240 |
Renders the item and all its descendant items to a <canvas>
element. Useful for rendering without Illustration
.
241 |
242 | ``` js
243 | anchor.renderGraphCanvas( ctx );
244 | ```
245 |
246 |
247 | ctx
: CanvasRenderingContext2D
248 |
249 |
250 | ``` js
251 | let canvas = document.querySelector('.zdog-canvas');
252 | let ctx = canvas.getContext('2d');
253 |
254 | let scene = new Anchor();
255 | // add some shapes...
256 |
257 | scene.updateGraph();
258 | // render on canvas
259 | scene.renderGraphCanvas( ctx );
260 | ```
261 |
262 | {{! --------------------------------------------- }}
263 |
264 |
renderGraphSvg()
265 |
266 |
Renders the item and all its descendant items to an SVG element. Useful for rendering without Illustration
.
267 |
268 | ``` js
269 | anchor.renderGraphSvg( element );
270 | ```
271 |
272 |
273 | element
: An SVG container element like <svg>
or <g>
.
274 |
275 |
276 | ``` js
277 | let svg = document.querySelector('.zdog-svg');
278 |
279 | let scene = new Anchor({...});
280 | // add some shapes...
281 |
282 | scene.updateGraph();
283 | // render on SVG
284 | scene.renderGraphSvg( svg );
285 | ```
286 |
287 | {{! --------------------------------------------- }}
288 |
289 |
normalizeRotate()
290 |
291 |
Wraps-around rotate
x
, y
, & z
values between 0
and TAU
.
292 |
293 | {{! --------------------------------------------- }}
294 |
--------------------------------------------------------------------------------
/modules/docs/api-dragger.hbs:
--------------------------------------------------------------------------------
1 |
Dragger
2 |
3 |
Tracks dragging interaction with pointer events. Illustration
inherits Dragger
which enables dragRotate
and use of the onDrag callback functions.
4 |
5 |
The Dragger
class by itself is useful for dragging interactions outside of Illustration.dragRotate
or rendering without Illustration
. See updatePath
for another Dragger demo.
6 |
7 |
8 |
9 | ``` js
10 | // use Dragger to rotate shapes separately
11 | let circle = new Zdog.Ellipse({...});
12 | let triangle = new Zdog.Shape({...});
13 | // variables for rotation dragging
14 | let viewRotation = new Zdog.Vector();
15 | let dragStartRX, dragStartRY;
16 |
17 | new Zdog.Dragger({
18 | startElement: illo.element,
19 | onDragStart: function() {
20 | // highlight on drag start
21 | circle.color = '#C25';
22 | triangle.color = '#EA0';
23 | // keep track of rotation
24 | dragStartRX = viewRotation.x;
25 | dragStartRY = viewRotation.y;
26 | },
27 | onDragMove: function( pointer, moveX, moveY ) {
28 | // move rotation
29 | let moveRX = moveY / illo.width * Zdog.TAU * -1;
30 | let moveRY = moveX / illo.width * Zdog.TAU * -1;
31 | viewRotation.x = dragStartRX + moveRX;
32 | viewRotation.y = dragStartRY + moveRY;
33 | },
34 | onDragEnd: function() {
35 | // remove highlight colors on drag end
36 | circle.color = '#636';
37 | triangle.color = '#E62';
38 | },
39 | });
40 |
41 | function animate() {
42 | // rotate shapes
43 | circle.rotate.set( viewRotation );
44 | triangle.rotate.set( viewRotation );
45 | illo.updateRenderGraph();
46 | requestAnimationFrame( animate );
47 | }
48 | animate();
49 | ```
50 |
51 |
52 |
54 | {{> edit-demo penSlug="zQPyZq"}}
55 |
56 |
57 |
58 | {{! --------------------------------------------- }}
59 |
60 |
startElement
61 |
62 |
The element to start dragging on the initial mousedown
, pointerdown
, or touchstart
event.
63 |
64 | ``` js
65 | // set with a selector string
66 | startElement: '.zdog-canvas'
67 |
68 | // set with an Element
69 | startElement: document.querySelector('.zdog-canvas')
70 | ```
71 |
72 | {{! --------------------------------------------- }}
73 |
74 |
onDragStart
75 |
76 |
Callback function triggered when dragging starts with the initial mousedown
, pointerdown
, or touchstart
event.
77 |
78 | ``` js
79 | onDragStart: function( pointer ) {
80 | console.log(`Drag started at ${pointer.pageX}, ${pointer.pageY});
81 | }
82 | ```
83 |
84 |
85 | pointer
- the Event or Touch object with .pageX
and .pageY
.
86 |
87 |
88 | {{! --------------------------------------------- }}
89 |
90 |
onDragMove
91 |
92 |
Callback function triggered when dragging moves with mousemove
, pointermove
, or touchmove
event.
93 |
94 | ``` js
95 | onDragMove: function( pointer, moveX, moveY ) {
96 | console.log(`Drag moved ${moveX}, ${moveY}`);
97 | }
98 | ```
99 |
100 |
101 | pointer
- the Event or Touch object with .pageX
and .pageY
.
102 | moveX
- horizontal distance moved from the dragStart position.
103 | moveY
- vertical distance moved from the dragStart position.
104 |
105 |
106 |
107 | {{! --------------------------------------------- }}
108 |
109 |
onDragEnd
110 |
111 |
Callback function triggered when dragging ends on the mouseup
, pointerup
, or touchend
event.
112 |
113 | ``` js
114 | onDragEnd: function() {
115 | console.log('Drag ended');
116 | }
117 | ```
118 |
119 | {{! --------------------------------------------- }}
120 |
--------------------------------------------------------------------------------
/modules/docs/api-group.hbs:
--------------------------------------------------------------------------------
1 |
Group
2 |
3 |
An item with a separated rendering order. Inherits Anchor
.
4 |
5 | {{> group-concept }}
6 |
7 | {{! --------------------------------------------- }}
8 |
9 |
visible
10 |
11 |
Shows or hides group, including all child items in the group. Shape.visible
only shows or hides the item. Enabled by default visible: true
.
12 |
13 | {{! --------------------------------------------- }}
14 |
15 |
updateSort
16 |
17 |
Updates the rendering order of the group’s child items.
18 |
19 |
Disabled by default updateSort: false
. Group child items are rendered in the order they are added to the Group
.
20 |
21 | {{! --------------------------------------------- }}
22 |
--------------------------------------------------------------------------------
/modules/docs/api-illo.hbs:
--------------------------------------------------------------------------------
1 |
Illustration
2 |
3 |
Handles displaying and rotating a scene on an HTML element. Inherits both Anchor
and Dragger
. Illustration
does several things.
4 |
5 |
6 | As an Anchor
, it acts as a top level item for all other items in the scene to be added to.
7 | It manages rendering items to an HTML element, either a <canvas>
or an <svg>
.
8 | It manages the dragging interaction to rotate an item.
9 |
10 |
11 |
12 |
13 | ``` js
14 | let illo = new Zdog.Illustration({
15 | element: '.zdog-canvas',
16 | dragRotate: true,
17 | });
18 | // add shapes to Illustration
19 | // triangle
20 | new Zdog.Shape({
21 | addTo: illo,
22 | // ...
23 | });
24 | // circle
25 | new Zdog.Ellipse({
26 | addTo: illo,
27 | // ...
28 | });
29 | // animate
30 | function animate() {
31 | illo.updateRenderGraph();
32 | requestAnimationFrame( animate );
33 | }
34 | animate();
35 | ```
36 |
37 |
38 |
40 | {{> edit-demo penSlug="dEZwzV"}}
41 |
42 |
43 |
44 | {{! --------------------------------------------- }}
45 |
46 |
element
47 |
48 |
The HTML element to render on, either a <canvas>
or an <svg>
.
49 |
50 | ``` js
51 | // set with a selector string
52 | element: '.zdog-canvas'
53 |
54 | // set with an Element
55 | element: document.querySelector('.zdog-canvas')
56 | ```
57 |
58 |
Illustration
requires the initial size of the element be set in its element width
and height
attributes.
59 |
60 | ``` html
61 |
62 | ```
63 |
64 |
With a <canvas>
element, Illustration
will increase resolution of the <canvas>
for high pixel density displays.
65 |
66 |
67 |
68 | ``` html
69 |
70 | ```
71 | ``` js
72 | element: '.zdog-canvas'
73 | ```
74 |
75 |
76 |
78 | {{> edit-demo penSlug="dEZwzV"}}
79 |
80 |
81 |
82 |
83 |
84 | ``` html
85 |
86 | ```
87 | ``` js
88 | element: '.zdog-svg'
89 | ```
90 |
91 |
92 |
93 | {{> edit-demo penSlug="Xwzoed"}}
94 |
95 |
96 |
97 | {{! --------------------------------------------- }}
98 |
99 |
translate, rotate, & scale
100 |
101 |
As an Anchor
, you can sets translate
, rotate
, & scale
transforms on the Illustration
.
102 |
103 |
Set rotate
to set the initial view rotation of the scene.
104 |
105 |
106 |
107 | ``` js
108 | rotate: { y: Zdog.TAU/8 }
109 | // rotate 45°
110 | ```
111 |
112 |
113 |
115 | {{> edit-demo penSlug="joaXaj"}}
116 |
117 |
118 |
119 | {{! --------------------------------------------- }}
120 |
121 |
zoom
122 |
123 |
Enlarges or shrinks the displayed size of the rendering. Whereas scale
will change the size of item geometry, zoom
changes item geometry and stroke
size.
124 |
125 |
126 |
127 | ``` js
128 | zoom: 1.5
129 | // enlarge 150%
130 | ```
131 |
132 |
133 |
135 | {{> edit-demo penSlug="KLybQP"}}
136 |
137 |
138 |
139 |
140 |
141 | ``` js
142 | zoom: 0.5
143 | // shrink to 50% size
144 | ```
145 |
146 |
147 |
149 |
150 |
151 |
152 | {{! --------------------------------------------- }}
153 |
154 |
centered
155 |
156 |
Centers the scene in the element. Enabled by default
.
157 |
158 |
159 |
160 | ``` js
161 | centered: false
162 | // position scene at 0,0 in top left corner
163 | ```
164 |
165 |
166 |
168 | {{> edit-demo penSlug="joaXZg"}}
169 |
170 |
171 |
172 | {{! --------------------------------------------- }}
173 |
174 |
dragRotate
175 |
176 |
Enables dragging to rotate on an item.
177 |
178 |
With dragRotate
enabled, you can then use Dragger
onDrag functions: onDragStart
, onDragMove
, onDragEnd
179 |
180 |
Set dragRotate: true
to drag-rotate the Illustration
’s item graph.
181 |
182 |
183 |
184 | ``` js
185 | let illo = new Zdog.Illustration({
186 | dragRotate: true,
187 | // ...
188 | });
189 |
190 | let circle = new Zdog.Ellipse({
191 | addTo: illo,
192 | // ...
193 | });
194 | let triangle = new Zdog.Shape({
195 | addTo: illo,
196 | // ...
197 | });
198 | ```
199 |
200 |
201 |
203 | {{> edit-demo penSlug="dEZwzV"}}
204 |
205 |
206 |
207 |
Set dragRotate
to an item to drag-rotate that item’s graph.
208 |
209 |
210 |
211 | ``` js
212 | let triangle = new Zdog.Shape({...});
213 |
214 | let illo = new Zdog.Illustration({
215 | dragRotate: triangle,
216 | // ...
217 | });
218 | illo.addChild( triangle );
219 |
220 | let circle = new Zdog.Ellipse({
221 | addTo: illo,
222 | // ...
223 | });
224 | ```
225 |
226 |
227 |
229 | {{> edit-demo penSlug="oRoJdo"}}
230 |
231 |
232 |
233 | {{! --------------------------------------------- }}
234 |
235 |
resize
236 |
237 |
Enables fluid resizing of element.
238 |
239 |
With an <canvas>
element, Illustration
will re-set the width
and height
attributes to match the display size of the element for crisp pixel-perfect display.
240 |
241 |
Enable resize: true
for fluid element resizing.
242 |
243 |
244 |
245 | ``` html
246 |
247 |
248 | ```
249 | ``` css
250 | .zdog-canvas {
251 | display: block;
252 | width: 100%;
253 | }
254 | ```
255 | ``` js
256 | resize: true
257 | ```
258 |
259 |
260 |
262 | {{> edit-demo penSlug="pmdqZv"}}
263 |
264 |
265 |
266 |
With an <svg>
element, Illustration
will remove width
and height
attributes, so the <svg>
will scale up its size proportionally, filling up the width of its parent element — similar behavior to an <img>
with width: 100%
.
267 |
268 |
269 |
270 | ``` html
271 |
272 | ```
273 | ``` js
274 | resize: true
275 | ```
276 |
277 |
278 |
280 | {{> edit-demo penSlug="wbPREZ"}}
281 |
282 |
283 |
284 |
Set resize: 'fullscreen'
to resize the element to the size of the browser window. View fullscreen demo on CodePen.
285 |
286 |
287 |
288 | ``` js
289 | resize: 'fullscreen'
290 | ```
291 | ``` css
292 | .zdog-canvas {
293 | width: 100%;
294 | height: 100%;
295 | }
296 | ```
297 |
298 |
299 |
300 |
For <canvas>
, set 100%
width and height CSS on the canvas. Zdog will scale up the canvas to match device pixel ratio. 100%
width and height then scales the element back down, thus providing higher pixel density.
301 |
302 | {{! --------------------------------------------- }}
303 |
304 |
onResize
305 |
306 |
A function triggered when the element is resized. Required resize
to be enabled.
307 |
308 | ``` js
309 | onResize: function( width, height ) {
310 | console.log(`Illo element is ${width} x ${height}`);
311 | }
312 | ```
313 |
314 |
Use onResize
to proportionally scale zoom
.
315 |
316 |
317 |
318 | ``` js
319 | resize: true,
320 | onResize: function( width ) {
321 | // scale zoom
322 | this.zoom = width / 400;
323 | },
324 | ```
325 |
326 |
327 |
329 | {{> edit-demo penSlug="gJXZQQ"}}
330 |
331 |
332 |
333 |
334 | {{! --------------------------------------------- }}
335 |
336 |
onPrerender
337 |
338 |
Function triggered before rendering.
339 |
340 | ``` js
341 | onPrerender: function( context ) {
342 | // ...
343 | }
344 | ```
345 |
346 |
347 | context
- the rendering context. For <canvas>
, the CanvasRenderingContext2D . For <svg>
, the <svg>
element.
348 |
349 |
350 |
351 |
352 | ``` js
353 | // with
354 | onPrerender: function( ctx ) {
355 | // render axis lines
356 | ctx.fillStyle = '#EA0';
357 | // with centered enabled, 0,0 is center of canvas
358 | ctx.fillRect( -1, -120, 2, 240 );
359 | ctx.fillRect( -120, -1, 240, 2 );
360 | },
361 | ```
362 |
363 |
364 |
366 | {{> edit-demo penSlug="oRoJJE"}}
367 |
368 |
369 |
370 | {{! --------------------------------------------- }}
371 |
372 |
renderGraph()
373 |
374 |
Renders an item and its graph to the Illustration
’s element.
375 |
376 |
Call .renderGraph()
to render the Illustration
item graph.
377 |
378 | ``` js
379 | illo.renderGraph()
380 | ```
381 |
382 |
Pass in an item to render that item.
383 |
384 | ``` js
385 | illo.renderGraph( scene )
386 | ```
387 |
388 | {{! --------------------------------------------- }}
389 |
390 |
updateRenderGraph()
391 |
392 |
Combines updateGraph()
and renderGraph()
methods — to save you a line of code. Updates and renders an item and its graph to the Illustration
’s element.
393 |
394 |
Call .updateRenderGraph()
to render the Illustration
’s item graph.
395 |
396 | ``` js
397 | illo.updateRenderGraph()
398 | ```
399 |
400 |
Pass in an item to render that item.
401 |
402 | ``` js
403 | illo.updateRenderGraph( scene )
404 | ```
405 |
406 | {{! --------------------------------------------- }}
407 |
408 |
setSize()
409 |
410 |
Sets element size.
411 |
412 | ``` js
413 | illo.setSize( width, height )
414 | ```
415 |
416 | {{! --------------------------------------------- }}
417 |
--------------------------------------------------------------------------------
/modules/docs/api-shape.hbs:
--------------------------------------------------------------------------------
1 |
Shape
2 |
3 |
A visible shape. Shape
is the super-class for all shape classes — Rect
, Ellipse
, Cone
, etc. All shape classes can use Shape
options and methods.
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
color
8 |
9 |
Sets shape stroke and fill color. Set to any color string — hex code, rgb()
, hsla()
, etc. Default
.
10 |
11 |
12 |
13 | ``` js
14 | color: '#E62'
15 | ```
16 |
17 |
18 |
19 | {{> edit-demo penSlug="wbPQMd"}}
20 |
21 |
22 |
23 | {{! --------------------------------------------- }}
24 |
25 |
stroke
26 |
27 |
Renders the shape line and sets line width. Default
.
28 |
29 |
30 |
31 | ``` js
32 | stroke: 30
33 | ```
34 |
35 |
36 |
38 | {{> edit-demo penSlug="eaeQJL"}}
39 |
40 |
41 |
42 |
Set stroke
to 0
or false
to disable.
43 |
44 |
45 |
46 | ``` js
47 | // render only fill
48 | stroke: false,
49 | fill: true,
50 | ```
51 |
52 |
53 |
55 | {{> edit-demo penSlug="JqOeGq"}}
56 |
57 |
58 |
59 | {{! --------------------------------------------- }}
60 |
61 |
fill
62 |
63 |
Renders the inner shape area. Disabled by default
.
64 |
65 |
66 |
67 | ``` js
68 | fill: true
69 | ```
70 |
71 |
72 |
74 | {{> edit-demo penSlug="EzbOKr"}}
75 |
76 |
77 |
78 | {{! --------------------------------------------- }}
79 |
80 |
closed
81 |
82 |
Closes the path from the last point back to the first. Enabled by default
.
83 |
84 |
85 |
86 | ``` js
87 | closed: false
88 | ```
89 |
90 |
91 |
93 | {{> edit-demo penSlug="BemGzW"}}
94 |
95 |
96 |
97 | {{! --------------------------------------------- }}
98 |
99 |
visible
100 |
101 |
Shows or hides shape. Does not affect child items. Enabled by default
.
102 |
103 | {{! --------------------------------------------- }}
104 |
105 |
backface
106 |
107 |
Shows or hides the shape when its backface is visible. Enabled by default
.
108 |
109 |
Set backface: false
to hide the shape when its backface is showing.
110 |
111 |
112 |
113 | ``` js
114 | backface: false
115 | ```
116 |
117 |
118 |
120 | {{> edit-demo penSlug="GaOwvr"}}
121 |
122 |
123 |
124 |
Set backface
to a color to change the shape’s color when its backface is showing.
125 |
126 |
127 |
128 | ``` js
129 | backface: "#636"
130 | ```
131 |
132 |
133 |
135 | {{> edit-demo penSlug="zQPMdX"}}
136 |
137 |
138 |
139 | {{! --------------------------------------------- }}
140 |
141 |
front
142 |
143 |
A Vector
used to determine where the front of the shape is. Useful for changing how backface
works for custom Shape
s. Default front: { z: 1 }
.
144 |
145 | {{! --------------------------------------------- }}
146 |
147 |
updatePath()
148 |
149 |
Updates the shape path. Trigger updatePath()
after you change a point on a Shape
’s path, a Rect
’s width or height, etc.
150 |
151 |
152 |
153 | ``` js
154 | let triangle = new Zdog.Shape({...});
155 | // get first path point
156 | let trianglePoint = triangle.path[0];
157 | let dragStartX, dragStartY;
158 |
159 | // drag to change path point
160 | new Zdog.Dragger({
161 | onDragStart: function() {
162 | dragStartX = trianglePoint.x;
163 | dragStartY = trianglePoint.y;
164 | },
165 | onDragMove: function( pointer, moveX, moveY ) {
166 | trianglePoint.x = dragStartX + moveX;
167 | trianglePoint.y = dragStartY + moveY;
168 | // path point changed, updatePath() to apply change
169 | triangle.updatePath();
170 | },
171 | });
172 | ```
173 |
174 |
175 |
177 | {{> edit-demo penSlug="PvOxQj"}}
178 |
179 |
180 |
181 | {{! --------------------------------------------- }}
182 |
--------------------------------------------------------------------------------
/modules/docs/api-utils.hbs:
--------------------------------------------------------------------------------
1 |
Utilities
2 |
3 |
Zdog includes a couple constants and methods to help with math & animation.
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
TAU
8 |
9 | ``` js
10 | Zdog.TAU // => 6.28318
11 | ```
12 |
13 |
A full rotation in radians. Math.PI * 2
. TAU
is more user-friendly than PI
as TAU
maps directly to a full rotation.
14 |
15 | ``` js
16 | const TAU = Zdog.TAU; // easier to read constant
17 |
18 | rotate: { y: TAU/4 } // /4 = quarter turn
19 | rotate: { y: TAU/2 } // /2 = half turn
20 | rotate: { y: TAU*3 } // *3 = 3 full turns
21 | ```
22 |
23 | {{! --------------------------------------------- }}
24 |
25 |
easeInOut()
26 |
27 |
Apply an in-out easing. Useful for animation.
28 |
29 | ``` js
30 | let easeAlpha = Zdog.easeInOut( alpha, power );
31 | ```
32 |
33 |
34 | alpha
- a Number 0
to 1
.
35 | power
- the exponential power of the easing curve. Default 2
.
36 |
37 |
38 |
39 |
40 | ``` js
41 | let ticker = 0;
42 | let cycleCount = 150;
43 |
44 | function animate() {
45 | let progress = ticker / cycleCount;
46 | // apply easing to rotation
47 | let tween = Zdog.easeInOut( progress % 1, 3 );
48 | illo.rotate.y = tween * Zdog.TAU;
49 | ticker++;
50 |
51 | illo.updateRenderGraph();
52 | requestAnimationFrame( animate );
53 | }
54 | animate();
55 | ```
56 |
57 |
58 |
60 | {{> edit-demo penSlug="arVXdE"}}
61 |
62 |
63 |
64 | {{! --------------------------------------------- }}
65 |
66 |
extend()
67 |
68 | ``` js
69 | Zdog.extend( a, b )
70 | ```
71 |
72 |
Sets the properties of Object b
on to Object a
.
73 |
74 | ``` js
75 | let optionsA = { stroke: 4, fill: true };
76 | let optionsB = { color: '#EA0', fill: false };
77 |
78 | Zdog.extend( optionsA, optionsB );
79 | // optionsA = { stroke: 4, color: '#EA0', fill: false }
80 | ```
81 |
82 | {{! --------------------------------------------- }}
83 |
84 |
lerp()
85 |
86 | ``` js
87 | Zdog.lerp( a, b, alpha )
88 | ```
89 |
90 |
Linear interpolation between values a
and b
given a percent decimal alpha
.
91 |
92 | ``` js
93 | // 75% of the way between 20 and 40
94 | Zdog.lerp( 20, 40, 0.75 );
95 | // => 35
96 | ```
97 |
98 | {{! --------------------------------------------- }}
99 |
100 |
modulo()
101 |
102 | ``` js
103 | Zdog.modulo( a, b )
104 | ```
105 |
106 |
Returns modulo or "wrap around" value of a
given b
.
107 |
108 | ``` js
109 | // It's 8AM now. What time will it be 18 hours from now?
110 | let later = Zdog.modulo( 8 + 18, 24 )
111 | // => 2, 2AM
112 |
113 | // It's 8AM now. What time was it 15 hours ago?
114 | let earlier = Zdog.modulo( 8 - 15, 24 )
115 | // => 17, uh, I'm American
116 | earlier = Zdog.modulo( earlier, 12 )
117 | // => 5PM
118 |
119 | // Why can't I use % operator?
120 | earlier = ( 8 - 15 ) % 24;
121 | // => -7, oh no. % returns remainders, which can be negative
122 | ```
123 |
124 |
--------------------------------------------------------------------------------
/modules/docs/api-vector.hbs:
--------------------------------------------------------------------------------
1 |
Vector
2 |
3 |
A 3D vector with x
, y
, and z
coordinates.
4 |
5 |
Create a Vector by passing in a vector Object or another Vector
.
6 |
7 | ``` js
8 | let position = new Zdog.Vector({ x: 1, y: 0, z: 2 });
9 | ```
10 |
11 |
Zdog uses Vector
s for position in 3D space and for rotation.
12 |
13 | ``` js
14 | // position
15 | let position = new Zdog.Vector({ x: 1, y: -2, z: 3 });
16 | // => 1 right, 2 up, 3 closer
17 | ```
18 |
19 |
With rotation , the coordinate values are used for the angle around the respective axis.
20 |
21 | ``` js
22 | let rotation = new Zdog.Vector({ y: Zdog.TAU/4 });
23 | // => quarter-turn around vertical y-axis
24 | ```
25 |
26 | {{! --------------------------------------------- }}
27 |
28 |
Vector Objects
29 |
30 | {{> vector-objects }}
31 |
32 | ``` js
33 | new Zdog.Vector({ x: 1, z: 2 }) // => { x: 1, y: 0, z: 2 }
34 | new Zdog.Vector({ y: 3 }) // => { x: 0, y: 3, z: 0 }
35 | new Zdog.Vector({}) // => { x: 0, y: 0, z: 0 }
36 |
37 | let position = new Zdog.Vector({ x: 4 });
38 | // => { x: 4, y: 0, z: 0 }
39 | position.add({ y: 5 });
40 | // => { x: 4, y: 5, z: 0 }
41 | ```
42 |
43 |
44 |
A vector Object is different from an instance of a Vector
class.
45 |
46 | ``` js
47 | // won't work, just an Object
48 | { x: 1 }.add({ y: 2 });
49 |
50 | // will work, is a Vector
51 | new Zdog.Vector({ x: 1 }).add({ y: 2 });
52 | ```
53 |
54 | {{! --------------------------------------------- }}
55 |
56 |
set()
57 |
58 |
Sets x
, y
, z
coordinates.
59 |
60 | ``` js
61 | vec.set({ x: 1, z: 2 })
62 | // => { x: 1, y: 0, z: 2 }
63 | ```
64 |
65 | {{! --------------------------------------------- }}
66 |
67 |
copy()
68 |
69 |
Returns a new Vector
with copied x
, y
, and z
coordinates. Most Vector
methods are mutable — they change the Vector’s coordinates. Use .copy()
to work with a vector while still preserving the original.
70 |
71 | ``` js
72 | let positionA = new Zdog.Vector({ x: 1, z: 2 });
73 | let positionB = positionA.copy();
74 |
75 | positionB.add({ x: 3 });
76 | // => { x: 4, y: 0, z: 2 }
77 | positionA
78 | // => { x: 1, y: 0, z: 2 }
79 | ```
80 |
81 | {{! --------------------------------------------- }}
82 |
83 |
add()
84 |
85 |
Adds x
, y
, z
coordinate values.
86 |
87 | ``` js
88 | let position = new Zdog.Vector({ x: 1, z: 2 });
89 | position.add({ x: 3, y: 4 });
90 | // => { x: 4, y: 5, z: 2 }
91 | ```
92 |
93 | {{! --------------------------------------------- }}
94 |
95 |
subtract()
96 |
97 |
Subtracts x
, y
, z
coordinate values.
98 |
99 | ``` js
100 | let position = new Zdog.Vector({ x: 1, z: 2 });
101 | position.subtract({ x: 3, y: 4 });
102 | // => { x: -2, y: -4, z: 2 }
103 | ```
104 |
105 | {{! --------------------------------------------- }}
106 |
107 |
multiply()
108 |
109 |
Multiplies x
, y
, z
coordinate values.
110 |
111 | ``` js
112 | let position = new Zdog.Vector({ x: 2, z: 3 });
113 | position.multiply({ x: 3, y: 4 z: 5 });
114 | // => { x: 6, y: 0, z: 15 }
115 | ```
116 |
117 |
.multiply()
can be passed a Number to multiply all coordinates by the same value.
118 |
119 | ``` js
120 | let position = new Zdog.Vector({ x: 2, z: 3 });
121 | position.multiply( 4 );
122 | // => { x: 8, y: 0, z: 12 }
123 | ```
124 |
125 | {{! --------------------------------------------- }}
126 |
127 |
rotate()
128 |
129 | ``` js
130 | vector.rotate( rotation );
131 | ```
132 |
133 |
Rotates a position vector given a rotation
vector Object .
134 |
135 | ``` js
136 | let position = new Zdog.Vector({ x: 1, y: 2 });
137 | // rotate 45° clockwise
138 | position.rotate({ z: Zdog.TAU/4 });
139 | // => { x: -2, y: 1, z: 0 }
140 | ```
141 |
142 | {{! --------------------------------------------- }}
143 |
144 |
magnitude()
145 |
146 |
Returns the total length of the vector.
147 |
148 | ``` js
149 | let position = new Zdog.Vector({ x: 6, y: 8 });
150 | let mag = position.magnitude();
151 | // => 10
152 | ```
153 |
154 | {{! --------------------------------------------- }}
155 |
156 |
lerp()
157 |
158 | ``` js
159 | vector.lerp( point, alpha );
160 | ```
161 |
162 |
Linear interporlate the vector towards point
, given alpha
a percent between the vector and point
.
163 |
164 | ``` js
165 | let position = new Zdog.Vector({ x: 2, y: 4 });
166 | // interpolate 75% to 6,8,0
167 | position.lerp( { x: 6, y: 8 }, 0.75 );
168 | // => { x: 5, y: 7, z: 0 }
169 | ```
170 |
171 | {{! --------------------------------------------- }}
172 |
173 |
--------------------------------------------------------------------------------
/modules/docs/child-shapes-add-to.hbs:
--------------------------------------------------------------------------------
1 |
Shapes can be added as children to other shapes. A child shape is positioned relative to its parent.
2 |
3 |
4 |
5 | ``` js
6 | let zCircle = new Zdog.Ellipse({
7 | addTo: illo,
8 | translate: { z: 40 }, // z +40 from illo
9 | // ...
10 | });
11 |
12 | let xRect = new Zdog.Rect({
13 | addTo: zCircle,
14 | translate: { x: 40 }, // x +40 from zCircle
15 | // ...
16 | });
17 |
18 | let yTri = new Zdog.Polygon({
19 | addTo: xRect,
20 | translate: { y: -60 }, // y -60 from xRect
21 | // ...
22 | });
23 | ```
24 |
25 |
26 |
28 | {{> edit-demo penSlug="pmWKje"}}
29 |
30 |
31 |
--------------------------------------------------------------------------------
/modules/docs/copy-example.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | ``` js
4 | // create original
5 | let rect = new Zdog.Rect({
6 | addTo: illo,
7 | width: 64,
8 | height: 64,
9 | translate: { x: -48 },
10 | stroke: 16,
11 | color: '#EA0',
12 | });
13 | // copy
14 | rect.copy({
15 | // overwrite original options
16 | translate: { x: 48 },
17 | color: '#C25',
18 | });
19 | ```
20 |
21 |
22 |
23 | {{> edit-demo penSlug="vwergo"}}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/modules/docs/copy-graph-example.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 | ``` js
4 | // create original
5 | let rect = new Zdog.Rect({
6 | // ...
7 | });
8 | // add child item
9 | new Zdog.Shape({
10 | addTo: rect,
11 | // ...
12 | });
13 | // copy rect and its children
14 | rect.copyGraph({
15 | // overwrite original rect options
16 | translate: { x: 48 },
17 | color: '#C25',
18 | });
19 | ```
20 |
21 |
22 |
24 | {{> edit-demo penSlug="MdEXpO"}}
25 |
26 |
27 |
--------------------------------------------------------------------------------
/modules/docs/group-concept.hbs:
--------------------------------------------------------------------------------
1 |
Use a Group
to control rendering order. Shapes will be rendered in the order they are added to the Group
. Group
s are useful for positioning shapes within other shapes, like windows in walls or pupils in eyes.
2 |
3 |
4 |
5 | ``` js
6 | // render shapes in order added
7 | var eyeGroup = new Zdog.Group({
8 | addTo: illo,
9 | translate: { z: 20 },
10 | });
11 | // eye white first
12 | new Zdog.Ellipse({
13 | addTo: eyeGroup,
14 | width: 160,
15 | height: 80,
16 | // ...
17 | });
18 | // then iris
19 | let iris = new Zdog.Ellipse({
20 | addTo: eyeGroup,
21 | diameter: 70,
22 | // ...
23 | });
24 | // then pupil
25 | iris.copy({
26 | diameter: 30,
27 | color: '#636',
28 | });
29 | // highlight last in front
30 | iris.copy({
31 | diameter: 30,
32 | translate: { x: 15, y: -15 },
33 | color: 'white',
34 | });
35 | ```
36 |
37 |
38 |
39 | {{> edit-demo penSlug="byoKLg"}}
40 |
41 |
42 |
--------------------------------------------------------------------------------
/modules/docs/modeling-concepts.hbs:
--------------------------------------------------------------------------------
1 | {{! --------------------------------------------- }}
2 |
3 |
Concepts
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
Child shapes
8 |
9 |
Zdog models are built with shapes. Shapes can be positioned with translate
. Their positions are relative . For instance, when added to an Illustration
, shapes are positioned relative to the Illustration
’s origin.
10 |
11 |
12 |
13 | ``` js
14 | let zCircle = new Zdog.Ellipse({
15 | addTo: illo,
16 | translate: { z: 40 }, // z +40 from illo
17 | // ...
18 | });
19 |
20 | let xRect = new Zdog.Rect({
21 | addTo: illo,
22 | translate: { x: 40 }, // x +40 from illo
23 | // ...
24 | });
25 |
26 | let yTri = new Zdog.Polygon({
27 | addTo: illo,
28 | translate: { y: -60 }, // y -60 from illo
29 | // ...
30 | });
31 | ```
32 |
33 |
34 |
36 | {{> edit-demo penSlug="KLXewa"}}
37 |
38 |
39 |
40 | {{> child-shapes-add-to }}
41 |
42 |
translate
is a transform — as is rotate
and scale
. Child shapes inherit the transforms of their parents (wow, that is deep ).
43 |
44 |
45 |
46 | ``` js
47 | let zCircle = new Zdog.Ellipse({
48 | addTo: illo,
49 | scale: 1.5, // scale 150%
50 | translate: { z: 40 },
51 | rotate: { z: -Zdog.TAU/8 }, // rotate 45° CCW
52 | // ...
53 | });
54 |
55 | let xRect = new Zdog.Rect({
56 | addTo: zCircle,
57 | translate: { x: 40 },
58 | rotate: { x: Zdog.TAU/8 }, // rotate back
59 | // ...
60 | });
61 |
62 | let yTri = new Zdog.Polygon({
63 | addTo: xRect,
64 | translate: { y: -60 },
65 | // ...
66 | });
67 | ```
68 |
69 |
70 |
72 | {{> edit-demo penSlug="LozrGX"}}
73 |
74 |
75 |
76 |
Using child shapes and their additive transforms enables you to build complex models.
77 |
78 | {{! --------------------------------------------- }}
79 |
80 |
Anchors
81 |
82 |
An Anchor
is an invisible shape. Use an Anchor
for transforms without rendering a shape.
83 |
84 |
85 |
86 | ``` js
87 | let zAnchor = new Zdog.Anchor({
88 | addTo: illo,
89 | scale: 1.5,
90 | translate: { z: 40 },
91 | rotate: { z: -Zdog.TAU/8 },
92 | });
93 |
94 | let xAnchor = new Zdog.Anchor({
95 | addTo: zAnchor,
96 | translate: { x: 40 },
97 | rotate: { x: Zdog.TAU/8 },
98 | });
99 |
100 | let yTri = new Zdog.Polygon({
101 | addTo: xAnchor,
102 | translate: { y: -60 },
103 | // ...
104 | });
105 | ```
106 |
107 |
108 |
110 | {{> edit-demo penSlug="MdEXeE"}}
111 |
112 |
113 |
114 |
115 | {{! --------------------------------------------- }}
116 |
117 |
Vector Objects
118 |
119 |
Properties like translate
, rotation
, and scale
are Vector
s. A Vector
can be set with a vector Object .
120 |
121 | {{> vector-objects }}
122 |
123 | ``` js
124 | translate: { x: 1, z: 2 }, // => { x: 1, y: 0, z: 2 }
125 | translate: { y: 3 }, // => { x: 0, y: 3, z: 0 }
126 | translate: {} // => { x: 0, y: 0, z: 0 }
127 | ```
128 |
129 | {{! --------------------------------------------- }}
130 |
131 |
Copying
132 |
133 |
Copy items with .copy()
.
134 |
135 | {{> copy-example }}
136 |
137 |
Copy items with their children with .copyGraph()
.
138 |
139 | {{> copy-graph-example }}
140 |
141 | {{! --------------------------------------------- }}
142 |
143 |
Stroke volume
144 |
145 |
Whereas polygonal 3D engines rely on meshes of polygons to depict volume, Zdog shapes can show volume with stroke
.
146 |
147 |
Look at this tasty burger. The patty and cheese slice are just simple circles. The sesame seeds are just lines. But with thick stroke
they appear as plump round discs and pills.
148 |
149 |
150 |
151 | ``` js
152 | // cheese
153 | new Zdog.Rect({
154 | width: 92,
155 | height: 92,
156 | stroke: 16,
157 | // ...
158 | });
159 | // patty
160 | new Zdog.Ellipse({
161 | diameter: 72,
162 | stroke: 28,
163 | // ...
164 | });
165 | // seed
166 | new Zdog.Shape({
167 | path: [ { y: -3 }, { y: 3 } ],
168 | stroke: 8,
169 | // ...
170 | });
171 | ```
172 |
173 |
174 |
175 | {{> edit-demo penSlug="QRqxMv"}}
176 |
177 |
178 |
179 |
Using stroke
for volume is what makes Zdog special. Let go of your earthly polygons and become one with the round thickness.
180 |
181 | {{! --------------------------------------------- }}
182 |
183 |
Groups
184 |
185 | {{> group-concept }}
186 |
187 | {{! --------------------------------------------- }}
188 |
--------------------------------------------------------------------------------
/modules/docs/shapes-basic.hbs:
--------------------------------------------------------------------------------
1 | {{! --------------------------------------------- }}
2 |
3 |
Rect
4 |
5 |
A rectangle. Set size with width
and height
. Default sizes: width: 1, height: 1
.
6 |
7 |
8 |
9 | ``` js
10 | let rect = new Zdog.Rect({
11 | addTo: illo,
12 | width: 120,
13 | height: 80,
14 | stroke: 20,
15 | color: '#E62',
16 | });
17 | ```
18 |
19 |
20 |
21 | {{> edit-demo penSlug="dEJLBZ"}}
22 |
23 |
24 |
25 |
All shapes are oriented facing "front" — towards the positive z-axis. Set rotate
to orient a shape in another direction.
26 |
27 |
28 |
29 | ``` js
30 | let rect = new Zdog.Rect({
31 | addTo: illo,
32 | width: 80,
33 | height: 64,
34 | stroke: 10,
35 | translate: { x: -48 },
36 | // turn to face left
37 | rotate: { y: TAU/4 },
38 | color: '#E62',
39 | });
40 |
41 | rect.copy({
42 | translate: { y: -48 },
43 | // turn to face up
44 | rotate: { x: TAU/4 },
45 | color: '#636',
46 | });
47 | ```
48 |
49 |
50 |
51 | {{> edit-demo penSlug="MdrRNa"}}
52 |
53 |
54 |
55 | {{! --------------------------------------------- }}
56 |
57 |
RoundedRect
58 |
59 |
A rectangle with rounded corners. Set size with width
and height
, like with Rect
. Set rounded corner radius with cornerRadius
. Default: cornerRadius: 0.25
.
60 |
61 |
62 |
63 | ``` js
64 | let roundedRect = new Zdog.RoundedRect({
65 | addTo: illo,
66 | width: 120,
67 | height: 80,
68 | cornerRadius: 30,
69 | stroke: 20,
70 | color: '#EA0',
71 | });
72 | ```
73 |
74 |
75 |
76 | {{> edit-demo penSlug="OYzYJr"}}
77 |
78 |
79 |
80 | {{! --------------------------------------------- }}
81 |
82 |
Ellipse
83 |
84 |
An ellipse. Set diameter
for circles. Default diameter: 1
85 |
86 |
87 |
88 | ``` js
89 | let circle = new Zdog.Ellipse({
90 | addTo: illo,
91 | diameter: 80,
92 | stroke: 20,
93 | color: '#C25',
94 | });
95 | ```
96 |
97 |
98 |
99 | {{> edit-demo penSlug="arErzW"}}
100 |
101 |
102 |
103 |
Set width
and height
for ellipses.
104 |
105 |
106 |
107 | ``` js
108 | let ellipse = new Zdog.Ellipse({
109 | addTo: illo,
110 | width: 60,
111 | height: 120,
112 | stroke: 20,
113 | color: '#C25',
114 | });
115 | ```
116 |
117 |
118 |
119 | {{> edit-demo penSlug="YbYbPL"}}
120 |
121 |
122 |
123 |
Set quarters
to an integer for quarter- and semi-circles. The quarter circle starts in the upper-right and continues clockwise.
124 |
125 |
126 |
127 | ``` js
128 | let semicircle = new Zdog.Ellipse({
129 | addTo: illo,
130 | diameter: 80,
131 | quarters: 2,
132 | stroke: 20,
133 | color: '#C25',
134 | });
135 | ```
136 |
137 |
138 |
139 | {{> edit-demo penSlug="pmpmJJ"}}
140 |
141 |
142 |
143 | {{! --------------------------------------------- }}
144 |
145 |
Polygon
146 |
147 |
A regular polygon. Set size with radius
and the number of sides with sides
. Default: radius: 0.5, sides: 3
.
148 |
149 |
150 |
151 | ``` js
152 | let pentagon = new Zdog.Polygon({
153 | addTo: illo,
154 | radius: 60,
155 | sides: 5,
156 | stroke: 20,
157 | color: '#EA0',
158 | });
159 | ```
160 |
161 |
162 |
163 | {{> edit-demo penSlug="oRpRXp"}}
164 |
165 |
166 |
--------------------------------------------------------------------------------
/modules/docs/shapes-composite.hbs:
--------------------------------------------------------------------------------
1 | {{! --------------------------------------------- }}
2 |
3 |
Hemisphere
4 |
5 |
A spherical hemisphere. Set size with diameter
. Set the color of the base ellipse with backface
. Defaults: diameter: 1, fill: true
. The origin of the hemisphere is the center of the base. The dome faces front toward positive z-axis.
6 |
7 |
8 |
9 | ``` js
10 | let dome = new Zdog.Hemisphere({
11 | addTo: illo,
12 | diameter: 120,
13 | // fill enabled by default
14 | // disable stroke for crisp edge
15 | stroke: false,
16 | color: '#C25',
17 | backface: '#EA0',
18 | });
19 | ```
20 |
21 |
22 |
23 | {{> edit-demo penSlug="OYzKJx"}}
24 |
25 |
26 |
27 | {{! --------------------------------------------- }}
28 |
29 |
Cone
30 |
31 |
A square cylinder with circular bases. Set size with diameter
and length
. Default diameter: 1, length: 1, fill: true
. Set the color of the base ellipse with backface
. The origin of the hemisphere is the center of the base. The dome faces front toward positive z-axis.
32 |
33 |
34 |
35 | ``` js
36 | let partyHat = new Zdog.Cone({
37 | addTo: illo,
38 | diameter: 70,
39 | length: 90,
40 | stroke: false,
41 | color: '#636',
42 | backface: '#C25',
43 | });
44 | ```
45 |
46 |
47 |
48 | {{> edit-demo penSlug="vwpoEy"}}
49 |
50 |
51 |
52 | {{! --------------------------------------------- }}
53 |
54 |
Cylinder
55 |
56 |
A square cylinder with circular bases. Set size with diameter
and length
. Defaults diameter: 1, length: 1, fill: true
. Set the color of the base ellipse with backface
. The origin of the cylinder is the center of its length. The cylinder is oriented front-to-back along the z-axis.
57 |
58 |
59 |
60 | ``` js
61 | let can = new Zdog.Cylinder({
62 | addTo: illo,
63 | diameter: 80,
64 | length: 120,
65 | stroke: false,
66 | color: '#C25',
67 | backface: '#E62',
68 | });
69 | ```
70 |
71 |
72 |
73 | {{> edit-demo penSlug="wbpVBp"}}
74 |
75 |
76 |
77 |
For different base colors, set frontFace
and backface
78 |
79 |
80 |
81 | ``` js
82 | let can = new Zdog.Cylinder({
83 | addTo: illo,
84 | diameter: 80,
85 | length: 120,
86 | stroke: false,
87 | color: '#C25',
88 | frontFace: '#EA0',
89 | backface: '#636',
90 | });
91 | ```
92 |
93 |
94 |
95 |
96 |
97 |
98 | {{! --------------------------------------------- }}
99 |
100 |
Box
101 |
102 |
A rectangular prism. Set size with width
, height
, and depth
. Set face colors with face options: frontFace
, rearFace
, leftFace
, rightFace
, topFace
, and bottomFace
. Defaults width: 1, height: 1, depth: 1, fill: true
103 |
104 |
105 |
106 | ``` js
107 | let box = new Zdog.Box({
108 | addTo: illo,
109 | width: 120,
110 | height: 100,
111 | depth: 80,
112 | stroke: false,
113 | color: '#C25', // default face color
114 | leftFace: '#EA0',
115 | rightFace: '#E62',
116 | topFace: '#ED0',
117 | bottomFace: '#636',
118 | });
119 | ```
120 |
121 |
122 |
123 | {{> edit-demo penSlug="qGpeOO"}}
124 |
125 |
126 |
127 |
Remove face shapes by disabling face options.
128 |
129 |
130 |
131 | ``` js
132 | let box = new Zdog.Box({
133 | addTo: illo,
134 | width: 120,
135 | height: 100,
136 | depth: 80,
137 | stroke: false,
138 | color: '#C25',
139 | // remove left & right faces
140 | leftFace: false,
141 | rightFace: false,
142 | rearFace: '#EA0',
143 | topFace: '#ED0',
144 | bottomFace: '#636',
145 | });
146 | ```
147 |
148 |
149 |
150 | {{> edit-demo penSlug="GayVpE"}}
151 |
152 |
153 |
--------------------------------------------------------------------------------
/modules/docs/shapes-shape.hbs:
--------------------------------------------------------------------------------
1 |
Shape
2 |
3 |
Shape class for custom shapes. The shape of a Shape
is defined by its path
.
4 |
5 | {{! --------------------------------------------- }}
6 |
7 |
path
8 |
9 |
Defines the shape.
10 |
11 |
When unset, path
defaults to a single point. With stroke
set, a single point renders as a sphere.
12 |
13 |
14 |
15 | ``` js
16 | new Zdog.Shape({
17 | addTo: illo,
18 | // no path set, default to single point
19 | stroke: 80,
20 | color: '#636',
21 | });
22 | ```
23 |
24 |
25 |
26 | {{> edit-demo penSlug="eayapz"}}
27 |
28 |
29 |
30 | {{! --------------------------------------------- }}
31 |
32 |
Path commands
33 |
34 |
Set path
to Array of path commands. Path commands set the directions for the path to shape. Similar to drawing a path in 2D <canvas>
, SVG paths , or Logo’s turtle graphics .
35 |
36 |
There are four path commands: line
, move
, arc
, and bezier
. Each command is set as an Object with the key of the command and value of a vector Object or an Array of vector Object s representing the command points.
37 |
38 |
39 | ``` js
40 | path: [
41 | { line: {/*x,y,z*/} }, // verbose syntax
42 | // or
43 | {/*x,y,z*/}, // line shorthand is just the point
44 |
45 | { move: {/*x,y,z*/} },
46 |
47 | { arc: [
48 | {/*x,y,z*/}, // corner point
49 | {/*x,y,z*/}, // end point
50 | ]},
51 |
52 | { bezier: [
53 | {/*x,y,z*/}, // start control point
54 | {/*x,y,z*/}, // end control point
55 | {/*x,y,z*/}, // end point
56 | ]},
57 | ]
58 | ```
59 |
60 |
To start the path shape, the first path command is always treated as move
.
61 |
62 | {{! --------------------------------------------- }}
63 |
64 |
line
65 |
66 | ``` js
67 | { line: {/*x,y,z*/} }, // verbose syntax
68 | // or
69 | {/*x,y,z*/}, // line shorthand is just the point
70 | ```
71 |
72 |
73 |
74 | ``` js
75 | new Zdog.Shape({
76 | addTo: illo,
77 | path: [
78 | { x: -40 }, // start at 1st point
79 | { x: 40 }, // line to 2nd point
80 | ],
81 | stroke: 20,
82 | color: '#636',
83 | });
84 | ```
85 |
86 |
87 |
88 | {{> edit-demo penSlug="BeJezE"}}
89 |
90 |
91 |
92 |
93 |
94 | ``` js
95 | // z-shape
96 | new Zdog.Shape({
97 | addTo: illo,
98 | path: [
99 | { x: -32, y: -40 }, // start at top left
100 | { x: 32, y: -40 }, // line to top right
101 | { x: -32, y: 40 }, // line to bottom left
102 | { x: 32, y: 40 }, // line to bottom right
103 | ],
104 | closed: false,
105 | stroke: 20,
106 | color: '#636',
107 | });
108 | ```
109 |
110 |
111 |
112 | {{> edit-demo penSlug="eayadB"}}
113 |
114 |
115 |
116 |
Path points can use z
coordinates to form 3D shapes.
117 |
118 |
119 |
120 | ``` js
121 | // 3D shape
122 | new Zdog.Shape({
123 | addTo: illo,
124 | path: [
125 | { x: -32, y: -40, z: 40 },
126 | { x: 32, y: -40 },
127 | { x: 32, y: 40, z: 40 },
128 | { x: 32, y: 40, z: -40 },
129 | ],
130 | closed: false,
131 | stroke: 20,
132 | color: '#636',
133 | });
134 | ```
135 |
136 |
137 |
138 | {{> edit-demo penSlug="GayajP"}}
139 |
140 |
141 |
142 | {{! --------------------------------------------- }}
143 |
144 |
move
145 |
146 | ``` js
147 | { move: {/*x,y,z*/} },
148 | ```
149 |
150 |
151 |
152 | ``` js
153 | new Zdog.Shape({
154 | addTo: illo,
155 | path: [
156 | { x: -40, y: -32 }, // start at top left
157 | { x: 40, y: -32 }, // line to top right
158 | { move: { x: -40, y: 32 } }, // move to bottom left
159 | { x: 40, y: 32 }, // line to bottom right
160 | ],
161 | closed: false,
162 | stroke: 20,
163 | color: '#636',
164 | });
165 | ```
166 |
167 |
168 |
169 | {{> edit-demo penSlug="NVXZxb"}}
170 |
171 |
172 |
173 | {{! --------------------------------------------- }}
174 |
175 |
arc
176 |
177 | ``` js
178 | { arc: [
179 | {/*x,y,z*/}, // corner point
180 | {/*x,y,z*/}, // end point
181 | ]},
182 | ```
183 |
184 |
Renders an elliptical curve. The ellipse of the curve fits within a rectangle formed by the previous, corner, and end points.
185 |
186 |
187 |
188 | ``` js
189 | new Zdog.Shape({
190 | addTo: illo,
191 | path: [
192 | { x: -60, y: -60 }, // start
193 | { arc: [
194 | { x: 20, y: -60 }, // corner
195 | { x: 20, y: 20 }, // end point
196 | ]},
197 | { arc: [ // start next arc from last end point
198 | { x: 20, y: 60 }, // corner
199 | { x: 60, y: 60 }, // end point
200 | ]},
201 | ],
202 | closed: false,
203 | stroke: 20,
204 | color: '#636'
205 | });
206 | ```
207 |
208 |
209 |
210 | {{> edit-demo penSlug="joYjqw"}}
211 |
212 |
213 |
214 | {{! --------------------------------------------- }}
215 |
216 |
bezier
217 |
218 | ``` js
219 | { bezier: [
220 | {/*x,y,z*/}, // start control point
221 | {/*x,y,z*/}, // end control point
222 | {/*x,y,z*/}, // end point
223 | ]},
224 | ```
225 |
226 |
Renders a bezier curve.
227 |
228 |
229 |
230 | ``` js
231 | new Zdog.Shape({
232 | addTo: illo,
233 | path: [
234 | { x: -60, y: -60 }, // start
235 | { bezier: [
236 | { x: 20, y: -60 }, // start control point
237 | { x: 20, y: 60 }, // end control point
238 | { x: 60, y: 60 }, // end point
239 | ]},
240 | ],
241 | closed: false,
242 | stroke: 20,
243 | color: '#636'
244 | });
245 | ```
246 |
247 |
248 |
249 | {{> edit-demo penSlug="xNpoVQ"}}
250 |
251 |
252 |
253 | {{! --------------------------------------------- }}
254 |
255 |
closed
256 |
257 |
Closes the path from the last point back to the first. Enabled by default
.
258 |
259 |
260 |
261 | ``` js
262 | new Zdog.Shape({
263 | addTo: illo,
264 | path: [ // triangle
265 | { x: 0, y: -40 },
266 | { x: 40, y: 40 },
267 | { x: -40, y: 40 },
268 | ],
269 | // closed by default
270 | stroke: 20,
271 | color: '#636'
272 | });
273 | ```
274 |
275 |
276 |
277 | {{> edit-demo penSlug="eaywzM"}}
278 |
279 |
280 |
281 |
282 |
283 | ``` js
284 | new Zdog.Shape({
285 | addTo: illo,
286 | path: [
287 | { x: 0, y: -40 },
288 | { x: 40, y: 40 },
289 | { x: -40, y: 40 },
290 | ],
291 | closed: false, // unclosed
292 | stroke: 20,
293 | color: '#636'
294 | });
295 | ```
296 |
297 |
298 |
299 | {{> edit-demo penSlug="qGpzNg"}}
300 |
301 |
302 |
--------------------------------------------------------------------------------
/modules/docs/vector-objects.hbs:
--------------------------------------------------------------------------------
1 |
A vector Object is a plain ol' JavaScript Object with x
, y
, z
coordinate properties. The coordinate properties are optional. They default to 0
if undefined. So you only need to set non-zero values.
2 |
--------------------------------------------------------------------------------
/modules/edit-demo/edit-demo.css:
--------------------------------------------------------------------------------
1 | /* edit-demo
2 | ------------------------- */
3 |
4 | .edit-demo {
5 | margin: 8px 0;
6 | }
7 |
8 | .edit-demo a {
9 | display: block;
10 | padding: 2px 4px;
11 | border-radius: 4px;
12 | border: none !important;
13 | font-size: 0.9rem;
14 | }
15 |
16 | .edit-demo .codepen-icon {
17 | vertical-align: top;
18 | stroke: #E62;
19 | }
20 |
21 | .edit-demo a:visited .codepen-icon {
22 | stroke: #C25;
23 | }
24 |
25 | .edit-demo a:hover .codepen-icon {
26 | stroke: #636;
27 | }
28 |
--------------------------------------------------------------------------------
/modules/edit-demo/edit-demo.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 | Edit this demo on CodePen
8 |
9 |
10 |
--------------------------------------------------------------------------------
/modules/example/eval-shape-demo.js:
--------------------------------------------------------------------------------
1 | /* jshint evil: true */
2 |
3 | ZdogDocs.evalShapeDemo = function( elem ) {
4 |
5 | var isAnimating = false;
6 |
7 | var illo = new Zdog.Illustration({
8 | element: elem.querySelector('.illo'),
9 | dragRotate: true,
10 | onDragStart: function() {
11 | isAnimating = true;
12 | animate();
13 | },
14 | onDragEnd: function() {
15 | isAnimating = false;
16 | },
17 | });
18 |
19 | var exampleCode = elem.querySelector('.example__code');
20 | eval( exampleCode.textContent );
21 |
22 | function animate() {
23 | illo.updateGraph();
24 | illo.renderGraph();
25 | if ( isAnimating ) {
26 | requestAnimationFrame( animate );
27 | }
28 | }
29 |
30 | animate();
31 | };
32 |
--------------------------------------------------------------------------------
/modules/example/eval-spin-demo.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.evalSpinDemo = function( example ) {
2 | /* jshint evil: true */
3 | var isSpinning = true;
4 | var isDragging = false;
5 | var didDrag = false;
6 | var illoElem = example.querySelector('.illo');
7 |
8 | var illo = new Zdog.Illustration({
9 | element: illoElem,
10 | dragRotate: true,
11 | onDragStart: function() {
12 | isSpinning = false;
13 | isDragging = true;
14 | didDrag = true;
15 | animate();
16 | },
17 | onDragEnd: function() {
18 | isDragging = false;
19 | },
20 | });
21 |
22 | var exampleCode = example.querySelector('.example__code');
23 | eval( exampleCode.textContent );
24 |
25 | function animate() {
26 | if ( isSpinning ) {
27 | illo.rotate.y += 0.03;
28 | }
29 | illo.updateRenderGraph();
30 | if ( isSpinning || isDragging ) {
31 | requestAnimationFrame( animate );
32 | }
33 | }
34 |
35 | // ----- IntersectionObserver ----- //
36 |
37 | // start animation if no IntObs
38 | if ( !ZdogDocs.supportsIntObs ) {
39 | animate();
40 | }
41 |
42 | ZdogDocs.observeIntersect({
43 | element: illoElem,
44 | onIntersect: function( isIntersect ) {
45 | if ( didDrag ) {
46 | return;
47 | }
48 | isSpinning = isIntersect;
49 | if ( isSpinning ) {
50 | animate();
51 | }
52 | }
53 | });
54 |
55 | };
56 |
--------------------------------------------------------------------------------
/modules/example/example.css:
--------------------------------------------------------------------------------
1 | /* example
2 | ------------------------- */
3 |
4 | .example {
5 | margin: 1.0rem 0;
6 | }
7 |
8 | .example__code {
9 | margin: 0 0 1.0rem 0;
10 | }
11 |
12 | .example__code pre {
13 | margin: 0;
14 | }
15 |
16 | .example__code pre + pre {
17 | margin-top: 1.0rem;
18 | }
19 |
20 | @media screen and ( min-width: 640px ) {
21 |
22 | .example {
23 | display: flex;
24 | }
25 |
26 | /* disable flex */
27 | .example--stacked {
28 | display: block;
29 | }
30 |
31 | .example__code {
32 | flex-grow: 1;
33 | margin: 0 1.0rem 0 0;
34 | }
35 |
36 | .example--stacked .example__code {
37 | margin: 0 0 1.0rem 0;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/modules/gh-button/gh-button.css:
--------------------------------------------------------------------------------
1 | /* gh-button
2 | ------------------------- */
3 |
4 | .gh-button {
5 | display: inline-block;
6 | background: none;
7 | border: none;
8 | color: #333;
9 | font-size: 1.1rem;
10 | }
11 |
12 | .container .gh-button {
13 | color: #333;
14 | }
15 |
16 | .gh-button__title,
17 | .gh-button__stat {
18 | float: left;
19 | font-weight: bold;
20 | line-height: 20px;
21 | padding: 5px 10px;
22 | border: 1px solid #d5d5d5;
23 | }
24 |
25 | .gh-button__icon,
26 | .gh-button .github-logo {
27 | height: 21px;
28 | fill: #333;
29 | display: inline-block;
30 | vertical-align: bottom;
31 | }
32 |
33 | .gh-button__title {
34 | background-color: #eee;
35 | background-image: linear-gradient(#fcfcfc, #eee);
36 | border-radius: 4px 0 0 4px;
37 | }
38 |
39 | .gh-button .github-logo {
40 | margin-right: 0.2em;
41 | }
42 |
43 | .gh-button__stat {
44 | border-left: 0;
45 | border-radius: 0 4px 4px 0;
46 | background: white;
47 | }
48 |
49 | .gh-button:hover { color: #333; }
50 |
51 | .gh-button:hover .gh-button__title {
52 | background-color: #ddd;
53 | background-image: linear-gradient(#eee, #ddd);
54 | }
55 |
56 | .gh-button:hover .gh-button__stat {
57 | color: #4078c0;
58 | }
59 |
60 | .gh-button:hover .gh-button__icon--star {
61 | fill: #4078c0;
62 | }
63 |
--------------------------------------------------------------------------------
/modules/gh-button/gh-button.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{project}} on GitHub
7 |
8 |
9 |
10 |
11 |
12 | {{stars}}
13 |
14 |
15 |
--------------------------------------------------------------------------------
/modules/gh-button/gh-button.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | var ghButtonGUID = 0;
4 |
5 | ZdogDocs.ghButton = function( elem ) {
6 |
7 | var hrefParts = elem.href.split('/');
8 | var user = hrefParts[3];
9 | var repo = hrefParts[4];
10 | var statTextElem = elem.querySelector('.gh-button__stat__text');
11 |
12 | // get data
13 | ghButtonGUID++;
14 | var callbackName = 'ghButtonCallback' + ghButtonGUID;
15 |
16 | window[ callbackName ] = function( response ) {
17 | var starText = addCommas( response.data.stargazers_count );
18 | statTextElem.textContent = starText;
19 | };
20 |
21 | function addCommas( num ) {
22 | return num.toString().replace( /(\d)(?=(\d{3})+$)/g, '$1,' );
23 | }
24 |
25 | // create & load script
26 | var script = document.createElement('script');
27 | script.src = 'https://api.github.com/repos/' + user + '/' + repo +
28 | '?callback=' + callbackName;
29 | document.head.appendChild( script );
30 |
31 | };
32 |
33 | })();
34 |
--------------------------------------------------------------------------------
/modules/grid4/grid4.css:
--------------------------------------------------------------------------------
1 | /* grid4
2 | ------------------------- */
3 |
4 | .grid4 {
5 | display: grid;
6 | grid-template-columns: repeat(4, 1fr);
7 | grid-column-gap: 1.0rem;
8 | grid-row-gap: 1.0rem;
9 | }
10 |
--------------------------------------------------------------------------------
/modules/hashed-header/hashed-header.css:
--------------------------------------------------------------------------------
1 | /* hashed-header
2 | ------------------------- */
3 |
4 | .hashed-header {
5 | position: relative;
6 | }
7 |
8 | .hashed-header__link {
9 | position: absolute;
10 | }
11 |
12 | .hashed-header__link::before {
13 | position: absolute;
14 | right: 0;
15 | padding-right: 5px;
16 | content: '#';
17 | opacity: 0;
18 | }
19 |
20 | .hashed-header:hover .hashed-header__link::before {
21 | content: '#';
22 | opacity: 1;
23 | }
24 |
--------------------------------------------------------------------------------
/modules/hero/hero.css:
--------------------------------------------------------------------------------
1 | /* hero
2 | ------------------------- */
3 |
4 | .hero__title {
5 | font-size: 3.0rem;
6 | color: #EA0;
7 | margin: 0;
8 | }
9 |
10 | .hero__tagline {
11 | margin: 0 0 0.5rem;
12 | font-size: 1.2rem;
13 | font-weight: bold;
14 | color: #636;
15 | }
16 |
17 | @media screen and ( min-width: 768px ) {
18 |
19 | .hero__masthead {
20 | display: flex;
21 | align-items: center;
22 | height: 170px;
23 | }
24 |
25 | .hero__title {
26 | font-size: 6.0rem;
27 | line-height: 1;
28 | color: #EA0;
29 | }
30 |
31 | .hero__tagline {
32 | font-size: 1.6rem;
33 | line-height: 1.1;
34 | margin: 5px 0 0;
35 | padding-left: 40px;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/modules/hero/hero.hbs:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 | {{> gh-button project="Zdog" ghPath="metafizzy/zdog" stars="7500"}}
8 |
9 |
10 |
--------------------------------------------------------------------------------
/modules/illo-showcase/illo-showcase.css:
--------------------------------------------------------------------------------
1 | /* illo-showcase
2 | ------------------------- */
3 |
4 | .illo-showcase {
5 | margin: 20px 0;
6 | }
7 |
8 | .illo-showcase__illo {
9 | width: 100%;
10 | }
11 |
--------------------------------------------------------------------------------
/modules/illo-showcase/illo-showcase.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
9 |
10 |
11 |
13 |
14 |
15 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/modules/illo/illo.css:
--------------------------------------------------------------------------------
1 | /* illo
2 | ------------------------- */
3 |
4 | .illo {
5 | display: block;
6 | background: #FDB;
7 | border-radius: 8px;
8 | cursor: move;
9 | }
10 |
11 | .illo--no-drag {
12 | cursor: auto;
13 | }
14 |
15 | .illo--fluid-canvas {
16 | display: block;
17 | width: 100%;
18 | }
19 |
--------------------------------------------------------------------------------
/modules/made-with-showcase/made-with-showcase.css:
--------------------------------------------------------------------------------
1 | /* made-with-showcase
2 | ------------------------- */
3 |
4 | .made-with-showcase__item__image {
5 | display: block;
6 | max-width: 100%;
7 | border-radius: 8px;
8 | }
9 |
--------------------------------------------------------------------------------
/modules/made-with-showcase/made-with-showcase.hbs:
--------------------------------------------------------------------------------
1 |
2 | {{#each made_with_examples}}
3 |
9 | {{/each}}
10 |
11 |
--------------------------------------------------------------------------------
/modules/masthead/masthead.css:
--------------------------------------------------------------------------------
1 | /* masthead
2 | ------------------------- */
3 |
4 | .masthead {
5 | display: flex;
6 | }
7 |
8 | .masthead__logo {
9 | width: 180px;
10 | margin-right: 10px;
11 | }
12 |
13 | @media screen and ( min-width: 768px ) {
14 |
15 | .masthead {
16 | display: block;
17 | }
18 |
19 | .masthead__logo {
20 | width: auto;
21 | margin: 0;
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/modules/nav/nav.css:
--------------------------------------------------------------------------------
1 | /* nav
2 | ------------------------- */
3 |
4 | @media screen and ( min-width: 768px ) and ( min-height: 550px ) {
5 | .nav {
6 | position: -webkit-sticky;
7 | position: sticky;
8 | top: 10px;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/modules/page-nav/page-nav.css:
--------------------------------------------------------------------------------
1 | /* page-nav
2 | ------------------------- */
3 |
4 | .page-nav {
5 | list-style: none;
6 | margin: 20px 0 0;
7 | padding: 0;
8 | line-height: 1.2;
9 | }
10 |
11 | .page-nav li {
12 | padding: 0;
13 | font-size: 0.9rem;
14 | }
15 |
16 | .page-nav li a {
17 | display: block;
18 | padding: 4px 10px;
19 | border-radius: 4px;
20 | }
21 |
22 | .page-nav li.page-nav__item--h3 a {
23 | padding-left: 20px;
24 | }
25 |
--------------------------------------------------------------------------------
/modules/site-footer/site-footer.css:
--------------------------------------------------------------------------------
1 | /* site-footer
2 | ------------------------- */
3 |
4 | .site-footer {
5 | margin: 4rem 0 3rem;
6 | display: block;
7 | }
8 |
9 | .site-footer__mfzy-link {
10 | display: inline-block;
11 | padding-left: 8px;
12 | padding-right: 8px;
13 | border-radius: 8px;
14 | }
15 |
16 | .site-footer__brought {
17 | display: inline-block;
18 | font-size: 1.2rem;
19 | vertical-align: top;
20 | padding-top: 0.4rem;
21 | padding-right: 0.5rem;
22 | }
23 |
24 | .mfzy-wordmark {
25 | stroke: #C25;
26 | }
27 |
28 | .site-footer__mfzy-link:hover .mfzy-wordmark {
29 | stroke: #333;
30 | }
31 |
--------------------------------------------------------------------------------
/modules/site-footer/site-footer.hbs:
--------------------------------------------------------------------------------
1 |
71 |
--------------------------------------------------------------------------------
/modules/site-nav/site-nav.css:
--------------------------------------------------------------------------------
1 | /* site-nav
2 | ------------------------- */
3 |
4 | .site-nav {
5 | list-style: none;
6 | margin: 0;
7 | padding: 0;
8 | }
9 |
10 | .site-nav__item {
11 | font-size: 1.15rem;
12 | font-weight: bold;
13 | line-height: 1.2;
14 | }
15 |
16 | .site-nav__item a {
17 | text-decoration: none;
18 | padding: 7px 10px;
19 | display: block;
20 | border-radius: 8px;
21 | }
22 |
23 | .site-nav__item.is-selected a {
24 | color: #636;
25 | background: #FDB;
26 | }
27 |
28 | /* ---- homepage ---- */
29 |
30 | .site-nav__item--index { font-size: 2.0rem; }
31 | .site-nav__item--index a {
32 | color: #EA0;
33 | padding-top: 2px;
34 | padding-bottom: 2px;
35 | }
36 |
37 | @media screen and ( min-width: 768px ) {
38 |
39 | .site-nav {
40 | margin: 10px 0 0;
41 | }
42 |
43 | .site-nav__item--index.is-selected a {
44 | color: white;
45 | background: transparent;
46 | }
47 |
48 | }
49 |
50 | .site-nav__item a:hover {
51 | color: #636;
52 | background: #EA0;
53 | }
54 |
--------------------------------------------------------------------------------
/modules/site-nav/site-nav.hbs:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/modules/site-nav/site-nav.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.siteNav = function( elem ) {
2 | var basename = document.body.getAttribute('data-basename');
3 | var className = '.site-nav__item--' + basename;
4 | var selectedItem = elem.querySelector( className );
5 | if ( selectedItem ) {
6 | selectedItem.classList.add('is-selected');
7 | }
8 | };
9 |
--------------------------------------------------------------------------------
/modules/socks-promo/socks-promo.css:
--------------------------------------------------------------------------------
1 | /* socks-promo
2 | ------------------------- */
3 |
4 | .socks-promo {
5 | margin: 40px 0;
6 | }
7 |
8 | .socks-promo__link {
9 | display: flex;
10 | border-radius: 8px;
11 | }
12 |
13 | .socks-promo__image {
14 | display: block;
15 | max-width: 100%;
16 | border-radius: 5px;
17 | }
18 |
19 | .socks-promo__cell:last-child { padding-left: 1.0rem; }
20 |
--------------------------------------------------------------------------------
/modules/socks-promo/socks-promo.hbs:
--------------------------------------------------------------------------------
1 |
15 |
--------------------------------------------------------------------------------
/modules/zdog-logo/zdog-logo.css:
--------------------------------------------------------------------------------
1 | /* zdog-logo
2 | ------------------------- */
3 |
4 | .zdog-logo {
5 | border-radius: 50%;
6 | max-width: 100%;
7 | }
8 |
--------------------------------------------------------------------------------
/modules/zdog-logo/zdog-logo.hbs:
--------------------------------------------------------------------------------
1 |
3 |
--------------------------------------------------------------------------------
/modules/zdog-logo/zdog-logo.js:
--------------------------------------------------------------------------------
1 | ZdogDocs.zdogLogo = function( elem ) {
2 |
3 | // variables
4 | var initRotate = { x: 20/360 * TAU, y: -50/360 * TAU };
5 | var isSpinning = false;
6 | var isAnimating = false;
7 |
8 | var illo = new Zdog.Illustration({
9 | element: elem,
10 | zoom: 1.75,
11 | rotate: initRotate,
12 | dragRotate: true,
13 | onDragStart: function() {
14 | isAnimating = true;
15 | isSpinning = false;
16 | animate();
17 | },
18 | onDragEnd: function() {
19 | isAnimating = false;
20 | },
21 | });
22 |
23 | var depth = 20;
24 | var lineWidth = 8;
25 |
26 | // ----- model ----- //
27 |
28 | var bigGroup = new Zdog.Group({
29 | addTo: illo,
30 | });
31 |
32 | var backGroup = new Zdog.Group({
33 | addTo: bigGroup,
34 | updateSort: true,
35 | });
36 |
37 |
38 | // top
39 | var topSide = new Zdog.Rect({
40 | addTo: backGroup,
41 | width: 40,
42 | height: depth,
43 | translate: { y: -20 },
44 | rotate: { x: TAU/4 },
45 | fill: true,
46 | stroke: lineWidth,
47 | color: orange,
48 | });
49 | topSide.copy({
50 | translate: { y: 20 },
51 | rotate: { x: -TAU/4 },
52 | });
53 |
54 | var endCap = new Zdog.Rect({
55 | addTo: backGroup,
56 | width: depth,
57 | height: 8,
58 | translate: { x: -20, y: -16 },
59 | rotate: { y: TAU/4 },
60 | fill: true,
61 | color: orange,
62 | stroke: lineWidth,
63 | backface: false,
64 | });
65 | endCap.copy({
66 | translate: { x: 20, y: 16 },
67 | rotate: { y: -TAU/4 },
68 | });
69 |
70 | var cornerCap = endCap.copy({
71 | height: 10,
72 | translate: { x: -20, y: 15 },
73 | });
74 | cornerCap.copy({
75 | translate: { x: 20, y: -15 },
76 | rotate: { y: -TAU/4 },
77 | });
78 |
79 | var underside = new Zdog.Rect({
80 | addTo: backGroup,
81 | width: 30,
82 | height: depth,
83 | translate: { x: -5, y: -12 },
84 | rotate: { x: -TAU/4 },
85 | stroke: lineWidth,
86 | fill: true,
87 | color: orange,
88 | });
89 | underside.copy({
90 | translate: { x: 5, y: 12 },
91 | rotate: { x: TAU/4 },
92 | });
93 |
94 | var slopeW = 30;
95 | var slopeH = 22;
96 | var slopeAngle = Math.atan( slopeH/slopeW );
97 |
98 | var slope = new Zdog.Rect({
99 | addTo: backGroup,
100 | width: Math.sqrt( slopeH*slopeH + slopeW*slopeW ),
101 | height: depth,
102 | translate: { x: -5, y: -1 },
103 | rotate: { x: TAU/4, y: slopeAngle },
104 | stroke: lineWidth,
105 | fill: true,
106 | color: orange,
107 | backface: false,
108 | });
109 |
110 | slope.copy({
111 | translate: { x: 5, y: 1 },
112 | rotate: { x: -TAU/4, y: -slopeAngle },
113 | });
114 |
115 | // tail
116 | new Zdog.Ellipse({
117 | addTo: backGroup,
118 | diameter: 32,
119 | quarters: 1,
120 | closed: false,
121 | translate: { x: 22, y: -4 },
122 | rotate: { z: TAU/4 },
123 | color: orange,
124 | stroke: lineWidth,
125 | });
126 |
127 | // tongue
128 |
129 | var tongueAnchor = new Zdog.Anchor({
130 | addTo: backGroup,
131 | translate: { x: -6, y: -7 },
132 | rotate: { y: TAU/4 },
133 |
134 | });
135 |
136 | var tongueH = 12;
137 | var tongueS = 5;
138 | var tongueTip = tongueH + tongueS;
139 |
140 | new Zdog.Shape({
141 | addTo: tongueAnchor,
142 | path: [
143 | { x: -tongueS, y: 0 },
144 | { x: tongueS, y: 0 },
145 | { x: tongueS, y: tongueH },
146 | { arc: [
147 | { x: tongueS, y: tongueTip },
148 | { x: 0, y: tongueTip }
149 | ]},
150 | { arc: [
151 | { x: -tongueS, y: tongueTip },
152 | { x: -tongueS, y: tongueH }
153 | ]},
154 | ],
155 | rotate: { x: TAU/4 - Math.atan(16/22) },
156 | fill: true,
157 | stroke: 4,
158 | color: eggplant,
159 |
160 | });
161 |
162 | var foreGroup = new Zdog.Group({
163 | addTo: bigGroup,
164 | updateSort: true,
165 | });
166 |
167 | var zFace = new Zdog.Shape({
168 | addTo: foreGroup,
169 | path: [
170 | { x: -20, y: -20 },
171 | { x: 20, y: -20 },
172 | { x: 20, y: -10 },
173 | { x: -10, y: 12 },
174 | { x: 20, y: 12 },
175 | { x: 20, y: 20 },
176 | { x: -20, y: 20 },
177 | { x: -20, y: 10 },
178 | { x: 10, y: -12 },
179 | { x: -20, y: -12 },
180 | ],
181 | translate: { z: depth/2 },
182 | fill: true,
183 | color: gold,
184 | stroke: lineWidth,
185 | backface: false,
186 | });
187 |
188 | zFace.copy({
189 | scale: { x: -1 },
190 | translate: { z: -depth/2 },
191 | rotate: { y: TAU/2 },
192 | });
193 |
194 | // nose
195 | var semiCircle = new Zdog.Ellipse({
196 | addTo: backGroup,
197 | quarters: 2,
198 | scale: 8,
199 | translate: { x: -26, y: -20 },
200 | rotate: { y: TAU/4, z: TAU/4 },
201 | fill: true,
202 | stroke: 5,
203 | color: eggplant,
204 | closed: true,
205 | // backface: false,
206 | });
207 |
208 | // ears
209 | // group & extra shape are hacks
210 | var earGroup = new Zdog.Group({
211 | addTo: illo,
212 | });
213 |
214 | var ear = semiCircle.copy({
215 | addTo: earGroup,
216 | quarters: 2,
217 | scale: 24,
218 | rotate: { z: -TAU/16, x: TAU/16 },
219 | translate: { x: 10, y: -14, z: depth },
220 | });
221 |
222 | new Zdog.Shape({
223 | visible: false,
224 | addTo: ear,
225 | translate: { z: 0.5, x: -0.5 },
226 | });
227 |
228 | earGroup.copyGraph({
229 | scale: { z: -1 },
230 | });
231 |
232 | // ----- animate ----- //
233 |
234 | var t = 0;
235 | var tSpeed = 1/180;
236 |
237 | function animate() {
238 | // update
239 | if ( isSpinning ) {
240 | var turn = Math.floor( t % 2 );
241 | if ( turn == 0 ) {
242 | illo.rotate.y = Zdog.easeInOut( t, 4 ) * TAU + initRotate.y;
243 | } else if ( turn == 1 ) {
244 | illo.rotate.z = Zdog.easeInOut( t, 4 ) * TAU;
245 | }
246 | t += tSpeed;
247 | }
248 | illo.updateRenderGraph();
249 | // animate next frame
250 | if ( isAnimating ) {
251 | requestAnimationFrame( animate );
252 | }
253 | }
254 |
255 | animate();
256 |
257 | };
258 |
--------------------------------------------------------------------------------
/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "build"
3 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zdog-docs",
3 | "version": "1.1.0",
4 | "description": "Documentation site for Zdog",
5 | "main": "gulpfile.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "David DeSandro",
11 | "license": "MIT",
12 | "dependencies": {
13 | "gulp": "^4.0.2",
14 | "gulp-concat": "^2.6.1",
15 | "gulp-front-matter": "^1.3.0",
16 | "gulp-hb": "^7.1.0",
17 | "gulp-jshint": "^2.1.0",
18 | "gulp-rename": "^1.4.0",
19 | "gulp-replace": "^1.0.0",
20 | "gulp-uglify": "^3.0.2",
21 | "highlight.js": "^10.4.1",
22 | "jshint": "^2.10.2",
23 | "transfob": "^1.0.0",
24 | "zdog": "^1.1.2"
25 | },
26 | "devDependencies": {},
27 | "repository": {
28 | "type": "git",
29 | "url": "git+https://github.com/metafizzy/zdog-docs.git"
30 | },
31 | "bugs": {
32 | "url": "https://github.com/metafizzy/zdog-docs/issues"
33 | },
34 | "homepage": "https://github.com/metafizzy/zdog-docs#readme"
35 | }
36 |
--------------------------------------------------------------------------------
/tasks/assets.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | gulp.task( 'assets', function() {
4 | return gulp.src('assets/**/*.*')
5 | .pipe( gulp.dest('build') );
6 | });
7 |
8 | module.exports = function() {};
9 |
--------------------------------------------------------------------------------
/tasks/content.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const rename = require('gulp-rename');
3 | const frontMatter = require('gulp-front-matter');
4 | const path = require('path');
5 | const transfob = require('transfob');
6 | const pageNav = require('./utils/page-nav');
7 | const highlightCodeBlock = require('./utils/highlight-code-block');
8 | const hb = require('gulp-hb');
9 |
10 | // sources
11 | let contentSrc = 'content/**/*.hbs';
12 | let partialsSrc = [
13 | // 'bower_components/fizzy-docs-modules/*/*.hbs',
14 | 'modules/*/*.hbs',
15 | 'demos/*/*.hbs',
16 | ];
17 | let dataSrc = 'data/*.json';
18 | let pageTemplateSrc = 'templates/*.hbs';
19 | let contentSrcs = [ contentSrc, pageTemplateSrc, dataSrc ]
20 | .concat( partialsSrc );
21 |
22 | // ----- page template ----- //
23 |
24 | module.exports = function( site ) {
25 |
26 | let pageTemplate;
27 |
28 | gulp.task( 'getPageTemplate', function() {
29 | return gulp.src('templates/page.hbs')
30 | .pipe( transfob( function( file, enc, next ) {
31 | pageTemplate = file.contents.toString();
32 | next( null, file );
33 | }));
34 | });
35 |
36 | gulp.task( 'buildPages', function() {
37 |
38 | return gulp.src( contentSrc )
39 | .pipe( frontMatter({
40 | property: 'data.page',
41 | remove: true
42 | }) )
43 | .pipe( transfob( function( file, enc, next ) {
44 | // add file path data
45 | file.rootPath = path.relative( file.path, file.cwd + '/content/' )
46 | .replace( /\.\.$/, '' );
47 | file.basename = path.basename( file.path, '.hbs' );
48 | // wrap contents in page template
49 | let contents = file.contents.toString();
50 | contents = pageTemplate.replace( '{{{main}}}', contents );
51 | file.contents = Buffer.from( contents );
52 | next( null, file );
53 | }))
54 | .pipe( hb()
55 | .partials( pageTemplateSrc )
56 | .partials( partialsSrc, {
57 | parsePartialName: function( options, file ) {
58 | return path.basename( file.path, '.hbs' );
59 | }
60 | } )
61 | .data( dataSrc )
62 | .data( site.data )
63 | // .helpers( helpers )
64 | )
65 | .pipe( pageNav() )
66 | .pipe( highlightCodeBlock() )
67 | .pipe( rename({ extname: '.html' }) )
68 | .pipe( gulp.dest('build') );
69 | });
70 |
71 | let content = gulp.series( 'getPageTemplate', 'buildPages' );
72 |
73 | gulp.task( 'content', content );
74 |
75 | if ( site.data.dev ) {
76 | gulp.watch( contentSrcs, content );
77 | }
78 |
79 | };
80 |
--------------------------------------------------------------------------------
/tasks/css.js:
--------------------------------------------------------------------------------
1 | const gulp = require('gulp');
2 | const concat = require('gulp-concat');
3 | const replace = require('gulp-replace');
4 | const getGlobPaths = require('./utils/get-glob-paths');
5 |
6 | const cssSrc = [
7 | 'base/fonts.css',
8 | 'base/base.css',
9 | 'base/syntax-highlight.css',
10 | 'modules/*/*.css',
11 | 'demos/*/*.css',
12 | ];
13 |
14 | gulp.task( 'css', function() {
15 | return gulp.src( cssSrc )
16 | .pipe( replace( '../assets/fonts/', 'fonts/' ) )
17 | .pipe( concat('zdog-docs.css') )
18 | .pipe( gulp.dest('build') );
19 | });
20 |
21 | module.exports = function( site ) {
22 | site.data.stylesheets = getGlobPaths( cssSrc );
23 | };
24 |
--------------------------------------------------------------------------------
/tasks/hint.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var jshint = require('gulp-jshint');
3 |
4 | gulp.task( 'hint-js', function() {
5 | return gulp.src([ 'base/*.js', 'modules/**/*/*.js', 'demos/**/*/*.js' ])
6 | .pipe( jshint() )
7 | .pipe( jshint.reporter('default') );
8 | });
9 |
10 | gulp.task( 'hint-tasks', function() {
11 | return gulp.src([ 'gulpfile.js', 'tasks/*.js' ])
12 | .pipe( jshint() )
13 | .pipe( jshint.reporter('default') );
14 | });
15 |
16 | gulp.task( 'hint', gulp.parallel( 'hint-js', 'hint-tasks' ) );
17 |
18 | module.exports = function() {};
19 |
--------------------------------------------------------------------------------
/tasks/js.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var concat = require('gulp-concat');
3 | var uglify = require('gulp-uglify');
4 | var getGlobPaths = require('./utils/get-glob-paths');
5 |
6 | var jsSrc = [
7 | // Zdog
8 | 'node_modules/zdog/js/boilerplate.js',
9 | 'node_modules/zdog/js/canvas-renderer.js',
10 | 'node_modules/zdog/js/svg-renderer.js',
11 | 'node_modules/zdog/js/vector.js',
12 | 'node_modules/zdog/js/anchor.js',
13 | 'node_modules/zdog/js/path-command.js',
14 | 'node_modules/zdog/js/shape.js',
15 | 'node_modules/zdog/js/group.js',
16 | 'node_modules/zdog/js/rect.js',
17 | 'node_modules/zdog/js/rounded-rect.js',
18 | 'node_modules/zdog/js/ellipse.js',
19 | 'node_modules/zdog/js/polygon.js',
20 | 'node_modules/zdog/js/cone.js',
21 | 'node_modules/zdog/js/cylinder.js',
22 | 'node_modules/zdog/js/hemisphere.js',
23 | 'node_modules/zdog/js/box.js',
24 | 'node_modules/zdog/js/dragger.js',
25 | 'node_modules/zdog/js/illustration.js',
26 | // docs
27 | 'base/boilerplate.js',
28 | // modules
29 | 'modules/*/*.js',
30 | 'demos/*/*.js',
31 | // init
32 | 'base/init.js',
33 | ];
34 |
35 | // concat & minify js
36 | gulp.task( 'js', function() {
37 | return gulp.src( jsSrc )
38 | .pipe( uglify() )
39 | .pipe( concat('zdog-docs.min.js') )
40 | .pipe( gulp.dest('build') );
41 | });
42 |
43 | module.exports = function( site ) {
44 | site.data.jsPaths = getGlobPaths( jsSrc );
45 | };
46 |
--------------------------------------------------------------------------------
/tasks/utils/get-glob-paths.js:
--------------------------------------------------------------------------------
1 | var glob = require('glob');
2 |
3 | /**
4 | * takes glob src and returns expanded paths
5 | * @param {Array} src
6 | * @returns {Array} paths
7 | */
8 | module.exports = function getGlobPaths( src ) {
9 | var paths = [];
10 | // expand paths
11 | src.forEach( function( path ) {
12 | if ( glob.hasMagic( path ) ) {
13 | var files = glob.sync( path );
14 | paths = paths.concat( files )
15 | } else {
16 | paths.push( path );
17 | }
18 | });
19 |
20 | return paths;
21 | };
22 |
--------------------------------------------------------------------------------
/tasks/utils/highlight-code-block.js:
--------------------------------------------------------------------------------
1 | var highlightjs = require('highlight.js');
2 | var transfob = require('transfob');
3 |
4 | highlightjs.configure({
5 | classPrefix: ''
6 | });
7 |
8 | var hljsJavascript = highlightjs.getLanguage('javascript');
9 | // highlight Zdog classes
10 | hljsJavascript.contains.push({
11 | className: 'zdog_class',
12 | begin: `Zdog\\.\\w+`,
13 | });
14 |
15 | hljsJavascript.keywords.demo_var = 'illo anchor rect circle shape';
16 |
17 | function replaceCodeBlock( whiteSpace, block ) {
18 | if ( !block ) {
19 | return '';
20 | }
21 | var langMatch = block.match( /^ *([\w]+)\n/ );
22 | var language = langMatch && langMatch[1];
23 | // remove first line
24 | block = block.replace( /.*\n/, '' );
25 | // remove leading whitespace from code block
26 | if ( whiteSpace && whiteSpace.length ) {
27 | var reWhiteSpace = new RegExp( '^' + whiteSpace, 'gim' );
28 | block = block.replace( reWhiteSpace, '' );
29 | }
30 | // highlight code
31 | var highlighted = block;
32 | if ( language ) {
33 | highlighted = highlightjs.highlight( language, block, true ).value;
34 | }
35 | var codeAttr = language ? `class="${language}"` : '';
36 | return `
${highlighted}
\n`;
37 | }
38 |
39 | module.exports = function() {
40 | return transfob( function( file, enc, next ) {
41 | var contents = file.contents.toString();
42 | // split contents by ```, get leading white space
43 | var blocks = contents.split( /\n( *)```/ );
44 | var hiContent = '';
45 | for ( var i=0; i < blocks.length; i += 4 ) {
46 | var normBlock = blocks[i];
47 | var whitespace = blocks[ i + 1 ] || '';
48 | var codeBlock = blocks[ i + 2 ] || '';
49 | codeBlock = replaceCodeBlock( whitespace, codeBlock );
50 | hiContent += `${normBlock}\n${codeBlock}`;
51 | }
52 | file.contents = Buffer.from( hiContent );
53 | next( null, file );
54 | });
55 | };
56 |
--------------------------------------------------------------------------------
/tasks/utils/page-nav.js:
--------------------------------------------------------------------------------
1 | const transfob = require('transfob');
2 |
3 | // get
title
4 | const reHeader = /\n
([^<]+)<\/h[23]>/gi;
5 |
6 | module.exports = function pageNav() {
7 | return transfob( function( file, enc, next ) {
8 | let contents = file.contents.toString();
9 | // add to @file.pageNavItems
10 | // const pageNavItems = [];
11 | let navItems = [];
12 | let h2Slug;
13 | // insert slugs into headers
14 | contents = contents.replace( reHeader, function( full, number, title ) {
15 | // remove HTML entities &
16 | let slug = title.replace( /&\w+;/gi, '' )
17 | // replace non-alphanumeric characters with dashes
18 | .replace( /[^\w]+/gi, '-' )
19 | // trim trailing hyphens
20 | .replace( /^\-/, '' ).replace( /\-$/, '' ).toLowerCase();
21 |
22 | if ( number == '2' ) {
23 | // create page-nav html
24 | navItems.push(`
25 | ${title} `);
26 | h2Slug = slug;
27 | } else {
28 | // prefix h2 slug on h3 slugs
29 | slug = `${h2Slug}-${slug}`;
30 | }
31 |
32 | return `\n`;
34 | });
35 |
36 | // insert page-nav HTML
37 | let pageNavHTML = '\n' +
38 | navItems.join('\n') + '\n ';
39 | contents = contents.replace( '', pageNavHTML );
40 |
41 | file.contents = Buffer.from( contents );
42 | next( null, file );
43 | });
44 | };
45 |
--------------------------------------------------------------------------------
/templates/page.hbs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Zdog · {{#if page.homepage}}{{description}}{{else}}{{page.title}}{{/if}}
9 |
10 | {{#if dev}}
11 | {{#each stylesheets}}
12 |
13 | {{/each}}
14 | {{else}}
15 |
16 | {{/if}}
17 |
18 | {{! Twitter Cards }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
40 |
41 |
42 | {{#if page.homepage}}
43 | {{> hero}}
44 | {{/if}}
45 |
46 | {{#if page.title}}
47 |
{{page.title}}
48 | {{/if}}
49 | {{{main}}}
50 |
51 | {{> site-footer }}
52 |
53 |
54 |
{{! .container }}
55 |
56 | {{#if dev}}
57 | {{#each jsPaths}}
58 |
59 | {{/each}}
60 | {{else}}
61 |
62 | {{/if}}
63 |
64 | {{#unless dev}}
65 |
69 |
70 | {{/unless}}
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------