├── .gitignore ├── README.md ├── css ├── reset.css └── main.css ├── LICENSE ├── js ├── sphere.js └── header.js └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .svn 3 | log/*.log 4 | tmp/** 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Sphere 2 | 3 | When bored, I sometimes open a blank JavaScript 4 | file and start writing without any clear objective 5 | of where I want to take it. This is the result of one 6 | such coding session. 7 | 8 | After some fiddling and minification I was able to 9 | squeeze the JavaScript source into 372 bytes. 10 | 11 | Curious about how this looks in action? [Check out the live demo.](http://hakim.se/experiments/html5/sphere). 12 | 13 | # License 14 | 15 | MIT licensed 16 | 17 | Copyright (C) 2017 Hakim El Hattab, http://hakim.se -------------------------------------------------------------------------------- /css/reset.css: -------------------------------------------------------------------------------- 1 | html{color:#000;background:#222222;} 2 | a{cursor:pointer;} 3 | html,body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;} 4 | table{border-collapse:collapse;border-spacing:0;} 5 | fieldset,img{border:0;} 6 | address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;} 7 | li{list-style:none;} 8 | caption,th{text-align:left;} 9 | /* h1,h2,h3,h4,h5,h6{font-size:100%;} */ 10 | q:before,q:after{content:'';} 11 | abbr,acronym {border:0;font-variant:normal;} 12 | sup {vertical-align:text-top;} 13 | sub {vertical-align:text-bottom;} 14 | input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;outline-style:none;outline-width:0pt;} 15 | legend{color:#000;} 16 | a:focus,object,h1,h2,h3,h4,h5,h6{-moz-outline-style: none; border:0px;} 17 | /*input[type="Submit"]{cursor:pointer;}*/ 18 | strong {font-weight: bold;} 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2017 Hakim El Hattab, http://hakim.se 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /js/sphere.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Draws a particle sphere/spiral on canvas. 3 | * 4 | * @author Hakim El Hattab | http://hakim.se 5 | */ 6 | (function(){ 7 | var d = document, 8 | canvas = d.body.appendChild( d.createElement( 'canvas' ) ), 9 | context = canvas.getContext( '2d' ), 10 | time = 0, 11 | w = 1, 12 | h = 1, 13 | cos = Math.cos, 14 | sin = Math.sin, 15 | PI = Math.PI; 16 | 17 | function resize() { 18 | canvas.width = w = innerWidth; 19 | canvas.height = h = innerHeight; 20 | } 21 | 22 | // Monitor browser resize 23 | addEventListener( 'resize', resize, false ); 24 | 25 | // Initial size 26 | resize(); 27 | 28 | // The main animation loop 29 | setInterval( function() { 30 | context.clearRect( 0, 0, w, h ); 31 | context.fillStyle = 'rgba(0,255,255,.5)'; 32 | context.globalCompositeOperation = 'lighter'; 33 | 34 | time += .1; 35 | 36 | // The number of particles to generate 37 | i = 10000; 38 | 39 | while( i-- ) { 40 | // The magic 41 | r = ( ( w + h ) * 0.4 ) * ( cos( ( time + i ) * ( .05 + ( ( sin(time*0.00002) / PI ) * .2 ) ) ) / PI ); 42 | 43 | context.fillRect( sin(i) * r + (w/2), 44 | cos(i) * r + (h/2), 45 | 1, 46 | 1 ); 47 | } 48 | }, 16 ); 49 | })() -------------------------------------------------------------------------------- /js/header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Controls the showing and hiding of the expandable 3 | * header. 4 | * 5 | * @author Hakim El Hattab / http://hakim.se 6 | */ 7 | window.onload = function() { 8 | 9 | var header = document.getElementsByTagName('header')[0]; 10 | var headerToggleTimeOut = -1; 11 | var headerMouseDown = false; 12 | 13 | document.addEventListener( 'mousedown', function() { 14 | headerMouseDown = true; 15 | }, false ); 16 | 17 | document.addEventListener( 'mouseup', function() { 18 | headerMouseDown = false; 19 | }, false ); 20 | 21 | header.addEventListener('mouseover', function() { 22 | if (!headerMouseDown) { 23 | // Make sure no previous call to toggle the header are 24 | // queued up 25 | clearTimeout( headerToggleTimeOut ); 26 | 27 | // Avoid accidentally opening the header by setting 28 | // a short time out 29 | headerToggleTimeOut = setTimeout( function() { 30 | header.setAttribute( 'class', 'open' ) 31 | }, 100 ); 32 | } 33 | }, false); 34 | 35 | header.addEventListener('mouseout', function() { 36 | // Make sure no previous call to toggle the header are 37 | // queued up 38 | clearTimeout( headerToggleTimeOut ); 39 | 40 | // Avoid accidentally closing the header by setting 41 | // a short time out 42 | headerToggleTimeOut = setTimeout( function() { 43 | header.setAttribute( 'class', '' ) 44 | }, 100 ); 45 | }, false); 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Sphere 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 |

Sphere

22 | Expand for more info. 23 | 24 | 25 |
26 | 27 | 28 |
29 |

About

30 |

31 | When bored, I sometimes open a blank JavaScript
32 | file and start writing without any clear objective
33 | of where I want to take it. This is the result of one
34 | such coding session. 35 |

36 |

37 | Created by Hakim El Hattab | @hakimel 38 |

39 |
40 | 41 |
42 |

Source

43 |

44 | After some fiddling and minification I was able to
45 | squeeze the JavaScript source into 372 bytes.
46 | You can find the source on GitHub. 47 |

48 |
49 | 50 | 51 |
52 |

Share

53 | 54 |
55 | 56 | 57 |
58 |
59 | 60 |
61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /********************************************* 4 | * GLOBAL 5 | *********************************************/ 6 | 7 | body, html { 8 | overflow: hidden; 9 | font-family: Helvetica, Arial, sans-serif; 10 | color: #fff; 11 | font-size: 11px; 12 | background: #010c12; 13 | } 14 | 15 | 16 | /********************************************* 17 | * HEADER 18 | *********************************************/ 19 | 20 | header { 21 | position: relative; 22 | width: 100%; 23 | height: 27px; 24 | margin: 0; 25 | padding: 0 8px 8px 8px; 26 | overflow: hidden; 27 | z-index: 5; 28 | 29 | background: rgba( 60, 60, 60, 0.5 ); 30 | color: #eee; 31 | 32 | -webkit-transition: height .22s ease-out; 33 | -moz-transition: height .22s ease-out; 34 | -o-transition: height .22s ease-out; 35 | transition: height .22s ease-out; 36 | } 37 | 38 | header.open { 39 | height: 165px; 40 | } 41 | 42 | header h1 { 43 | font-family: Molengo, Helvetica, Arial, sans-serif; 44 | float: left; 45 | margin-top: 1px; 46 | } 47 | 48 | header .header-instruction { 49 | float: left; 50 | margin: 12px 0 0 15px; 51 | 52 | font-size: 10px; 53 | font-style: italic; 54 | color: #999; 55 | 56 | -webkit-transition: opacity .18s linear; 57 | -moz-transition: opacity .18s linear; 58 | -o-transition: opacity .18s linear; 59 | transition: opacity .18s linear; 60 | } 61 | header.open .header-instruction { 62 | opacity: 0; 63 | } 64 | header div.extra { 65 | margin: 45px 0 0 20px; 66 | clear: both; 67 | 68 | -webkit-transition: opacity .18s linear; 69 | -moz-transition: opacity .18s linear; 70 | -o-transition: opacity .18s linear; 71 | transition: opacity .18s linear; 72 | } 73 | header div.extra h3 { 74 | margin-bottom: 10px; 75 | } 76 | header a { 77 | padding: 2px 4px 2px 2px; 78 | color: #999; 79 | 80 | -webkit-transition: all .1s ease-out; 81 | -moz-transition: all .1s ease-out; 82 | -o-transition: all .1s ease-out; 83 | transition: all .1s ease-in; 84 | } 85 | header a:hover { 86 | padding: 2px 4px 2px 2px; 87 | 88 | color: #ddd; 89 | background-color: #333; 90 | border-radius: 1px; 91 | } 92 | header section { 93 | height: 120px; 94 | padding: 0 25px; 95 | float: left; 96 | 97 | border-left: 1px #333 solid; 98 | } 99 | header p { 100 | margin-bottom: 5px; 101 | 102 | font-size: 12px; 103 | letter-spacing: 0.05em; 104 | } 105 | #about { 106 | padding-left: 0; 107 | border: none; 108 | } 109 | #about p.credits { 110 | margin: 15px 0 2px 0; 111 | 112 | font-style: italic; 113 | color: #666; 114 | font-size: 11px; 115 | line-height: 1.4em; 116 | } 117 | #about a:hover { 118 | padding: 2px 10px 2px 8px; 119 | } 120 | #share iframe, 121 | #share div { 122 | display: inline-block; 123 | } 124 | #retweet-button { 125 | margin-right: 6px; 126 | } 127 | 128 | a[href="http://www.w3counter.com"] { 129 | display: none!important; 130 | } 131 | 132 | .no-canvas { 133 | color: #999999; 134 | font-size: 24px; 135 | text-align: center; 136 | margin-top: 150px; 137 | } 138 | 139 | 140 | /********************************************* 141 | * EXPERIMENT STYLES 142 | *********************************************/ 143 | 144 | canvas { 145 | z-index: 1; 146 | } 147 | 148 | #background { 149 | border: none; 150 | z-index: 0; 151 | } 152 | 153 | .ui { 154 | font-family: Arial, Helvetica, sans-serif; 155 | font-size: 10px; 156 | color: #999999; 157 | text-align: left; 158 | padding: 8px; 159 | background-color: rgba(0,0,0,0.5); 160 | float: left; 161 | } 162 | 163 | #status { 164 | width: 884px; 165 | height: 15px; 166 | padding: 8px; 167 | display: none; 168 | position: absolute; 169 | z-index: 2; 170 | } 171 | 172 | #status span { 173 | color: #bbbbbb; 174 | font-weight: bold; 175 | margin-right: 5px; 176 | } 177 | 178 | #status .fps { 179 | float: right; 180 | } 181 | 182 | #panels { 183 | width: 100%; 184 | position: absolute; 185 | z-index: 3; 186 | } 187 | 188 | #message { 189 | padding: 16px; 190 | margin-top: 10px; 191 | width: 225px; 192 | } 193 | 194 | .ui h2 { 195 | margin-bottom: 20px; 196 | color: #eeeeee; 197 | } 198 | 199 | .ui ul { 200 | margin: 10px 0; 201 | } 202 | 203 | .ui ul li { 204 | margin: 0 0 2px 0; 205 | } 206 | 207 | .ui a { 208 | outline: none; 209 | font-family: Arial, Helvetica, sans-serif; 210 | font-size: 38px; 211 | text-decoration: none; 212 | color: #bbbbbb; 213 | padding: 2px; 214 | display: block; 215 | transition: all .18s linear; 216 | -o-transition: all .18s linear; 217 | -moz-transition: all .18s linear; 218 | -webkit-transition: all .18s linear; 219 | } 220 | 221 | .ui a:hover { 222 | color: #ffffff; 223 | background-color: #000000; 224 | transition: all .18s linear; 225 | -o-transition: all .18s linear; 226 | -moz-transition: all .18s linear; 227 | -webkit-transition: all .18s linear; 228 | } 229 | 230 | .ui a.external { 231 | outline: none; 232 | font-family: Arial, Helvetica, sans-serif; 233 | font-size: 10px; 234 | font-weight: bold; 235 | text-decoration: none; 236 | color: #bbbbbb; 237 | display: inline; 238 | padding: 0; 239 | } 240 | 241 | .ui a.external:hover { 242 | color: #ffffff; 243 | } 244 | 245 | --------------------------------------------------------------------------------