├── .babelrc ├── .browserslistrc ├── .editorconfig ├── .gitignore ├── LICENSE ├── README.md ├── assets ├── images │ └── .gitkeep ├── scripts │ ├── app.js │ ├── globals.js │ ├── modules.js │ ├── modules │ │ ├── DistortionExample.js │ │ ├── Example.js │ │ ├── GlImage.js │ │ ├── Gui.js │ │ ├── Load.js │ │ └── Scroll.js │ ├── shaders │ │ ├── distortionFragment.js │ │ └── distortionVertex.js │ ├── utils │ │ ├── array.js │ │ ├── debounce.js │ │ ├── environment.js │ │ ├── html.js │ │ ├── is.js │ │ ├── maths.js │ │ ├── transform.js │ │ └── visibility.js │ └── vendors │ │ └── .gitkeep └── styles │ ├── components │ ├── _button.scss │ ├── _form.scss │ ├── _gl-image.scss │ ├── _heading.scss │ └── _scrollbar.scss │ ├── elements │ ├── _fonts.scss │ └── _page.scss │ ├── generic │ ├── _button.scss │ ├── _form.scss │ ├── _generic.scss │ └── _media.scss │ ├── main.scss │ ├── objects │ ├── _container.scss │ ├── _crop.scss │ ├── _layout.scss │ ├── _ratio.scss │ ├── _scroll.scss │ └── _table.scss │ ├── settings │ ├── _config.colors.scss │ └── _config.scss │ ├── templates │ └── .gitkeep │ ├── tools │ ├── _family.scss │ ├── _fonts.scss │ ├── _functions.scss │ ├── _layout.scss │ ├── _mixins.scss │ └── _widths.scss │ ├── utilities │ ├── _align.scss │ ├── _helpers.scss │ ├── _print.scss │ ├── _ratio.scss │ ├── _spacing.scss │ ├── _states.scss │ └── _widths.scss │ └── vendors │ └── .gitkeep ├── build ├── build.js ├── concat.js ├── error.js ├── notify.js ├── scripts.js ├── serve.js ├── styles.js ├── svgs.js └── watch.js ├── docs ├── axis.jpg └── positionExample.jpg ├── gulpfile.babel.js ├── mconfig.json ├── package-lock.json ├── package.json └── www ├── assets ├── emails │ └── index.html ├── fonts │ └── .gitkeep ├── images │ ├── favicons │ │ ├── android-chrome-144x144.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── mstile-150x150.png │ │ └── safari-pinned-tab.svg │ ├── image-1.jpg │ ├── image-2.jpg │ ├── image-3.jpg │ ├── image-4.jpg │ ├── linear-h-displacement.jpg │ ├── linear-v-displacement.jpg │ ├── radial-displacement.jpg │ └── radial-displacement.png ├── scripts │ ├── app.js │ ├── app.js.map │ └── vendors.js └── styles │ └── main.css ├── browserconfig.xml ├── example └── index.html ├── favicon.ico ├── index.html └── site.webmanifest /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.browserslistrc: -------------------------------------------------------------------------------- 1 | defaults 2 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 4 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [{*.yml,*.json}] 16 | indent_size = 2 17 | indent_style = space 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | Thumbs.db 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Locomotive, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Description 3 | Simple example to implement easily images rendered with WebGL. You just need to create a wrap, set its width and height with css, and the images will get the same dimensions. 4 | 5 | 6 | ## Installation 7 | ```sh 8 | npm i 9 | ``` 10 | 11 | ## Run 12 | ```sh 13 | gulp 14 | ``` 15 | 16 | ## Usage 17 | 18 | ### HTML 19 | ```html 20 |
21 |
22 |
23 | ``` 24 | 25 | ### CSS 26 | ```css 27 | .c-gl-image { 28 | width: 500px; //Can be in %, vw etc.. 29 | height: 390px; 30 | } 31 | ``` 32 | 33 | ## Options 34 | 35 | | Attribute | Values | Description | 36 | | --------- | ------ | ----------- | 37 | | `data-gl-image-texture` | url | Image you want to display | 38 | | `data-gl-image-displacement` | url | Texture you want for a displacement (example: linear or radial gradient, The brighter the pixel, the more the z-axis is affected) | 39 | | `data-gl-image-factor` | integer | Value to manage the intensity of the displacement | 40 | | `data-gl-image-gap` | integer | % of the canvas width to have a gap. Prevent an `overflow: hidden` style and allow to see the effect on the borders| 41 | 42 | 43 | ## Examples 44 | ### Radial displacement texture 45 | ![](https://raw.githubusercontent.com//locomotivemtl/webgl-images/master/www/assets/images/radial-displacement.jpg) 46 | 47 | ### Axis 48 | ![](https://raw.githubusercontent.com//locomotivemtl/webgl-images/master/docs/axis.jpg) 49 | 50 | ### Displacement Position 0,0 51 | ![](https://raw.githubusercontent.com//locomotivemtl/webgl-images/master/docs/positionExample.jpg) 52 | 53 | 54 | ## Dependencies 55 | 56 | - [OGL](https://github.com/oframe/ogl/) 57 | - [Locomotive Boilerplate](https://github.com/locomotivemtl/locomotive-boilerplate) 58 | - [Locomotive Scroll](https://github.com/locomotivemtl/locomotive-scroll) 59 | -------------------------------------------------------------------------------- /assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/assets/images/.gitkeep -------------------------------------------------------------------------------- /assets/scripts/app.js: -------------------------------------------------------------------------------- 1 | import modular from 'modujs'; 2 | import * as modules from './modules'; 3 | import globals from './globals'; 4 | import { html } from './utils/environment'; 5 | 6 | const app = new modular({ 7 | modules: modules 8 | }); 9 | 10 | app.init(app); 11 | globals(); 12 | 13 | html.classList.add('is-loaded', 'is-ready'); 14 | html.classList.remove('is-loading'); 15 | 16 | -------------------------------------------------------------------------------- /assets/scripts/globals.js: -------------------------------------------------------------------------------- 1 | import svg4everybody from 'svg4everybody'; 2 | 3 | export default function() { 4 | svg4everybody(); 5 | } 6 | -------------------------------------------------------------------------------- /assets/scripts/modules.js: -------------------------------------------------------------------------------- 1 | export {default as Load} from './modules/Load'; 2 | export {default as Scroll} from './modules/Scroll'; 3 | export {default as GlImage} from './modules/GlImage'; 4 | export {default as DistortionExample} from './modules/DistortionExample'; 5 | export {default as Gui} from './modules/Gui'; 6 | -------------------------------------------------------------------------------- /assets/scripts/modules/DistortionExample.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | import vertexShader from '../shaders/distortionVertex'; 3 | import fragmentShader from '../shaders/distortionFragment'; 4 | import {Renderer, Camera, Transform, Texture, Vec2, Plane, Program, Mesh } from 'ogl'; 5 | 6 | const CLASS = { 7 | LOADING: 'is-loading' 8 | } 9 | 10 | export default class extends module { 11 | constructor(m) { 12 | super(m); 13 | 14 | this.el.classList.add(CLASS.LOADING); 15 | 16 | this.textureSrc = this.getData('texture'); 17 | this.displacementSrc = this.getData('displacement'); 18 | this.gap = this.getData('gap'); 19 | 20 | this.windowWidth = window.innerWidth; 21 | this.windowHeight = window.innerHeight; 22 | 23 | // El and webgl plane BCR 24 | this.BCR = this.el.getBoundingClientRect(); 25 | this.planeBCR = { 26 | width: 1, 27 | height: 1, 28 | x: 0, 29 | y: 0 30 | } 31 | 32 | // Useful booleans 33 | this.inView = true; 34 | this.isLoaded = false; 35 | this.isRenderable = false; 36 | 37 | // Positions 38 | this.displacementPosition = new Vec2(0,0); 39 | this.mouse = new Vec2(0,0); 40 | 41 | this.settings = { 42 | factor: 0, 43 | factorAim: this.getData('factor'), 44 | scale: 0 45 | } 46 | 47 | } 48 | 49 | init() { 50 | 51 | this.$wrap = this.$('wrap')[0]; 52 | 53 | // Init ogl renderer 54 | this.renderer = new Renderer({dpr: 2, antialias: true, alpha: true}); 55 | this.renderer.setSize(this.BCR.width, this.BCR.height); 56 | 57 | this.gl = this.renderer.gl; 58 | this.$wrap.appendChild(this.gl.canvas); 59 | 60 | this.initScene(); 61 | this.initCamera(); 62 | this.initShape(); 63 | 64 | this.isRenderable = true; 65 | this.tl = new TimelineMax({ 66 | repeat: -1, 67 | onUpdate: () => { 68 | this.formatPosition({ 69 | x: this.mouse.x, 70 | y: this.mouse.y, 71 | obj: this.displacementPosition 72 | }); 73 | this.call('updateProgress',this.tl.progress(),'Gui'); 74 | } 75 | }); 76 | this.settings.factor = this.settings.factorAim; 77 | this.tl.to(this.mouse,1,{ 78 | x:1, 79 | y:1, 80 | }); 81 | this.tl.to(this.mouse,1,{ 82 | x:0, 83 | y:0, 84 | }); 85 | 86 | } 87 | 88 | initScene() { 89 | this.scene = new Transform(); 90 | } 91 | 92 | initCamera() { 93 | this.fov = 75; 94 | this.camera = new Camera(this.glElement, {fov: this.fov}); 95 | this.camera.position.set(0,0,1); 96 | } 97 | 98 | initShape() { 99 | 100 | this.geometry = new Plane(this.gl,{width: 1, height: 1, widthSegments: 10, heightSegments: 10}); 101 | 102 | const texture = new Texture(this.gl, {minFilter: this.gl.LINEAR}); 103 | 104 | const displacementTexture = new Texture(this.gl, {minFilter: this.gl.LINEAR}); 105 | const displacementImg = new Image(); 106 | displacementImg.src = this.displacementSrc; 107 | 108 | displacementImg.onload = () => { 109 | displacementTexture.image = displacementImg; 110 | 111 | const img = new Image(); 112 | img.src = this.textureSrc; 113 | img.onload = () => { 114 | texture.image = img; 115 | 116 | this.program = new Program(this.gl, { 117 | vertex: vertexShader, 118 | fragment: fragmentShader, 119 | uniforms: { 120 | displacementTexture : { value: displacementTexture }, 121 | displacement:{ value: this.displacementPosition }, 122 | texture : { value: texture }, 123 | factor: { value: this.settings.factor } 124 | } 125 | }); 126 | 127 | this.mesh = new Mesh(this.gl, {geometry: this.geometry, program: this.program}); 128 | 129 | this.updateSize(); 130 | this.isLoaded = true; 131 | this.el.classList.remove(CLASS.LOADING); 132 | 133 | this.render(); 134 | 135 | }; 136 | }; 137 | 138 | 139 | } 140 | 141 | calculateUnitSize(distance){ 142 | const vFov = this.fov * Math.PI / 180; 143 | const height = (2 * Math.tan(vFov / 2) * distance); 144 | const width = height * this.camera.aspect; 145 | 146 | return { 147 | width, 148 | height 149 | } 150 | } 151 | 152 | updateSize() { 153 | this.camUnit = this.calculateUnitSize(this.camera.position.z); 154 | 155 | // Set size @update 156 | this.planeBCR.width = this.camUnit.width - (this.camUnit.width * (this.gap / 100)); 157 | this.planeBCR.height = this.planeBCR.width / this.camera.aspect; 158 | 159 | this.geometry = new Plane(this.gl,{width: this.planeBCR.width, height: this.planeBCR.height, widthSegments: 100, heightSegments: 100}); 160 | this.mesh.geometry = this.geometry; 161 | 162 | this.gl.canvas.style.width = `${this.BCR.width}px`; 163 | this.gl.canvas.style.height = `${this.BCR.height}px`; 164 | } 165 | 166 | formatPosition(param) { 167 | param.obj.x = -(param.x) + 0.5; 168 | param.obj.y = param.y - 0.5 169 | } 170 | 171 | render(t) { 172 | this.raf = requestAnimationFrame((t)=>this.render(t)); 173 | 174 | if(this.isLoaded && this.isRenderable) { 175 | 176 | this.program.uniforms.displacement.value = this.displacementPosition; 177 | 178 | this.program.uniforms.factor.value = this.settings.factor; 179 | } 180 | 181 | this.renderer.render({scene: this.mesh, camera: this.camera}); 182 | } 183 | 184 | resize() { 185 | const newBCR = this.el.getBoundingClientRect() 186 | if(this.BCR && this.BCR.top == newBCR.top && this.BCR.height == newBCR.height) return 187 | this.BCR = newBCR 188 | 189 | this.windowWidth = window.innerWidth; 190 | this.windowHeight = window.innerHeight; 191 | 192 | this.renderer.setSize(this.BCR.width, this.BCR.height); 193 | this.camera.perspective({aspect: this.gl.canvas.width / this.gl.canvas.height}); 194 | this.updateSize(); 195 | } 196 | 197 | scroll() { 198 | const newBCR = this.el.getBoundingClientRect() 199 | if(this.BCR && this.BCR.top == newBCR.top && this.BCR.height == newBCR.height) return 200 | this.BCR = newBCR; 201 | 202 | } 203 | 204 | updateFactor(factor) { 205 | this.settings.factor = factor; 206 | } 207 | updateProgress(progress) { 208 | this.tl.progress(progress); 209 | } 210 | 211 | updatePlay(value) { 212 | if(value) { 213 | this.tl.play(); 214 | } else { 215 | this.tl.pause(); 216 | } 217 | } 218 | 219 | destroy() { 220 | super.destroy(); 221 | cancelAnimationFrame(this.raf); 222 | window.removeEventListener('resize', this.resizeBind); 223 | document.removeEventListener('scroll', this.scrollBind); 224 | } 225 | } 226 | -------------------------------------------------------------------------------- /assets/scripts/modules/Example.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | 3 | export default class extends module { 4 | constructor(m) { 5 | super(m); 6 | } 7 | 8 | init() { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /assets/scripts/modules/GlImage.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | import vertexShader from '../shaders/distortionVertex'; 3 | import fragmentShader from '../shaders/distortionFragment'; 4 | import {Renderer, Camera, Transform, Texture, Vec2, Plane, Program, Mesh } from 'ogl'; 5 | 6 | const CLASS = { 7 | LOADING: 'is-loading' 8 | } 9 | 10 | export default class extends module { 11 | constructor(m) { 12 | super(m); 13 | 14 | this.el.classList.add(CLASS.LOADING); 15 | 16 | this.textureSrc = this.getData('texture'); 17 | this.displacementSrc = this.getData('displacement'); 18 | this.gap = this.getData('gap'); 19 | 20 | this.windowWidth = window.innerWidth; 21 | this.windowHeight = window.innerHeight; 22 | 23 | this.events = { 24 | mousemove: { 25 | wrap: 'mousemove' 26 | }, 27 | mouseenter: { 28 | wrap: 'mouseenter' 29 | }, 30 | mouseleave: { 31 | wrap: 'mouseleave' 32 | } 33 | } 34 | 35 | // El and webgl plane BCR 36 | this.BCR = this.el.getBoundingClientRect(); 37 | this.planeBCR = { 38 | width: 1, 39 | height: 1, 40 | x: 0, 41 | y: 0 42 | } 43 | 44 | // Useful booleans 45 | this.inView = true; 46 | this.isLoaded = false; 47 | this.isRenderable = false; 48 | 49 | // Positions 50 | this.displacementPosition = new Vec2(-0.5,-0.5); 51 | this.mouse = new Vec2(-0.5,-0.5); 52 | 53 | this.settings = { 54 | factor: 0, 55 | factorAim: this.getData('factor'), 56 | scale: 0 57 | } 58 | 59 | } 60 | 61 | init() { 62 | 63 | this.$wrap = this.$('wrap')[0]; 64 | 65 | // Init ogl renderer 66 | this.renderer = new Renderer({dpr: 2, antialias: true, alpha: true}); 67 | this.renderer.setSize(this.BCR.width, this.BCR.height); 68 | 69 | this.gl = this.renderer.gl; 70 | this.$wrap.appendChild(this.gl.canvas); 71 | 72 | this.initScene(); 73 | this.initCamera(); 74 | this.initShape(); 75 | 76 | this.scrollBind = this.scroll.bind(this); 77 | document.addEventListener('scroll', this.scrollBind); 78 | 79 | this.resizeBind = this.resize.bind(this); 80 | window.addEventListener('resize', this.resizeBind); 81 | } 82 | 83 | initScene() { 84 | this.scene = new Transform(); 85 | } 86 | 87 | initCamera() { 88 | this.fov = 75; 89 | this.camera = new Camera(this.glElement, {fov: this.fov}); 90 | this.camera.position.set(0,0,1); 91 | } 92 | 93 | initShape() { 94 | 95 | this.geometry = new Plane(this.gl,{width: 1, height: 1, widthSegments: 10, heightSegments: 10}); 96 | 97 | const texture = new Texture(this.gl, {minFilter: this.gl.LINEAR}); 98 | 99 | const displacementTexture = new Texture(this.gl, {minFilter: this.gl.LINEAR}); 100 | const displacementImg = new Image(); 101 | displacementImg.src = this.displacementSrc; 102 | 103 | displacementImg.onload = () => { 104 | displacementTexture.image = displacementImg; 105 | 106 | const img = new Image(); 107 | img.src = this.textureSrc; 108 | img.onload = () => { 109 | texture.image = img; 110 | 111 | this.program = new Program(this.gl, { 112 | vertex: vertexShader, 113 | fragment: fragmentShader, 114 | uniforms: { 115 | displacementTexture : { value: displacementTexture }, 116 | displacement:{ value: this.displacementPosition }, 117 | texture : { value: texture }, 118 | factor: { value: this.settings.factor } 119 | } 120 | }); 121 | 122 | this.mesh = new Mesh(this.gl, {geometry: this.geometry, program: this.program}); 123 | 124 | this.updateSize(); 125 | this.isLoaded = true; 126 | this.el.classList.remove(CLASS.LOADING); 127 | this.render(); 128 | 129 | }; 130 | }; 131 | 132 | 133 | } 134 | 135 | calculateUnitSize(distance){ 136 | const vFov = this.fov * Math.PI / 180; 137 | const height = (2 * Math.tan(vFov / 2) * distance); 138 | const width = height * this.camera.aspect; 139 | 140 | return { 141 | width, 142 | height 143 | } 144 | } 145 | 146 | updateSize() { 147 | this.camUnit = this.calculateUnitSize(this.camera.position.z); 148 | 149 | // Set size @update 150 | this.planeBCR.width = this.camUnit.width - (this.camUnit.width * (this.gap / 100)); 151 | this.planeBCR.height = this.planeBCR.width / this.camera.aspect; 152 | 153 | this.geometry = new Plane(this.gl,{width: this.planeBCR.width, height: this.planeBCR.height, widthSegments: 100, heightSegments: 100}); 154 | this.mesh.geometry = this.geometry; 155 | 156 | this.gl.canvas.style.width = `${this.BCR.width}px`; 157 | this.gl.canvas.style.height = `${this.BCR.height}px`; 158 | } 159 | 160 | mouseenter(e) { 161 | this.isRenderable = true; 162 | 163 | this.formatPosition({ 164 | x: (e.clientX - this.BCR.left) / this.BCR.width, 165 | y: (e.clientY - this.BCR.top) / this.BCR.height, 166 | obj: this.mouse 167 | }); 168 | 169 | this.formatPosition({ 170 | x: (e.clientX - this.BCR.left) / this.BCR.width, 171 | y: (e.clientY - this.BCR.top) / this.BCR.height, 172 | obj: this.displacementPosition 173 | }); 174 | 175 | gsap.to(this.settings,0.6,{ 176 | factor: this.settings.factorAim 177 | }); 178 | 179 | } 180 | 181 | mouseleave(e) { 182 | gsap.to(this.settings,0.6,{ 183 | factor: 0, 184 | onComplete: () => { 185 | this.isRenderable = false; 186 | } 187 | }); 188 | 189 | } 190 | 191 | mousemove(e) { 192 | this.formatPosition({ 193 | x: (e.clientX - this.BCR.left) / this.BCR.width, 194 | y: (e.clientY - this.BCR.top) / this.BCR.height, 195 | obj: this.mouse 196 | }); 197 | 198 | this.formatPosition({ 199 | x: (e.clientX - this.BCR.left) / this.BCR.width, 200 | y: (e.clientY - this.BCR.top) / this.BCR.height, 201 | obj: this.displacementPosition 202 | }); 203 | 204 | } 205 | 206 | formatPosition(param) { 207 | param.obj.x = -(param.x) + 0.5; 208 | param.obj.y = param.y - 0.5 209 | } 210 | 211 | render(t) { 212 | this.raf = requestAnimationFrame((t)=>this.render(t)); 213 | 214 | if(this.isLoaded && this.isRenderable) { 215 | 216 | this.program.uniforms.displacement.value = this.displacementPosition; 217 | this.program.uniforms.factor.value = this.settings.factor; 218 | } 219 | 220 | this.renderer.render({scene: this.mesh, camera: this.camera}); 221 | } 222 | 223 | resize() { 224 | const newBCR = this.el.getBoundingClientRect() 225 | if(this.BCR && this.BCR.top == newBCR.top && this.BCR.height == newBCR.height) return 226 | this.BCR = newBCR 227 | 228 | this.windowWidth = window.innerWidth; 229 | this.windowHeight = window.innerHeight; 230 | 231 | this.renderer.setSize(this.BCR.width, this.BCR.height); 232 | this.camera.perspective({aspect: this.gl.canvas.width / this.gl.canvas.height}); 233 | this.updateSize(); 234 | } 235 | 236 | scroll() { 237 | const newBCR = this.el.getBoundingClientRect() 238 | if(this.BCR && this.BCR.top == newBCR.top && this.BCR.height == newBCR.height) return 239 | this.BCR = newBCR; 240 | 241 | } 242 | 243 | destroy() { 244 | super.destroy(); 245 | cancelAnimationFrame(this.raf); 246 | window.removeEventListener('resize', this.resizeBind); 247 | document.removeEventListener('scroll', this.scrollBind); 248 | } 249 | } 250 | -------------------------------------------------------------------------------- /assets/scripts/modules/Gui.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | 3 | export default class extends module { 4 | constructor(m) { 5 | super(m); 6 | 7 | this.settings = { 8 | factor: 1, 9 | progress: 0, 10 | play: true 11 | } 12 | } 13 | 14 | init() { 15 | this.gui = new dat.GUI(); 16 | this.factorController = this.gui.add(this.settings,'factor', -2, 2); 17 | this.progressController = this.gui.add(this.settings,'progress', 0, 1).step(0.01); 18 | this.playController = this.gui.add(this.settings,'play'); 19 | 20 | this.factorController.onChange((value) => { 21 | this.call('updateFactor',value,'DistortionExample') 22 | }); 23 | 24 | this.progressController.onChange((value) => { 25 | this.call('updateProgress',value,'DistortionExample') 26 | }); 27 | 28 | this.playController.onChange((value) => { 29 | this.call('updatePlay',value,'DistortionExample') 30 | }); 31 | } 32 | 33 | updateProgress(progress) { 34 | this.progressController.setValue(progress); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /assets/scripts/modules/Load.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | import modularLoad from 'modularload'; 3 | 4 | export default class extends module { 5 | constructor(m) { 6 | super(m); 7 | } 8 | 9 | init() { 10 | const load = new modularLoad({ 11 | enterDelay: 0, 12 | transitions: { 13 | customTransition: {} 14 | } 15 | }); 16 | 17 | load.on('loaded', (transition, oldContainer, newContainer) => { 18 | this.call('destroy', oldContainer, 'app'); 19 | this.call('update', newContainer, 'app'); 20 | }); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /assets/scripts/modules/Scroll.js: -------------------------------------------------------------------------------- 1 | import { module } from 'modujs'; 2 | import LocomotiveScroll from 'locomotive-scroll'; 3 | 4 | export default class extends module { 5 | constructor(m) { 6 | super(m); 7 | } 8 | 9 | init() { 10 | this.scroll = new LocomotiveScroll({ 11 | el: this.el, 12 | smooth: true 13 | }); 14 | 15 | this.scroll.on('call', (func,way,obj,id) => { 16 | // Using modularJS 17 | this.call(func[0],{way,obj},func[1],func[2]); 18 | }); 19 | 20 | this.scroll.on('scroll', (args) => { 21 | // console.log(args.scroll); 22 | }) 23 | } 24 | 25 | toggleLazy(args) { 26 | let src = this.getData('lazy', args.obj.el) 27 | if(src.length) { 28 | if(args.obj.el.tagName == "IMG") { 29 | args.obj.el.src = src 30 | } else { 31 | args.obj.el.style.backgroundImage = `url(${src})` 32 | } 33 | this.setData('lazy', '', args.obj.el) 34 | } 35 | } 36 | 37 | destroy() { 38 | this.scroll.destroy(); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /assets/scripts/shaders/distortionFragment.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | 3 | precision highp float; 4 | precision highp int; 5 | uniform sampler2D texture; 6 | varying vec2 vUv; 7 | varying vec3 vNormal; 8 | 9 | void main() { 10 | 11 | vec3 normal = normalize(vNormal); 12 | vec3 tex = texture2D(texture, vUv).rgb; 13 | 14 | // vec3 light = normalize(vec3(0.5, 1.0, -0.3)); 15 | // float shading = dot(normal, light) * 0.15; 16 | 17 | gl_FragColor.rgb = tex; 18 | gl_FragColor.a = 1.0; 19 | 20 | gl_FragColor = texture2D(texture, vUv); 21 | 22 | 23 | } 24 | ` 25 | -------------------------------------------------------------------------------- /assets/scripts/shaders/distortionVertex.js: -------------------------------------------------------------------------------- 1 | export default ` 2 | precision highp float; 3 | precision highp int; 4 | attribute vec2 uv; 5 | attribute vec3 position; 6 | attribute vec3 normal; 7 | uniform mat4 modelViewMatrix; 8 | uniform mat4 projectionMatrix; 9 | uniform mat3 normalMatrix; 10 | 11 | uniform sampler2D displacementTexture; 12 | uniform float factor; 13 | uniform float scale; 14 | uniform vec2 displacement; 15 | varying vec2 displacementUv; 16 | varying vec2 vUv; 17 | varying vec3 vNormal; 18 | 19 | void main() { 20 | 21 | // vNormal = normalize(normalMatrix * normal); 22 | 23 | displacementUv = uv + displacement; 24 | vUv = uv; 25 | 26 | vec3 newPosition = vec3(position.x, position.y , position.z + (texture2D(displacementTexture, displacementUv).r * factor * 0.1)); 27 | 28 | gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.); 29 | } 30 | ` 31 | -------------------------------------------------------------------------------- /assets/scripts/utils/array.js: -------------------------------------------------------------------------------- 1 | import { isArray } from './is'; 2 | 3 | export function addToArray ( array, value ) { 4 | const index = array.indexOf( value ); 5 | 6 | if ( index === -1 ) { 7 | array.push( value ); 8 | } 9 | } 10 | 11 | export function arrayContains ( array, value ) { 12 | for ( let i = 0, c = array.length; i < c; i++ ) { 13 | if ( array[i] == value ) { 14 | return true; 15 | } 16 | } 17 | 18 | return false; 19 | } 20 | 21 | export function arrayContentsMatch ( a, b ) { 22 | let i; 23 | 24 | if ( !isArray( a ) || !isArray( b ) ) { 25 | return false; 26 | } 27 | 28 | if ( a.length !== b.length ) { 29 | return false; 30 | } 31 | 32 | i = a.length; 33 | while ( i-- ) { 34 | if ( a[i] !== b[i] ) { 35 | return false; 36 | } 37 | } 38 | 39 | return true; 40 | } 41 | 42 | export function ensureArray ( x ) { 43 | if ( typeof x === 'string' ) { 44 | return [ x ]; 45 | } 46 | 47 | if ( x === undefined ) { 48 | return []; 49 | } 50 | 51 | return x; 52 | } 53 | 54 | export function lastItem ( array ) { 55 | return array[ array.length - 1 ]; 56 | } 57 | 58 | export function removeFromArray ( array, member ) { 59 | if ( !array ) { 60 | return; 61 | } 62 | 63 | const index = array.indexOf( member ); 64 | 65 | if ( index !== -1 ) { 66 | array.splice( index, 1 ); 67 | } 68 | } 69 | 70 | export function toArray ( arrayLike ) { 71 | const array = []; 72 | let i = arrayLike.length; 73 | while ( i-- ) { 74 | array[i] = arrayLike[i]; 75 | } 76 | 77 | return array; 78 | } 79 | 80 | export function findByKeyValue( array, key, value ) { 81 | return array.filter(function( obj ) { 82 | return obj[key] === value; 83 | }); 84 | } 85 | 86 | export function cloneArray( array ) { 87 | return JSON.parse(JSON.stringify(array)); 88 | } 89 | -------------------------------------------------------------------------------- /assets/scripts/utils/debounce.js: -------------------------------------------------------------------------------- 1 | export default function(func, wait, immediate) { 2 | let timeout; 3 | return function() { 4 | const context = this; 5 | const args = arguments; 6 | const later = function() { 7 | timeout = null; 8 | if (!immediate) func.apply(context, args); 9 | }; 10 | const callNow = immediate && !timeout; 11 | clearTimeout(timeout); 12 | timeout = setTimeout(later, wait); 13 | if (callNow) func.apply(context, args); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /assets/scripts/utils/environment.js: -------------------------------------------------------------------------------- 1 | const APP_NAME = 'Boilerplate'; 2 | const DATA_API_KEY = '.data-api'; 3 | 4 | const html = document.documentElement; 5 | const body = document.body; 6 | const isDebug = !!html.getAttribute('data-debug'); 7 | 8 | export { APP_NAME, DATA_API_KEY, html, body, isDebug }; 9 | -------------------------------------------------------------------------------- /assets/scripts/utils/html.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @see https://github.com/ractivejs/ractive/blob/dev/src/utils/html.js 3 | */ 4 | export function escapeHtml(str) { 5 | return str 6 | .replace(/&/g, '&') 7 | .replace(//g, '>'); 9 | } 10 | 11 | /** 12 | * Prepare HTML content that contains mustache characters for use with Ractive 13 | * @param {string} str 14 | * @return {string} 15 | */ 16 | export function unescapeHtml(str) { 17 | return str 18 | .replace(/</g, '<') 19 | .replace(/>/g, '>') 20 | .replace(/&/g, '&'); 21 | } 22 | 23 | /** 24 | * Get element data attributes 25 | * @param {DOMElement} node 26 | * @return {Array} data 27 | */ 28 | export function getNodeData(node) { 29 | // All attributes 30 | const attributes = node.attributes; 31 | 32 | // Regex Pattern 33 | const pattern = /^data\-(.+)$/; 34 | 35 | // Output 36 | const data = {}; 37 | 38 | for (let i in attributes) { 39 | if (!attributes[i]) { 40 | continue; 41 | } 42 | 43 | // Attributes name (ex: data-module) 44 | let name = attributes[i].name; 45 | 46 | // This happens. 47 | if (!name) { 48 | continue; 49 | } 50 | 51 | let match = name.match(pattern); 52 | if (!match) { 53 | continue; 54 | } 55 | 56 | // If this throws an error, you have some 57 | // serious problems in your HTML. 58 | data[match[1]] = getData(node.getAttribute(name)); 59 | } 60 | 61 | return data; 62 | } 63 | 64 | const rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/; 65 | 66 | /** 67 | * Parse value to data type. 68 | * 69 | * @link https://github.com/jquery/jquery/blob/3.1.1/src/data.js 70 | * @param {string} data - A value to convert. 71 | * @return {mixed} Returns the value in its natural data type. 72 | */ 73 | export function getData(data) { 74 | if (data === 'true') { 75 | return true; 76 | } 77 | 78 | if (data === 'false') { 79 | return false; 80 | } 81 | 82 | if (data === 'null') { 83 | return null; 84 | } 85 | 86 | // Only convert to a number if it doesn't change the string 87 | if (data === +data+'') { 88 | return +data; 89 | } 90 | 91 | if (rbrace.test( data )) { 92 | return JSON.parse( data ); 93 | } 94 | 95 | return data; 96 | } 97 | 98 | /** 99 | * Returns an array containing all the parent nodes of the given node 100 | * @param {object} node 101 | * @return {array} parent nodes 102 | */ 103 | export function getParents(elem) { 104 | // Set up a parent array 105 | let parents = []; 106 | 107 | // Push each parent element to the array 108 | for ( ; elem && elem !== document; elem = elem.parentNode ) { 109 | parents.push(elem); 110 | } 111 | 112 | // Return our parent array 113 | return parents; 114 | } 115 | 116 | // https://gomakethings.com/how-to-get-the-closest-parent-element-with-a-matching-selector-using-vanilla-javascript/ 117 | export function queryClosestParent(elem, selector) { 118 | 119 | // Element.matches() polyfill 120 | if (!Element.prototype.matches) { 121 | Element.prototype.matches = 122 | Element.prototype.matchesSelector || 123 | Element.prototype.mozMatchesSelector || 124 | Element.prototype.msMatchesSelector || 125 | Element.prototype.oMatchesSelector || 126 | Element.prototype.webkitMatchesSelector || 127 | function(s) { 128 | var matches = (this.document || this.ownerDocument).querySelectorAll(s), 129 | i = matches.length; 130 | while (--i >= 0 && matches.item(i) !== this) {} 131 | return i > -1; 132 | }; 133 | } 134 | 135 | // Get the closest matching element 136 | for ( ; elem && elem !== document; elem = elem.parentNode ) { 137 | if ( elem.matches( selector ) ) return elem; 138 | } 139 | return null; 140 | 141 | }; 142 | -------------------------------------------------------------------------------- /assets/scripts/utils/is.js: -------------------------------------------------------------------------------- 1 | const toString = Object.prototype.toString; 2 | const arrayLikePattern = /^\[object (?:Array|FileList)\]$/; 3 | 4 | // thanks, http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/ 5 | export function isArray ( thing ) { 6 | return toString.call( thing ) === '[object Array]'; 7 | } 8 | 9 | export function isArrayLike ( obj ) { 10 | return arrayLikePattern.test( toString.call( obj ) ); 11 | } 12 | 13 | export function isEqual ( a, b ) { 14 | if ( a === null && b === null ) { 15 | return true; 16 | } 17 | 18 | if ( typeof a === 'object' || typeof b === 'object' ) { 19 | return false; 20 | } 21 | 22 | return a === b; 23 | } 24 | 25 | // http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric 26 | export function isNumeric ( thing ) { 27 | return !isNaN( parseFloat( thing ) ) && isFinite( thing ); 28 | } 29 | 30 | export function isObject ( thing ) { 31 | return ( thing && toString.call( thing ) === '[object Object]' ); 32 | } 33 | 34 | export function isFunction( thing ) { 35 | const getType = {}; 36 | return thing && getType.toString.call(thing) === '[object Function]'; 37 | } 38 | -------------------------------------------------------------------------------- /assets/scripts/utils/maths.js: -------------------------------------------------------------------------------- 1 | export function lerp(start, end, amt){ 2 | return (1 - amt) * start + amt * end 3 | } 4 | -------------------------------------------------------------------------------- /assets/scripts/utils/transform.js: -------------------------------------------------------------------------------- 1 | export function transform(el, transformValue){ 2 | el.style.webkitTransform = transformValue; 3 | el.style.msTransform = transformValue; 4 | el.style.transform = transformValue; 5 | } 6 | 7 | export function getTranslate(el){ 8 | const translate = {} 9 | if(!window.getComputedStyle) return; 10 | 11 | const style = getComputedStyle(el); 12 | const transform = style.transform || style.webkitTransform || style.mozTransform; 13 | 14 | let mat = transform.match(/^matrix3d\((.+)\)$/); 15 | if(mat) return parseFloat(mat[1].split(', ')[13]); 16 | mat = transform.match(/^matrix\((.+)\)$/); 17 | translate.x = mat ? parseFloat(mat[1].split(', ')[4]) : 0; 18 | translate.y = mat ? parseFloat(mat[1].split(', ')[5]) : 0; 19 | 20 | return translate; 21 | } 22 | -------------------------------------------------------------------------------- /assets/scripts/utils/visibility.js: -------------------------------------------------------------------------------- 1 | import { isFunction } from './is'; 2 | import { arrayContains, findByKeyValue, removeFromArray } from './array'; 3 | import { $document, $window, $html, $body } from './environment'; 4 | 5 | const CALLBACKS = { 6 | hidden: [], 7 | visible: [] 8 | }; 9 | 10 | const ACTIONS = [ 11 | 'addCallback', 12 | 'removeCallback' 13 | ]; 14 | 15 | const STATES = [ 16 | 'visible', 17 | 'hidden' 18 | ]; 19 | 20 | const PREFIX = 'v-'; 21 | 22 | let UUID = 0; 23 | 24 | // Main event 25 | $document.on('visibilitychange', function(event) { 26 | if (document.hidden) { 27 | onDocumentChange('hidden'); 28 | } else { 29 | onDocumentChange('visible'); 30 | } 31 | }); 32 | 33 | /** 34 | * Add a callback 35 | * @param {string} state 36 | * @param {function} callback 37 | * @return {string} ident 38 | */ 39 | function addCallback (state, options) { 40 | let callback = options.callback || ''; 41 | 42 | if (!isFunction(callback)) { 43 | console.warn('Callback is not a function'); 44 | return false; 45 | } 46 | 47 | let ident = PREFIX + UUID++; 48 | 49 | CALLBACKS[state].push({ 50 | ident: ident, 51 | callback: callback 52 | }); 53 | 54 | return ident; 55 | } 56 | 57 | /** 58 | * Remove a callback 59 | * @param {string} state Visible or hidden 60 | * @param {string} ident Unique identifier 61 | * @return {boolean} If operation was a success 62 | */ 63 | function removeCallback (state, options) { 64 | let ident = options.ident || ''; 65 | 66 | if (typeof(ident) === 'undefined' || ident === '') { 67 | console.warn('Need ident to remove callback'); 68 | return false; 69 | } 70 | 71 | let index = findByKeyValue(CALLBACKS[state], 'ident', ident)[0]; 72 | 73 | // console.log(ident) 74 | // console.log(CALLBACKS[state]) 75 | 76 | if (typeof(index) !== 'undefined') { 77 | removeFromArray(CALLBACKS[state], index); 78 | return true; 79 | } else { 80 | console.warn('Callback could not be found'); 81 | return false; 82 | } 83 | } 84 | 85 | /** 86 | * When document state changes, trigger callbacks 87 | * @param {string} state Visible or hidden 88 | */ 89 | function onDocumentChange (state) { 90 | let callbackArray = CALLBACKS[state]; 91 | let i = 0; 92 | let len = callbackArray.length; 93 | 94 | for (; i < len; i++) { 95 | callbackArray[i].callback(); 96 | } 97 | } 98 | 99 | /** 100 | * Public facing API for adding and removing callbacks 101 | * @param {object} options Options 102 | * @return {boolean|integer} Unique identifier for the callback or boolean indicating success or failure 103 | */ 104 | function visibilityApi (options) { 105 | let action = options.action || ''; 106 | let state = options.state || ''; 107 | let ret; 108 | 109 | // Type and value checking 110 | if (!arrayContains(ACTIONS, action)) { 111 | console.warn('Action does not exist'); 112 | return false; 113 | } 114 | if (!arrayContains(STATES, state)) { 115 | console.warn('State does not exist'); 116 | return false; 117 | } 118 | 119 | // @todo Magic call function pls 120 | if (action === 'addCallback') { 121 | ret = addCallback(state, options); 122 | } else if (action === 'removeCallback') { 123 | ret = removeCallback(state, options); 124 | } 125 | 126 | return ret; 127 | } 128 | 129 | export { visibilityApi }; 130 | -------------------------------------------------------------------------------- /assets/scripts/vendors/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/assets/scripts/vendors/.gitkeep -------------------------------------------------------------------------------- /assets/styles/components/_button.scss: -------------------------------------------------------------------------------- 1 | .c-button { 2 | padding: rem(15px) rem(20px); 3 | background-color: lightgray; 4 | 5 | @include u-hocus { 6 | background-color: darkgray; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /assets/styles/components/_form.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Form 3 | // ========================================================================== 4 | .c-form { 5 | 6 | } 7 | 8 | .c-form_item { 9 | position: relative; 10 | margin-bottom: rem(30px); 11 | } 12 | 13 | // Label 14 | // ========================================================================== 15 | .c-form_label { 16 | display: block; 17 | margin-bottom: rem(10px); 18 | } 19 | 20 | // Input 21 | // ========================================================================== 22 | $input-icon-color: 424242; // No # 23 | 24 | .c-form_input { 25 | padding: rem(10px); 26 | border: 1px solid lightgray; 27 | background-color: white; 28 | 29 | &:hover { 30 | border-color: darkgray; 31 | } 32 | 33 | &:focus { 34 | border-color: dimgray; 35 | } 36 | 37 | &::placeholder { 38 | color: gray; 39 | } 40 | } 41 | 42 | // Checkbox 43 | // ========================================================================== 44 | $checkbox: rem(18px); 45 | $checkbox-icon-color: $input-icon-color; 46 | 47 | .c-form_checkboxLabel { 48 | @extend .c-form_label; 49 | 50 | position: relative; 51 | display: inline-block; 52 | margin-right: rem(10px); 53 | margin-bottom: 0; 54 | padding-left: ($checkbox + rem(10px)); 55 | cursor: pointer; 56 | 57 | &::before, &::after { 58 | position: absolute; 59 | top: 50%; 60 | left: 0; 61 | display: inline-block; 62 | margin-top: (-$checkbox / 2); 63 | padding: 0; 64 | width: $checkbox; 65 | height: $checkbox; 66 | content: ""; 67 | } 68 | 69 | &::before { 70 | background-color: $white; 71 | border: 1px solid lightgray; 72 | } 73 | 74 | &::after { 75 | border-color: transparent; 76 | background-color: transparent; 77 | background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2210.5%22%20viewBox%3D%220%200%2013%2010.5%22%20enable-background%3D%22new%200%200%2013%2010.5%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpath%20fill%3D%22%23#{$checkbox-icon-color}%22%20d%3D%22M4.8%205.8L2.4%203.3%200%205.7l4.8%204.8L13%202.4c0%200-2.4-2.4-2.4-2.4L4.8%205.8z%22%2F%3E%3C%2Fsvg%3E"); 78 | background-position: center; 79 | background-size: rem(12px); 80 | background-repeat: no-repeat; 81 | opacity: 0; 82 | } 83 | 84 | &:hover { 85 | &::before { 86 | border-color: darkgray; 87 | } 88 | } 89 | 90 | .c-form_checkbox:focus + & { 91 | &::before { 92 | border-color: dimgray; 93 | } 94 | } 95 | 96 | .c-form_checkbox:checked + & { 97 | &::after { 98 | opacity: 1; 99 | } 100 | } 101 | } 102 | 103 | .c-form_checkbox { 104 | position: absolute; 105 | width: 0; 106 | opacity: 0; 107 | } 108 | 109 | // Radio 110 | // ========================================================================== 111 | $radio-icon-color: $input-icon-color; 112 | 113 | .c-form_radioLabel { 114 | @extend .c-form_checkboxLabel; 115 | 116 | &::before, &::after { 117 | border-radius: 50%; 118 | } 119 | 120 | &::after { 121 | background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2213%22%20viewBox%3D%220%200%2013%2013%22%20enable-background%3D%22new%200%200%2013%2013%22%20xml%3Aspace%3D%22preserve%22%3E%3Ccircle%20fill%3D%22%23#{$radio-icon-color}%22%20cx%3D%226.5%22%20cy%3D%226.5%22%20r%3D%226.5%22%2F%3E%3C%2Fsvg%3E"); 122 | background-size: rem(6px); 123 | } 124 | } 125 | 126 | .c-form_radio { 127 | @extend .c-form_checkbox; 128 | } 129 | 130 | // Select 131 | // ============================================================================= 132 | $select-icon: rem(40px); 133 | $select-icon-color: $input-icon-color; 134 | 135 | .c-form_select { 136 | position: relative; 137 | cursor: pointer; 138 | 139 | &::after { 140 | position: absolute; 141 | top: 0; 142 | right: 0; 143 | bottom: 0; 144 | z-index: 2; 145 | width: $select-icon; 146 | background-image: url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20version%3D%221.1%22%20x%3D%220%22%20y%3D%220%22%20width%3D%2213%22%20height%3D%2211.3%22%20viewBox%3D%220%200%2013%2011.3%22%20enable-background%3D%22new%200%200%2013%2011.3%22%20xml%3Aspace%3D%22preserve%22%3E%3Cpolygon%20fill%3D%22%23#{$select-icon-color}%22%20points%3D%226.5%2011.3%203.3%205.6%200%200%206.5%200%2013%200%209.8%205.6%20%22%2F%3E%3C%2Fsvg%3E"); 147 | background-position: center; 148 | background-size: rem(8px); 149 | background-repeat: no-repeat; 150 | content: ""; 151 | pointer-events: none; 152 | } 153 | } 154 | 155 | .c-form_select_input { 156 | @extend .c-form_input; 157 | 158 | position: relative; 159 | z-index: 1; 160 | padding-right: $select-icon; 161 | cursor: pointer; 162 | } 163 | 164 | // Textarea 165 | // ============================================================================= 166 | .c-form_textarea { 167 | @extend .c-form_input; 168 | 169 | min-height: rem(200px); 170 | } 171 | -------------------------------------------------------------------------------- /assets/styles/components/_gl-image.scss: -------------------------------------------------------------------------------- 1 | .c-gl-image { 2 | // width: 500px; 3 | // height: 390px; 4 | @include o-layout-item; 5 | position: relative; 6 | margin: 0; 7 | display: inline-block; 8 | 9 | &::before { 10 | content:""; 11 | display: block; 12 | padding-bottom: 78%; 13 | } 14 | 15 | @media (min-width: $from-medium) { 16 | width: 40%; 17 | } 18 | 19 | &.is-loading { 20 | background-color: rgba(0,0,0,0.2); 21 | } 22 | } 23 | 24 | .c-gl-image_wrap { 25 | position: absolute; 26 | top: 0; 27 | bottom: 0; 28 | right: 0; 29 | left: 0; 30 | 31 | canvas { 32 | position: absolute; 33 | top: 0; 34 | bottom: 0; 35 | right: 0; 36 | left: 0; 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /assets/styles/components/_heading.scss: -------------------------------------------------------------------------------- 1 | .c-heading { 2 | line-height: $line-height-h; 3 | margin-bottom: rem(30px); 4 | 5 | &.-h1 { 6 | font-size: rem($font-size-h1); 7 | } 8 | 9 | &.-h2 { 10 | font-size: rem($font-size-h2); 11 | } 12 | 13 | &.-h3 { 14 | font-size: rem($font-size-h3); 15 | } 16 | 17 | &.-h4 { 18 | font-size: rem($font-size-h4); 19 | } 20 | 21 | &.-h5 { 22 | font-size: rem($font-size-h5); 23 | } 24 | 25 | &.-h6 { 26 | font-size: rem($font-size-h6); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /assets/styles/components/_scrollbar.scss: -------------------------------------------------------------------------------- 1 | .c-scrollbar { 2 | position: absolute; 3 | right: 0; 4 | top: 0; 5 | width: 11px; 6 | height: 100vh; 7 | transform-origin: center right; 8 | transition: transform 0.3s, opacity 0.3s; 9 | opacity: 0; 10 | 11 | &:hover { 12 | transform: scaleX(1.45); 13 | } 14 | 15 | &:hover, .has-scroll-scrolling &, .has-scroll-dragging & { 16 | opacity: 1; 17 | } 18 | } 19 | 20 | .c-scrollbar_thumb { 21 | position: absolute; 22 | top: 0; 23 | right: 0; 24 | background-color: black; 25 | opacity: 0.5; 26 | width: 7px; 27 | border-radius: 10px; 28 | margin: 2px; 29 | cursor: grab; 30 | 31 | .has-scroll-dragging & { 32 | cursor: grabbing; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /assets/styles/elements/_fonts.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Base / Fonts 3 | // ========================================================================== 4 | 5 | // @include font-face( 6 | // $font-foobar, 7 | // "fonts/Foobar/Regular" 8 | // ) { 9 | // font-style: normal; 10 | // font-weight: 400; 11 | // } 12 | 13 | // @include font-face( 14 | // $font-foobar, 15 | // "fonts/Foobar/Medium" 16 | // ) { 17 | // font-style: normal; 18 | // font-weight: 500; 19 | // } 20 | 21 | // @include font-face( 22 | // $font-foobar, 23 | // "fonts/Foobar/Semibold" 24 | // ) { 25 | // font-style: normal; 26 | // font-weight: 600; 27 | // } 28 | 29 | // @include font-face( 30 | // $font-bazqux, 31 | // "fonts/Bazqux/Regular", 32 | // ("eot", "woff2", "woff", "ttf") 33 | // ) { 34 | // font-style: normal; 35 | // font-weight: 400; 36 | // } 37 | -------------------------------------------------------------------------------- /assets/styles/elements/_page.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Base / Page 3 | // ========================================================================== 4 | 5 | // 6 | // Simple page-level setup. 7 | // 8 | // 1. Set the default `font-size` and `line-height` for the entire project, 9 | // sourced from our default variables. 10 | // 2. Force scrollbars to always be visible to prevent awkward ‘jumps’ when 11 | // navigating between pages that do/do not have enough content to produce 12 | // scrollbars naturally. 13 | // 3. Ensure the page always fills at least the entire height of the viewport. 14 | // 15 | html { 16 | overflow-y: scroll; /* [2] */ 17 | min-height: 100%; /* [3] */ 18 | color: $color; 19 | font-family: $font-family; 20 | line-height: $line-height; /* [1] */ 21 | 22 | @media (max-width: $to-small) { 23 | font-size: 12px; 24 | } 25 | 26 | @media (min-width: $from-small) and (max-width: $to-medium) { 27 | font-size: 13px; 28 | } 29 | 30 | @media (min-width: $from-medium) and (max-width: $to-large) { 31 | font-size: 14px; 32 | } 33 | 34 | @media (min-width: $from-large) and (max-width: $to-huge) { 35 | font-size: $font-size; /* [1] */ 36 | } 37 | 38 | @media (min-width: $from-huge) and (max-width: $to-gigantic) { 39 | font-size: 18px; 40 | } 41 | 42 | @media (min-width: $from-gigantic) and (max-width: $to-colossal) { 43 | font-size: 21px; 44 | } 45 | 46 | @media (min-width: $from-colossal) { 47 | font-size: 24px; 48 | } 49 | 50 | &.is-loading { 51 | cursor: wait; 52 | } 53 | 54 | &.has-scroll-smooth { 55 | overflow: hidden; 56 | } 57 | 58 | &.has-scroll-dragging { 59 | user-select: none; 60 | } 61 | } 62 | 63 | body { 64 | 65 | .has-scroll-smooth & { 66 | overflow: hidden; 67 | } 68 | } 69 | 70 | ::selection { 71 | background-color: $selection-background-color; 72 | color: $selection-text-color; 73 | text-shadow: none; 74 | } 75 | 76 | a { 77 | color: $link-color; 78 | 79 | @include u-hocus { 80 | color: $link-hover-color; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /assets/styles/generic/_button.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Generic / Buttons 3 | // ========================================================================== 4 | 5 | // 6 | // 1. Allow us to style box model properties. 7 | // 2. Fixes odd inner spacing in IE7. 8 | // 3. Reset/normalize some styles. 9 | // 4. Line different sized buttons up a little nicer. 10 | // 5. Make buttons inherit font styles (often necessary when styling `input`s as buttons). 11 | // 6. Force all button-styled elements to appear clickable. 12 | // 13 | button, 14 | .c-button { 15 | @include u-hocus { 16 | text-decoration: none; 17 | } 18 | 19 | display: inline-block; /* [1] */ 20 | overflow: visible; /* [2] */ 21 | margin: 0; /* [3] */ 22 | padding: 0; 23 | outline: 0; 24 | border: 0; 25 | background: none transparent; 26 | color: inherit; 27 | vertical-align: middle; /* [4] */ 28 | text-align: center; /* [3] */ 29 | text-decoration: none; 30 | text-transform: none; 31 | font: inherit; /* [5] */ 32 | line-height: normal; 33 | cursor: pointer; /* [6] */ 34 | user-select: none; 35 | } 36 | -------------------------------------------------------------------------------- /assets/styles/generic/_form.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Generic / Forms 3 | // ========================================================================== 4 | 5 | input, 6 | select, 7 | textarea { 8 | display: block; 9 | margin: 0; 10 | padding: 0; 11 | width: 100%; 12 | outline: 0; 13 | border: 0; 14 | border-radius: 0; 15 | background: none transparent; 16 | color: inherit; 17 | font: inherit; 18 | line-height: normal; 19 | appearance: none; 20 | } 21 | 22 | select { 23 | text-transform: none; 24 | 25 | &::-ms-expand { 26 | display: none; 27 | } 28 | 29 | &::-ms-value { 30 | background: none; 31 | color: inherit; 32 | } 33 | 34 | // Remove Firefox :focus dotted outline, breaks color inherit 35 | // &:-moz-focusring { 36 | // color: transparent; 37 | // text-shadow: 0 0 0 #000000; // Text :focus color 38 | // } 39 | } 40 | 41 | textarea { 42 | overflow: auto; 43 | resize: vertical; 44 | } 45 | -------------------------------------------------------------------------------- /assets/styles/generic/_generic.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Generic 3 | // ========================================================================== 4 | 5 | html { 6 | box-sizing: border-box; 7 | } 8 | 9 | // 10 | // Add the correct display in IE 10-. 11 | // 1. Add the correct display in IE. 12 | // 13 | template, /* [1] */ 14 | [hidden] { 15 | display: none; 16 | } 17 | 18 | *, 19 | :before, 20 | :after { 21 | box-sizing: inherit; 22 | } 23 | 24 | address { 25 | font-style: inherit; 26 | } 27 | 28 | dfn, 29 | cite, 30 | em, 31 | i { 32 | font-style: italic; 33 | } 34 | 35 | b, 36 | strong { 37 | font-weight: $bold; 38 | } 39 | 40 | a { 41 | text-decoration: none; 42 | 43 | svg { 44 | pointer-events: none; 45 | } 46 | } 47 | 48 | ul, 49 | ol { 50 | margin: 0; 51 | padding: 0; 52 | list-style: none; 53 | } 54 | 55 | p, 56 | figure { 57 | margin: 0; 58 | padding: 0; 59 | } 60 | 61 | h1, h2, h3, h4, h5, h6 { 62 | margin: 0; 63 | } 64 | 65 | /** 66 | * 1. Single taps should be dispatched immediately on clickable elements 67 | */ 68 | a, area, button, input, label, select, textarea, [tabindex] { 69 | -ms-touch-action: manipulation; /* [1] */ 70 | touch-action: manipulation; 71 | } 72 | 73 | [hreflang] > abbr[title] { 74 | text-decoration: none; 75 | } 76 | 77 | table { 78 | border-spacing: 0; 79 | border-collapse: collapse; 80 | } 81 | 82 | hr { 83 | display: block; 84 | margin: 1em 0; 85 | padding: 0; 86 | height: 1px; 87 | border: 0; 88 | border-top: 1px solid #CCCCCC; 89 | } 90 | -------------------------------------------------------------------------------- /assets/styles/generic/_media.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Generic / Media 3 | // ========================================================================== 4 | 5 | // 6 | // 1. Setting `vertical-align` removes the whitespace that appears under `img` 7 | // elements when they are dropped into a page as-is. Safer alternative to 8 | // using `display: block;`. 9 | // 10 | audio, 11 | canvas, 12 | iframe, 13 | img, 14 | svg, 15 | video { 16 | vertical-align: middle; /* [1] */ 17 | } 18 | 19 | // 20 | // Add the correct display in iOS 4-7. 21 | // 22 | audio:not([controls]) { 23 | display: none; 24 | height: 0; 25 | } 26 | 27 | // 28 | // 2. Fluid media for responsive purposes. 29 | // 30 | img, 31 | svg { 32 | max-width: 100%; /* [2] */ 33 | height: auto; 34 | 35 | // 36 | // 4. If a `width` and/or `height` attribute have been explicitly defined, let’s 37 | // not make the image fluid. 38 | // 39 | &[width], /* [4] */ 40 | &[height] { 41 | /* [4] */ 42 | max-width: none; 43 | } 44 | } 45 | 46 | // 47 | // 4. Offset `alt` text from surrounding copy. 48 | // 49 | img { 50 | font-style: italic; /* [4] */ 51 | } 52 | 53 | // 54 | // 5. SVG elements should fallback to their surrounding text color. 55 | // 56 | svg { 57 | fill: currentColor; /* [5] */ 58 | } 59 | -------------------------------------------------------------------------------- /assets/styles/main.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Main 3 | // ========================================================================== 4 | 5 | // Settings 6 | // ========================================================================== 7 | @import "settings/config.colors"; 8 | @import "settings/config"; 9 | 10 | // ========================================================================== 11 | // Tools 12 | // ========================================================================== 13 | @import "tools/functions"; 14 | @import "tools/mixins"; 15 | @import "tools/fonts"; 16 | @import "tools/layout"; 17 | @import "tools/widths"; 18 | // @import "tools/family"; 19 | 20 | // Generic 21 | // ========================================================================== 22 | @import "node_modules/normalize.css/normalize"; 23 | @import "generic/generic"; 24 | @import "generic/media"; 25 | // @import "generic/form"; 26 | @import "generic/button"; 27 | 28 | // Elements 29 | // ========================================================================== 30 | @import "elements/fonts"; 31 | @import "elements/page"; 32 | 33 | // Objects 34 | // ========================================================================== 35 | @import "objects/scroll"; 36 | @import "objects/container"; 37 | @import "objects/ratio"; 38 | @import "objects/layout"; 39 | // @import "objects/crop"; 40 | // @import "objects/table"; 41 | 42 | // Vendors 43 | // ========================================================================== 44 | // @import "vendors/vendor"; 45 | 46 | // Components 47 | // ========================================================================== 48 | @import "components/scrollbar"; 49 | @import "components/heading"; 50 | @import "components/button"; 51 | // @import "components/form"; 52 | @import "components/gl-image"; 53 | 54 | // Templates 55 | // ========================================================================== 56 | // @import "templates/template"; 57 | 58 | // Utilities 59 | // ========================================================================== 60 | @import "utilities/ratio"; 61 | @import "utilities/widths"; 62 | // @import "utilities/align"; 63 | // @import "utilities/helpers"; 64 | // @import "utilities/states"; 65 | // @import "utilities/spacing"; 66 | // @import "utilities/print"; 67 | -------------------------------------------------------------------------------- /assets/styles/objects/_container.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Objects / Container 3 | // ========================================================================== 4 | 5 | // 6 | // Page-level constraining and wrapping elements. 7 | // 8 | // > In programming languages the word *container* is generally used for structures 9 | // that can contain more than one element. 10 | // > A *wrapper* instead is something that wraps around a single object to provide 11 | // more functionalities and interfaces to it. 12 | // @link http://stackoverflow.com/a/13202141/140357 13 | // 14 | 15 | .o-container { 16 | margin-right: auto; 17 | margin-left: auto; 18 | padding-right: rem($padding); 19 | padding-left: rem($padding); 20 | max-width: rem($container-width + ($padding * 2)); 21 | } 22 | -------------------------------------------------------------------------------- /assets/styles/objects/_crop.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Objects / Crop 3 | // ========================================================================== 4 | 5 | // 6 | // @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.crop.scss 7 | // 8 | 9 | // A list of cropping ratios that get generated as modifier classes. 10 | $crop-ratios: ( 11 | (2:1), 12 | (4:3), 13 | (16:9), 14 | ) !default; 15 | 16 | /** 17 | * Provide a cropping container in order to display media (usually images) 18 | * cropped to certain ratios. 19 | * 20 | * 1. Set up a positioning context in which the image can sit. 21 | * 2. This is the crucial part: where the cropping happens. 22 | */ 23 | .o-crop { 24 | position: relative; /* [1] */ 25 | display: block; 26 | overflow: hidden; /* [2] */ 27 | } 28 | 29 | /** 30 | * Apply this class to the content (usually `img`) that needs cropping. 31 | * 32 | * 1. Image’s default positioning is top-left in the cropping box. 33 | * 2. Make sure the media doesn’t stop itself too soon. 34 | */ 35 | .o-crop_content { 36 | position: absolute; 37 | top: 0; /* [1] */ 38 | left: 0; /* [1] */ 39 | max-width: none; /* [2] */ 40 | 41 | /** 42 | * We can position the media in different locations within the cropping area. 43 | */ 44 | &.-right { 45 | right: 0; 46 | left: auto; 47 | } 48 | 49 | &.-bottom { 50 | top: auto; 51 | bottom: 0; 52 | } 53 | 54 | &.-center { 55 | top: 50%; 56 | left: 50%; 57 | transform: translate(-50%, -50%); 58 | } 59 | } 60 | 61 | /* stylelint-disable */ 62 | 63 | // 64 | // Generate a series of crop classes to be used like so: 65 | // 66 | // @example 67 | //
68 | // 69 | // 70 | .o-crop { 71 | @each $crop in $crop-ratios { 72 | @each $antecedent, $consequent in $crop { 73 | @if (type-of($antecedent) != number) { 74 | @error "`#{$antecedent}` needs to be a number." 75 | } 76 | 77 | @if (type-of($consequent) != number) { 78 | @error "`#{$consequent}` needs to be a number." 79 | } 80 | 81 | &.-#{$antecedent}\:#{$consequent} { 82 | padding-bottom: ($consequent/$antecedent) * 100%; 83 | } 84 | } 85 | } 86 | } 87 | 88 | /* stylelint-enable */ 89 | -------------------------------------------------------------------------------- /assets/styles/objects/_layout.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Objects / Layout 3 | // ========================================================================== 4 | 5 | // 6 | // Grid-like layout system. 7 | // 8 | // The layout object provides us with a column-style layout system. This file 9 | // contains the basic structural elements, but classes should be complemented 10 | // with width utilities, for example: 11 | // 12 | // @example 13 | //
14 | //
15 | //
16 | //
17 | //
18 | //
19 | //
20 | //
21 | // 22 | // We can also manipulate entire layout systems by adding a series of modifiers 23 | // to the `.o-layout` block. For example: 24 | // 25 | // @example 26 | //
27 | // 28 | // This will reverse the displayed order of the system so that it runs in the 29 | // opposite order to our source, effectively flipping the system over. 30 | // 31 | // @example 32 | //
33 | // 34 | // This will cause the system to fill up from either the centre or the right 35 | // hand side. Default behaviour is to fill up the layout system from the left. 36 | // 37 | // @requires tools/layout 38 | // @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss 39 | // 40 | 41 | .o-layout { 42 | @include o-layout; 43 | 44 | // Gutter modifiers 45 | &.-gutter { 46 | margin-left: rem(-$unit); 47 | } 48 | 49 | &.-gutter-small { 50 | margin-left: rem(-$unit/2); 51 | } 52 | 53 | // Horizontal aligment modifiers 54 | &.-center { 55 | text-align: center; 56 | } 57 | 58 | &.-right { 59 | text-align: right; 60 | } 61 | 62 | &.-reverse { 63 | direction: rtl; 64 | 65 | &.-flex { 66 | flex-direction: row-reverse; 67 | } 68 | } 69 | 70 | &.-flex { 71 | display: flex; 72 | 73 | &.-top { 74 | align-items: flex-start; 75 | } 76 | &.-middle { 77 | align-items: center; 78 | } 79 | &.-bottom { 80 | align-items: flex-end; 81 | } 82 | } 83 | &.-stretch { 84 | align-items: stretch; 85 | } 86 | } 87 | 88 | .o-layout_item { 89 | @include o-layout_item; 90 | 91 | // Gutter modifiers 92 | .o-layout.-gutter > & { 93 | padding-left: rem($unit); 94 | } 95 | 96 | .o-layout.-gutter-small > & { 97 | padding-left: rem($unit/2); 98 | } 99 | 100 | // Vertical alignment modifiers 101 | .o-layout.-middle > & { 102 | vertical-align: middle; 103 | } 104 | 105 | .o-layout.-bottom > & { 106 | vertical-align: bottom; 107 | } 108 | 109 | // Horizontal aligment modifiers 110 | .o-layout.-center > &, 111 | .o-layout.-right > &, 112 | .o-layout.-reverse > & { 113 | text-align: left; 114 | } 115 | 116 | .o-layout.-reverse > & { 117 | direction: ltr; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /assets/styles/objects/_ratio.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Objects / Ratio 3 | // ========================================================================== 4 | 5 | /** 6 | * Create ratio-bound content blocks, to keep media (e.g. images, videos) in 7 | * their correct aspect ratios. 8 | * 9 | * http://alistapart.com/article/creating-intrinsic-ratios-for-video 10 | * 11 | * 1. Default cropping is a 1:1 ratio (i.e. a perfect square). 12 | */ 13 | .o-ratio { 14 | position: relative; 15 | display: block; 16 | overflow: hidden; 17 | 18 | &:before { 19 | display: block; 20 | padding-bottom: 100%; /* [1] */ 21 | width: 100%; 22 | content: ""; 23 | } 24 | } 25 | 26 | .o-ratio_content, 27 | .o-ratio > img, 28 | .o-ratio > iframe, 29 | .o-ratio > embed, 30 | .o-ratio > object { 31 | position: absolute; 32 | top: 0; 33 | bottom: 0; 34 | left: 0; 35 | width: 100%; 36 | // height: 100%; 37 | } 38 | -------------------------------------------------------------------------------- /assets/styles/objects/_scroll.scss: -------------------------------------------------------------------------------- 1 | .o-scroll { 2 | min-height: 100vh; 3 | } 4 | -------------------------------------------------------------------------------- /assets/styles/objects/_table.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Objects / Tables 3 | // ========================================================================== 4 | .o-table { 5 | width: 100%; 6 | 7 | /** 8 | * Force all cells within a table to occupy the same width as each other. 9 | * 10 | * @link https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout#Values 11 | */ 12 | &.-fixed { 13 | table-layout: fixed; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/styles/settings/_config.colors.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Settings / Config / Colors 3 | // ========================================================================== 4 | 5 | // Palette 6 | // ============================================================================= 7 | $white: #FFFFFF; 8 | $black: #000000; 9 | 10 | // Specific 11 | // ============================================================================= 12 | // Link 13 | $link-color: #1A0DAB; 14 | $link-focus-color: #1A0DAB; 15 | $link-hover-color: darken(#1A0DAB, 10%); 16 | // Selection 17 | $selection-text-color: #3297FD; 18 | $selection-background-color: #FFFFFF; 19 | 20 | // Social Colors 21 | // ============================================================================= 22 | $facebook-color: #3B5998; 23 | $instagram-color: #E1306C; 24 | $youtube-color: #CD201F; 25 | $twitter-color: #1DA1F2; 26 | -------------------------------------------------------------------------------- /assets/styles/settings/_config.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Settings / Config 3 | // ========================================================================== 4 | 5 | // Context 6 | // ============================================================================= 7 | // The current stylesheet context. Available values: frontend, editor. 8 | $context: frontend !default; 9 | 10 | // Path is relative to the stylesheets directory. 11 | $assets-path: "../" !default; 12 | 13 | // Typefaces 14 | // ============================================================================= 15 | $font-sans-serif: sans-serif; 16 | 17 | // Typography 18 | // ============================================================================= 19 | // Base 20 | $font-size: 16px; 21 | $line-height: 24px / $font-size; 22 | $font-family: $font-sans-serif; 23 | $color: #222222; 24 | // Headings 25 | $font-size-h1: 36px !default; 26 | $font-size-h2: 28px !default; 27 | $font-size-h3: 24px !default; 28 | $font-size-h4: 20px !default; 29 | $font-size-h5: 18px !default; 30 | $font-size-h6: 16px !default; 31 | $line-height-h: $line-height; 32 | // Weights 33 | $light: 300; 34 | $normal: 400; 35 | $medium: 500; 36 | $bold: 700; 37 | 38 | // Transitions 39 | // ============================================================================= 40 | $speed: 0.3s; 41 | $easing: linear; 42 | 43 | // Spacing Units 44 | // ============================================================================= 45 | $unit: 60px; 46 | $unit-small: 30px; 47 | 48 | // Container 49 | // ========================================================================== 50 | $container-width: 2000px; 51 | $padding: $unit; 52 | 53 | // Breakpoints 54 | // ============================================================================= 55 | $from-tiny: 500px !default; 56 | $to-tiny: $from-tiny - 1 !default; 57 | $from-small: 700px !default; 58 | $to-small: $from-small - 1 !default; 59 | $from-medium: 1000px !default; 60 | $to-medium: $from-medium - 1 !default; 61 | $from-large: 1200px !default; 62 | $to-large: $from-large - 1 !default; 63 | $from-big: 1400px !default; 64 | $to-big: $from-big - 1 !default; 65 | $from-huge: 1600px !default; 66 | $to-huge: $from-huge - 1 !default; 67 | $from-enormous: 1800px !default; 68 | $to-enormous: $from-enormous - 1 !default; 69 | $from-gigantic: 2000px !default; 70 | $to-gigantic: $from-gigantic - 1 !default; 71 | $from-colossal: 2400px !default; 72 | $to-colossal: $from-colossal - 1 !default; 73 | -------------------------------------------------------------------------------- /assets/styles/templates/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/assets/styles/templates/.gitkeep -------------------------------------------------------------------------------- /assets/styles/tools/_family.scss: -------------------------------------------------------------------------------- 1 | // 2 | // 3 | // DOCS : https://lukyvj.github.io/family.scss/ 4 | // 5 | // 6 | /// Select all children from the first to `$num`. 7 | /// @group with-arguments 8 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 9 | /// @param {number} $num - id of the child 10 | @mixin first($num) { 11 | @if $num == 1 { 12 | &:first-child { 13 | @content; 14 | } 15 | } @else { 16 | &:nth-child(-n + #{$num}) { 17 | @content; 18 | } 19 | } 20 | } 21 | 22 | /// Select all children from the last to `$num`. 23 | /// @group with-arguments 24 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 25 | /// @param {number} $num - id of the child 26 | @mixin last($num) { 27 | &:nth-last-child(-n + #{$num}) { 28 | @content; 29 | } 30 | } 31 | 32 | /// Select all children after the first to `$num`. 33 | /// @group with-arguments 34 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 35 | /// @param {number} $num - id of the child 36 | @mixin after-first($num) { 37 | &:nth-child(n + #{$num + 1}) { 38 | @content; 39 | } 40 | } 41 | 42 | /// Select all children before `$num` from the last. 43 | /// @group with-arguments 44 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 45 | /// @param {number} $num - id of the child 46 | @mixin from-end($num) { 47 | &:nth-last-child(#{$num}) { 48 | @content; 49 | } 50 | } 51 | 52 | /// Select all children between `$first` and `$last`. 53 | /// @group with-arguments 54 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 55 | @mixin between($first, $last) { 56 | &:nth-child(n + #{$first}):nth-child(-n + #{$last}) { 57 | @content; 58 | } 59 | } 60 | 61 | /// Select all even children between `$first` and `$last`. 62 | /// @group with-arguments 63 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 64 | @mixin even-between($first, $last) { 65 | &:nth-child(even):nth-child(n + #{$first}):nth-child(-n + #{$last}) { 66 | @content; 67 | } 68 | } 69 | 70 | /// Select all odd children between `$first` and `$last`. 71 | /// @group with-arguments 72 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 73 | @mixin odd-between($first, $last) { 74 | &:nth-child(odd):nth-child(n + #{$first}):nth-child(-n + #{$last}) { 75 | @content; 76 | } 77 | } 78 | 79 | /// Select all `$num` children between `$first` and `$last`. 80 | /// @group with-arguments 81 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 82 | @mixin n-between($num, $first, $last) { 83 | &:nth-child(#{$num}n):nth-child(n + #{$first}):nth-child(-n + #{$last}) { 84 | @content; 85 | } 86 | } 87 | 88 | 89 | /// Select all children but `$num`. 90 | /// @group with-arguments 91 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 92 | /// @param {number} $num - id of the child 93 | @mixin all-but($num) { 94 | &:not(:nth-child(#{$num})) { 95 | @content; 96 | } 97 | } 98 | 99 | /// Select children each `$num`. 100 | /// @group with-arguments 101 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 102 | /// @param {number} $num - id of the child 103 | /// @alias every 104 | @mixin each($num) { 105 | &:nth-child(#{$num}n) { 106 | @content; 107 | } 108 | } 109 | 110 | /// Select children each `$num`. 111 | /// @group with-arguments 112 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 113 | /// @param {number} $num - id of the child 114 | @mixin every($num) { 115 | &:nth-child(#{$num}n) { 116 | @content; 117 | } 118 | } 119 | 120 | /// Select the `$num` child from the start and the `$num` child from the last. 121 | /// @group with-arguments 122 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 123 | /// @param {number} $num - id of the child 124 | @mixin from-first-last($num) { 125 | &:nth-child(#{$num}), 126 | &:nth-last-child(#{$num}) { 127 | @content; 128 | } 129 | } 130 | 131 | 132 | /// Select the item in the middle of `$num` child. Only works with odd number 133 | /// chain. 134 | /// @group with-arguments 135 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 136 | /// @param {number} $num - id of the child 137 | @mixin middle($num) { 138 | &:nth-child(#{round($num / 2)}) { 139 | @content; 140 | } 141 | } 142 | 143 | 144 | /// Select all children between the `$num` first and the `$num` last. 145 | /// @group with-arguments 146 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 147 | /// @param {number} $num - id of the child 148 | @mixin all-but-first-last($num) { 149 | &:nth-child(n + #{$num}):nth-last-child(n + #{$num}) { 150 | @content; 151 | } 152 | } 153 | 154 | 155 | /// This quantity-query mixin will only select the first of `$limit` items. It will not 156 | /// work if there is not as much as item as you set in `$limit`. 157 | /// @group Quantity queries 158 | /// @param {number} $limit 159 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 160 | @mixin first-of($limit) { 161 | &:nth-last-child(#{$limit}):first-child { 162 | @content; 163 | } 164 | } 165 | 166 | /// This quantity-query mixin will only select the last of `$limit` items. It will not 167 | /// if there is not as much as item as you set in `$limit`. 168 | /// @group Quantity queries 169 | /// @param {number} $limit 170 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 171 | @mixin last-of($limit) { 172 | &:nth-of-type(#{$limit}):nth-last-of-type(1) { 173 | @content; 174 | } 175 | } 176 | 177 | /// This quantity-query mixin will select every items if there is at least `$num` items. It will not 178 | /// if there is not as much as item as you set in `$num`. 179 | /// @group Quantity queries 180 | /// @param {number} $limit 181 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 182 | @mixin at-least($num) { 183 | $selector: &; 184 | $child: nth(nth($selector, -1), -1); 185 | 186 | &:nth-last-child(n + #{$num}), 187 | &:nth-last-child(n + #{$num}) ~ #{$child} { 188 | @content; 189 | } 190 | } 191 | 192 | /// This quantity-query mixin will select every items if there is at most `$num` items. It will not 193 | /// if there is not as much as item as you set in `$num`. 194 | /// @group Quantity queries 195 | /// @param {number} $limit 196 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 197 | @mixin at-most($num) { 198 | $selector: &; 199 | $child: nth(nth($selector, -1), -1); 200 | 201 | &:nth-last-child(-n + #{$num}):first-child, 202 | &:nth-last-child(-n + #{$num}):first-child ~ #{$child} { 203 | @content; 204 | } 205 | } 206 | 207 | /// This quantity-query mixin will select every items only if there is between `$min` and `$max` items. 208 | /// @group Quantity queries 209 | /// @param {number} $limit 210 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 211 | @mixin in-between($min, $max) { 212 | $selector: &; 213 | $child: nth(nth($selector, -1), -1); 214 | 215 | &:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child, 216 | &:nth-last-child(n + #{$min}):nth-last-child(-n + #{$max}):first-child ~ #{$child} { 217 | @content; 218 | } 219 | } 220 | 221 | /// Select the first exact child 222 | /// @group no-arguments 223 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 224 | @mixin first-child() { 225 | &:first-of-type { 226 | @content 227 | } 228 | } 229 | 230 | /// Select the last exact child 231 | /// @group no-arguments 232 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 233 | @mixin last-child() { 234 | &:last-of-type { 235 | @content 236 | } 237 | } 238 | 239 | /// Select all even children. 240 | /// @group no-arguments 241 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 242 | @mixin even() { 243 | &:nth-child(even) { 244 | @content; 245 | } 246 | } 247 | 248 | /// Select all odd children. 249 | /// @group no-arguments 250 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 251 | @mixin odd() { 252 | &:nth-child(odd) { 253 | @content; 254 | } 255 | } 256 | 257 | /// Select only the first and last child. 258 | /// @group no-arguments 259 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 260 | @mixin first-last() { 261 | &:first-child, 262 | &:last-child { 263 | @content; 264 | } 265 | } 266 | 267 | /// Will only select the child if it’s unique. 268 | /// @group no-arguments 269 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 270 | /// @alias only 271 | @mixin unique() { 272 | &:only-child { 273 | @content; 274 | } 275 | } 276 | 277 | /// Will only select the child if it’s unique. 278 | /// @group no-arguments 279 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 280 | @mixin only() { 281 | &:only-child { 282 | @content; 283 | } 284 | } 285 | 286 | /// Will only select children if they are not unique. Meaning if there is at 287 | /// least 2 children, the style is applied. 288 | /// @group no-arguments 289 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 290 | @mixin not-unique() { 291 | &:not(:only-child) { 292 | @content; 293 | } 294 | } 295 | 296 | 297 | /// This mixin is used to automatically sort z-index in numerical order. But it 298 | /// can also sort them in anti-numerical order, depending the parameters you use. 299 | /// @group using functions 300 | /// @content [Write the style you want to apply to the children, and it will be added within the @content directive] 301 | /// @param {number} $num - Number of children 302 | /// @param {string} $direction [forward] - Direction of the sort 303 | /// @param {number} $index [0] - Index of the sorting 304 | @mixin child-index($num, $direction: 'forward', $index: 0) { 305 | @for $i from 1 through $num { 306 | @if ($direction == 'forward') { 307 | &:nth-child(#{$i}) { 308 | z-index: order-index($i, $index); 309 | @content; 310 | } 311 | } @else if ($direction == 'backward') { 312 | &:nth-last-child(#{$i}) { 313 | z-index: order-index($i, $index); 314 | @content; 315 | } 316 | } 317 | } 318 | } 319 | 320 | /// Used by the child-index mixin. It will returned the proper sorted numbers 321 | /// depending on the `$index` value. 322 | /// @access private 323 | /// @param {number} $num - Number of children 324 | /// @param {number} $index - Index of the sorting 325 | @function order-index($i, $index) { 326 | @return ($index + $i); 327 | } 328 | -------------------------------------------------------------------------------- /assets/styles/tools/_fonts.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Tools / Font Faces 3 | // ========================================================================== 4 | 5 | $global-font-file-formats: "woff2", "woff" !default; 6 | 7 | // 8 | // Builds the `src` list for an `@font-face` declaration. 9 | // 10 | // @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/utilities/_font-source-declaration.scss 11 | // @link http://goo.gl/Ru1bKP 12 | // 13 | // @param {String} $font-family - The font family name. 14 | // @param {String} $file-path - The path to the font family. 15 | // @param {List} $file-formats - The file formats to request. 16 | // @return {List} 17 | // 18 | // @require {function} list-contains 19 | // 20 | // @access private 21 | // 22 | @function font-source-declaration( 23 | $font-family, 24 | $file-path, 25 | $file-formats 26 | ) { 27 | $src: (); 28 | $formats-map: ( 29 | eot: "#{$file-path}.eot?#iefix" format("embedded-opentype"), 30 | woff2: "#{$file-path}.woff2" format("woff2"), 31 | woff: "#{$file-path}.woff" format("woff"), 32 | ttf: "#{$file-path}.ttf" format("truetype"), 33 | svg: "#{$file-path}.svg##{$font-family}" format("svg"), 34 | ); 35 | 36 | @each $key, $values in $formats-map { 37 | @if list-contains($file-formats, $key) { 38 | $file-path: nth($values, 1); 39 | $font-format: nth($values, 2); 40 | $src: append($src, url("#{$assets-path}#{$file-path}") $font-format, comma); 41 | } 42 | } 43 | 44 | @return $src; 45 | } 46 | 47 | // 48 | // Generates an `@font-face` declaration. 49 | // 50 | // You can choose the specific file formats you need to output; the mixin supports 51 | // `eot`, `ttf`, `svg`, `woff2` and `woff`. 52 | // 53 | // @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/library/_font-face.scss 54 | // 55 | // @param {String} $font-family - The font family name. 56 | // @param {String} $file-path - The path to the font family. 57 | // @param {String|List} $file-formats [("ttf", "woff2", "woff")] 58 | // A list of file formats to support, 59 | // for example ("eot", "ttf", "svg", "woff2", "woff"). 60 | // 61 | // @content 62 | // Any additional CSS properties that are included in the `@include` 63 | // directive will be output within the `@font-face` declaration, e.g. 64 | // you can pass in `font-weight`, `font-style` and/or `unicode-range`. 65 | // 66 | // @example scss 67 | // @include font-face( 68 | // "source-sans-pro", 69 | // "fonts/source-sans-pro-regular", 70 | // ("woff2", "woff") 71 | // ) { 72 | // font-style: normal; 73 | // font-weight: 400; 74 | // } 75 | // 76 | // // CSS Output 77 | // @font-face { 78 | // font-family: "source-sans-pro"; 79 | // src: url("fonts/source-sans-pro-regular.woff2") format("woff2"), 80 | // url("fonts/source-sans-pro-regular.woff") format("woff"); 81 | // font-style: normal; 82 | // font-weight: 400; 83 | // } 84 | // 85 | // @require {function} _font-source-declaration 86 | // @require {function} _retrieve-bourbon-setting 87 | // 88 | @mixin font-face( 89 | $font-family, 90 | $file-path, 91 | $file-formats: $global-font-file-formats 92 | ) { 93 | @font-face { 94 | font-family: $font-family; 95 | src: font-source-declaration( $font-family, $file-path, $file-formats); 96 | @content; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /assets/styles/tools/_functions.scss: -------------------------------------------------------------------------------- 1 | // Tools / Functions 2 | // ========================================================================== 3 | 4 | // 5 | // Converts the given pixel value to its EM quivalent. 6 | // 7 | // @param {Number} $size - The pixel value to convert. 8 | // @param {Number} $base [$font-size] - The assumed base font size. 9 | // @return {Number} Scalable pixel value in EMs. 10 | // 11 | @function em($size, $base: $font-size) { 12 | @if (type-of($size) == number) { 13 | @if (unit($size) != "px") { 14 | @error "`#{$size}` needs to be a pixel value."; 15 | } 16 | } @else { 17 | @error "`#{$size}` needs to be a number."; 18 | } 19 | 20 | @if (type-of($base) == number) { 21 | @if (unit($base) != "px") { 22 | @error "`#{$base}` needs to be a pixel value."; 23 | } 24 | } @else { 25 | @error "`#{$base}` needs to be a number."; 26 | } 27 | 28 | @return ($size / $base) * 1em; 29 | } 30 | 31 | // 32 | // Converts the given pixel value to its REM quivalent. 33 | // 34 | // @param {Number} $size - The pixel value to convert. 35 | // @param {Number} $base [$font-size] - The assumed base font size. 36 | // @return {Number} Scalable pixel value in REMs. 37 | // 38 | @function rem($size, $base: $font-size) { 39 | @if (type-of($size) == number) { 40 | @if (unit($size) != "px") { 41 | @error "`#{$size}` needs to be a pixel value."; 42 | } 43 | } @else { 44 | @error "`#{$size}` needs to be a number."; 45 | } 46 | 47 | @if (type-of($base) == number) { 48 | @if (unit($base) != "px") { 49 | @error "`#{$base}` needs to be a pixel value."; 50 | } 51 | } @else { 52 | @error "`#{$base}` needs to be a number."; 53 | } 54 | 55 | @return ($size / $base) * 1rem; 56 | } 57 | 58 | // 59 | // Converts a number to a percentage. 60 | // 61 | // @alias percentage() 62 | // @link http://sassdoc.com/annotations/#alias 63 | // @param {Number} $number - The value to convert. 64 | // @return {Number} A percentage. 65 | // 66 | @function span($number) { 67 | @return percentage($number); 68 | } 69 | 70 | // 71 | // Checks if a list contains a value(s). 72 | // 73 | // @link https://github.com/thoughtbot/bourbon/blob/master/core/bourbon/validators/_contains.scss 74 | // @param {List} $list - The list to check against. 75 | // @param {List} $values - A single value or list of values to check for. 76 | // @return {Boolean} 77 | // @access private 78 | // 79 | @function list-contains( 80 | $list, 81 | $values... 82 | ) { 83 | @each $value in $values { 84 | @if type-of(index($list, $value)) != "number" { 85 | @return false; 86 | } 87 | } 88 | 89 | @return true; 90 | } 91 | 92 | // 93 | // Resolve whether a rule is important or not. 94 | // 95 | // @param {Boolean} $flag - Whether a rule is important (TRUE) or not (FALSE). 96 | // @return {String|Null} Returns `!important` or NULL. 97 | // 98 | @function important($flag: false) { 99 | @if ($flag == true) { 100 | @return !important; 101 | } @elseif ($important == false) { 102 | @return null; 103 | } @else { 104 | @error "`#{$flag}` needs to be `true` or `false`." 105 | } 106 | } 107 | 108 | // 109 | // Determine if the current context is for a WYSIWYG editor. 110 | // 111 | // @requires {String} $context - The global context of the stylesheet. 112 | // @return {Boolean} If the $context is set to "editor". 113 | // 114 | @function is-editor() { 115 | @return ('editor' == $context); 116 | } 117 | 118 | // 119 | // Determine if the current context is for the front-end. 120 | // 121 | // @requires {String} $context - The global context of the stylesheet. 122 | // @return {Boolean} If the $context is set to "frontend". 123 | // 124 | @function is-frontend() { 125 | @return ('frontend' == $context); 126 | } 127 | 128 | $context: 'frontend' !default; 129 | -------------------------------------------------------------------------------- /assets/styles/tools/_layout.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Tools / Layout 3 | // ========================================================================== 4 | 5 | // 6 | // Grid-like layout system. 7 | // 8 | // The layout tools provide a column-style layout system. This file contains 9 | // the mixins to generate basic structural elements. 10 | // 11 | // @link https://github.com/inuitcss/inuitcss/blob/0420ba8/objects/_objects.layout.scss 12 | // 13 | 14 | // 15 | // Generate the layout container. 16 | // 17 | // 1. Use the negative margin trick for multi-row grids: 18 | // http://csswizardry.com/2011/08/building-better-grid-systems/ 19 | // 20 | // @requires {function} u-list-reset 21 | // @output `font-size`, `margin`, `padding`, `list-style` 22 | // 23 | @mixin o-layout($gutter: 0, $fix-whitespace: true) { 24 | margin: 0; 25 | padding: 0; 26 | list-style: none; 27 | 28 | @if ($fix-whitespace) { 29 | font-size: 0; 30 | } 31 | 32 | @if (type-of($gutter) == number) { 33 | margin-left: -$gutter; // [1] 34 | } 35 | } 36 | 37 | // 38 | // Generate the layout item. 39 | // 40 | // 1. Required in order to combine fluid widths with fixed gutters. 41 | // 2. Allows us to manipulate grids vertically, with text-level properties, 42 | // etc. 43 | // 3. Default item alignment is with the tops of each other, like most 44 | // traditional grid/layout systems. 45 | // 4. By default, all layout items are full-width (mobile first). 46 | // 5. Gutters provided by left padding: 47 | // http://csswizardry.com/2011/08/building-better-grid-systems/ 48 | // 49 | @mixin o-layout_item($gutter: 0, $fix-whitespace: true) { 50 | display: inline-block; // [2] 51 | width: 100%; // [4] 52 | vertical-align: top; // [3] 53 | 54 | @if ($fix-whitespace) { 55 | font-size: 1rem; 56 | } 57 | 58 | @if (type-of($gutter) == number) { 59 | padding-left: $gutter; // [5] 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /assets/styles/tools/_mixins.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Tools / Mixins 3 | // ========================================================================== 4 | 5 | // 6 | // Set the color of the highlight that appears over a link while it's being tapped. 7 | // 8 | // By default, the highlight is suppressed. 9 | // 10 | // @param {Color} $value [rgba(0, 0, 0, 0)] - The value of the highlight. 11 | // @output `-webkit-tap-highlight-color` 12 | // 13 | @mixin tap-highlight-color($value: rgba(0, 0, 0, 0)) { 14 | -webkit-tap-highlight-color: $value; 15 | } 16 | 17 | // 18 | // Set whether or not touch devices use momentum-based scrolling for the given element. 19 | // 20 | // By default, applies momentum-based scrolling for the current element. 21 | // 22 | // @param {String} $value [rgba(0, 0, 0, 0)] - The type of scrolling. 23 | // @output `-webkit-overflow-scrolling` 24 | // 25 | @mixin overflow-scrolling($value: touch) { 26 | -webkit-overflow-scrolling: $value; 27 | } 28 | 29 | // 30 | // Micro clearfix rules for containing floats. 31 | // 32 | // @link http://www.cssmojo.com/the-very-latest-clearfix-reloaded/ 33 | // @param {List} $supports The type of clearfix to generate. 34 | // @output Injects `:::after` pseudo-element. 35 | // 36 | @mixin u-clearfix($supports...) { 37 | &::after { 38 | display: if(list-contains($supports, table), table, block); 39 | clear: both; 40 | content: if(list-contains($supports, opera), " ", ""); 41 | } 42 | } 43 | 44 | // 45 | // Generate a font-size and baseline-compatible line-height. 46 | // 47 | // @link https://github.com/inuitcss/inuitcss/c14029c/tools/_tools.font-size.scss 48 | // @param {Number} $font-size - The size of the font. 49 | // @param {Number} $line-height [auto] - The line box height. 50 | // @param {Boolean} $important [false] - Whether the font-size is important. 51 | // @output `font-size`, `line-height` 52 | // 53 | @mixin font-size($font-size, $line-height: auto, $important: false) { 54 | $important: important($important); 55 | font-size: rem($font-size) $important; 56 | 57 | @if ($line-height == "auto") { 58 | line-height: ceil($font-size / $line-height) * ($line-height / $font-size) $important; 59 | } 60 | @else { 61 | @if (type-of($line-height) == number or $line-height == "inherit" or $line-height == "normal") { 62 | line-height: $line-height $important; 63 | } 64 | @elseif ($line-height != "none" and $line-height != false) { 65 | @error "D’oh! `#{$line-height}` is not a valid value for `$line-height`." 66 | } 67 | } 68 | } 69 | 70 | // 71 | // Vertically-center the direct descendants of the current element. 72 | // 73 | // Centering is achieved by displaying children as inline-blocks. Any whitespace 74 | // between elements is nullified by redefining the font size of the container 75 | // and its children. 76 | // 77 | // @output `font-size`, `display`, `vertical-align` 78 | // 79 | @mixin o-vertical-center { 80 | font-size: 0; 81 | 82 | &::before { 83 | display: inline-block; 84 | height: 100%; 85 | content: ""; 86 | vertical-align: middle; 87 | } 88 | 89 | > * { 90 | display: inline-block; 91 | vertical-align: middle; 92 | font-size: 1rem; 93 | } 94 | } 95 | 96 | // 97 | // Generate `:hover` and `:focus` styles in one go. 98 | // 99 | // @link https://github.com/inuitcss/inuitcss/blob/master/tools/_tools.mixins.scss 100 | // @content Wrapped in `:focus` and `:hover` pseudo-classes. 101 | // @output Wraps the given content in `:focus` and `:hover` pseudo-classes. 102 | // 103 | @mixin u-hocus { 104 | &:focus, 105 | &:hover { 106 | @content; 107 | } 108 | } 109 | 110 | // 111 | // Generate `:active` and `:focus` styles in one go. 112 | // 113 | // @see {Mixin} u-hocus 114 | // @content Wrapped in `:focus` and `:active` pseudo-classes. 115 | // @output Wraps the given content in `:focus` and `:hover` pseudo-classes. 116 | // 117 | @mixin u-actus { 118 | &:focus, 119 | &:active { 120 | @content; 121 | } 122 | } 123 | 124 | // 125 | // Prevent text from wrapping onto multiple lines for the current element. 126 | // 127 | // An ellipsis is appended to the end of the line. 128 | // 129 | // 1. Ensure that the node has a maximum width after which truncation can occur. 130 | // 2. Fix for IE 8/9 if `word-wrap: break-word` is in effect on ancestor nodes. 131 | // 132 | // @param {Number} $width [100%] - The maximum width of element. 133 | // @output `max-width`, `word-wrap`, `white-space`, `overflow`, `text-overflow` 134 | // 135 | @mixin u-truncate($width: 100%) { 136 | overflow: hidden; 137 | text-overflow: ellipsis; 138 | white-space: nowrap; 139 | word-wrap: normal; // [2] 140 | @if $width { 141 | max-width: $width; // [1] 142 | } 143 | } 144 | 145 | // 146 | // Applies accessible hiding to the current element. 147 | // 148 | // @param {Boolean} $important [true] - Whether the visibility is important. 149 | // @output Properties for removing the element from the document flow. 150 | // 151 | @mixin u-accessibly-hidden($important: true) { 152 | $important: important($important); 153 | position: absolute $important; 154 | overflow: hidden; 155 | clip: rect(0 0 0 0); 156 | margin: 0; 157 | padding: 0; 158 | width: 1px; 159 | height: 1px; 160 | border: 0; 161 | } 162 | 163 | // 164 | // Allows an accessibly hidden element to be focusable via keyboard navigation. 165 | // 166 | // @content For styling the now visible element. 167 | // @output Injects `:focus`, `:active` pseudo-classes. 168 | // 169 | @mixin u-accessibly-focusable { 170 | @include u-actus { 171 | clip: auto; 172 | width: auto; 173 | height: auto; 174 | 175 | @content; 176 | } 177 | } 178 | 179 | // 180 | // Hide the current element from all. 181 | // 182 | // The element will be hidden from screen readers and removed from the document flow. 183 | // 184 | // @link http://juicystudio.com/article/screen-readers-display-none.php 185 | // @param {Boolean} $important [true] - Whether the visibility is important. 186 | // @output `display`, `visibility` 187 | // 188 | @mixin u-hidden($important: true) { 189 | $important: important($important); 190 | display: none $important; 191 | visibility: hidden $important; 192 | } 193 | 194 | // 195 | // Show the current element for all. 196 | // 197 | // The element will be accessible from screen readers and visible in the document flow. 198 | // 199 | // @param {String} $display [block] - The rendering box used for the element. 200 | // @param {Boolean} $important [true] - Whether the visibility is important. 201 | // @output `display`, `visibility` 202 | // 203 | @mixin u-shown($display: block, $important: true) { 204 | $important: important($important); 205 | display: $display $important; 206 | visibility: visible $important; 207 | } 208 | -------------------------------------------------------------------------------- /assets/styles/tools/_widths.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Tools / Widths 3 | // ========================================================================== 4 | 5 | // Optionally, the boilerplate can generate classes to offset items by a 6 | // certain width. Would you like to generate these types of class as well? E.g.: 7 | // 8 | // @example css 9 | // .u-push-1/3 10 | // .u-pull-2/4 11 | // .u-pull-1/5 12 | // .u-push-2/3 13 | $widths-offsets: false !default; 14 | 15 | // By default, the boilerplate uses fractions-like classes like `
`. 16 | // You can change the `/` to whatever you fancy with this variable. 17 | $fractions-delimiter: \/ !default; 18 | 19 | // When using Sass-MQ, this defines the separator for the breakpoints suffix 20 | // in the class name. By default, we are generating the responsive suffixes 21 | // for the classes with a `@` symbol so you get classes like: 22 | //
23 | $breakpoint-delimiter: \@ !default; 24 | 25 | // 26 | // Generate a series of width helper classes 27 | // 28 | // @example scss 29 | // @include widths(12); 30 | // 31 | // @example html 32 | //
33 | // 34 | // @example scss 35 | // @include widths(3 4, -mobile); 36 | // 37 | // @example html 38 | //
39 | // 40 | // @link https://github.com/inuitcss/inuitcss/commit/6eb574f/utilities/_utilities.widths.scss 41 | // @requires {Function} important 42 | // @requires {Function} $widths-offsets 43 | // @requires {Function} $fractions-delimiter 44 | // @requires {Function} $breakpoint-delimiter 45 | // @param {List} $colums - The columns we want the widths to have. 46 | // @param {String} $breakpoint - Optional suffix for responsive widths. 47 | // @output `width`, `position`, `right`, `left` 48 | // 49 | @mixin widths($columns, $breakpoint: null, $important: true) { 50 | $important: important($important); 51 | 52 | // Loop through the number of columns for each denominator of our fractions. 53 | @each $denominator in $columns { 54 | // Begin creating a numerator for our fraction up until we hit the 55 | // denominator. 56 | @for $numerator from 1 through $denominator { 57 | // Build a class in the format `.u-3/4[@]`. 58 | .u-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} { 59 | width: ($numerator / $denominator) * 100% $important; 60 | } 61 | 62 | @if ($widths-offsets == true) { 63 | // Build a class in the format `.u-push-1/2[@]`. 64 | .u-push-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} { 65 | position: relative $important; 66 | right: auto $important; 67 | left: ($numerator / $denominator) * 100% $important; 68 | } 69 | 70 | // Build a class in the format `.u-pull-5/6[@]`. 71 | .u-pull-#{$numerator}#{$fractions-delimiter}#{$denominator}#{$breakpoint} { 72 | position: relative $important; 73 | right: ($numerator / $denominator) * 100% $important; 74 | left: auto $important; 75 | } 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /assets/styles/utilities/_align.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Alignment 3 | // ========================================================================== 4 | 5 | // Floats 6 | // ========================================================================== 7 | .u-float-left { 8 | float: left !important; 9 | } 10 | 11 | .u-float-right { 12 | float: right !important; 13 | } 14 | 15 | // Horizontal Text 16 | // ========================================================================== 17 | .u-text-center { 18 | text-align: center !important; 19 | } 20 | 21 | .u-text-left { 22 | text-align: left !important; 23 | } 24 | 25 | .u-text-right { 26 | text-align: right !important; 27 | } 28 | 29 | // Vertical Text 30 | // ========================================================================== 31 | .u-align-baseline { 32 | vertical-align: baseline !important; 33 | } 34 | 35 | .u-align-bottom { 36 | vertical-align: bottom !important; 37 | } 38 | 39 | .u-align-middle { 40 | vertical-align: middle !important; 41 | } 42 | 43 | .u-align-top { 44 | vertical-align: top !important; 45 | } 46 | 47 | .u-vertical-center { 48 | @include o-vertical-center; 49 | } 50 | -------------------------------------------------------------------------------- /assets/styles/utilities/_helpers.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Helpers 3 | // ========================================================================== 4 | 5 | // Layout 6 | // ========================================================================== 7 | .u-clearfix { 8 | @include u-clearfix; 9 | } 10 | 11 | // Decorative 12 | // ============================================================================= 13 | .u-truncate { 14 | @include u-truncate; 15 | } 16 | 17 | // Visibility / Display 18 | // ========================================================================== 19 | [hidden][aria-hidden="false"] { 20 | position: absolute; 21 | display: inherit; 22 | clip: rect(0, 0, 0, 0); 23 | } 24 | 25 | [hidden][aria-hidden="false"]:focus { 26 | clip: auto; 27 | } 28 | 29 | // .u-block { 30 | // display: block; 31 | // } 32 | 33 | // /** 34 | // * 1. Fix for Firefox bug: an image styled `max-width:100%` within an 35 | // * inline-block will display at its default size, and not limit its width to 36 | // * 100% of an ancestral container. 37 | // */ 38 | // .u-inline-block { 39 | // display: inline-block !important; 40 | // max-width: 100%; /* 1 */ 41 | // } 42 | 43 | // .u-inline { 44 | // display: inline !important; 45 | // } 46 | 47 | // .u-table { 48 | // display: table !important; 49 | // } 50 | 51 | // .u-tableCell { 52 | // display: table-cell !important; 53 | // } 54 | 55 | // .u-tableRow { 56 | // display: table-row !important; 57 | // } 58 | 59 | /** 60 | * Completely remove from the flow but leave available to screen readers. 61 | */ 62 | .u-screen-reader-text { 63 | @include u-accessibly-hidden; 64 | } 65 | 66 | @media not print { 67 | .u-screen-reader-text\@screen { 68 | @include u-accessibly-hidden; 69 | } 70 | } 71 | 72 | /* 73 | * Extends the `.screen-reader-text` class to allow the element 74 | * to be focusable when navigated to via the keyboard. 75 | * 76 | * @link https://www.drupal.org/node/897638 77 | * @todo Define styles when focused. 78 | */ 79 | .u-screen-reader-text.-focusable { 80 | @include u-accessibly-focusable; 81 | } 82 | -------------------------------------------------------------------------------- /assets/styles/utilities/_print.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Print Mode 3 | // ========================================================================== 4 | 5 | //// 6 | /// Very crude, reset-like styles taken from the HTML5 Boilerplate: 7 | /// - https://github.com/h5bp/html5-boilerplate/blob/5.3.0/dist/doc/css.md#print-styles 8 | /// - https://github.com/h5bp/html5-boilerplate/blob/master/dist/css/main.css#L205-L282 9 | /// 10 | /// @link https://github.com/inuitcss/inuitcss/blob/c27993f/utilities/_utilities.print.scss 11 | //// 12 | 13 | @media print { 14 | /** 15 | * 1. Black prints faster: http://www.sanbeiji.com/archives/953 16 | */ 17 | *, 18 | *:before, 19 | *:after, 20 | *:first-letter, 21 | *:first-line { 22 | background: transparent !important; 23 | box-shadow: none !important; 24 | color: #000000 !important; /* [1] */ 25 | text-shadow: none !important; 26 | } 27 | 28 | a, 29 | a:visited { 30 | text-decoration: underline; 31 | } 32 | 33 | a[href]:after { 34 | content: " (" attr(href) ")"; 35 | } 36 | 37 | abbr[title]:after { 38 | content: " (" attr(title) ")"; 39 | } 40 | 41 | /** 42 | * Don't show links that are fragment identifiers, or use the `javascript:` 43 | * pseudo protocol. 44 | */ 45 | a[href^="#"]:after, 46 | a[href^="javascript:"]:after { 47 | content: ""; 48 | } 49 | 50 | pre, 51 | blockquote { 52 | border: 1px solid #999999; 53 | page-break-inside: avoid; 54 | } 55 | 56 | /** 57 | * Printing Tables: http://css-discuss.incutio.com/wiki/Printing_Tables 58 | */ 59 | thead { 60 | display: table-header-group; 61 | } 62 | 63 | tr, 64 | img { 65 | page-break-inside: avoid; 66 | } 67 | 68 | 69 | img { 70 | max-width: 100% !important; 71 | } 72 | 73 | p, 74 | h2, 75 | h3 { 76 | orphans: 3; 77 | widows: 3; 78 | } 79 | 80 | h2, 81 | h3 { 82 | page-break-after: avoid; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /assets/styles/utilities/_ratio.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Ratio 3 | // ========================================================================== 4 | 5 | // 6 | // @link https://github.com/inuitcss/inuitcss/blob/19d0c7e/objects/_objects.ratio.scss 7 | // 8 | 9 | // A list of aspect ratios that get generated as modifier classes. 10 | 11 | $aspect-ratios: ( 12 | (2:1), 13 | (4:3), 14 | (16:9), 15 | ) !default; 16 | 17 | /* stylelint-disable */ 18 | 19 | // 20 | // Generate a series of ratio classes to be used like so: 21 | // 22 | // @example 23 | //
24 | // 25 | // 26 | @each $ratio in $aspect-ratios { 27 | @each $antecedent, $consequent in $ratio { 28 | @if (type-of($antecedent) != number) { 29 | @error "`#{$antecedent}` needs to be a number." 30 | } 31 | 32 | @if (type-of($consequent) != number) { 33 | @error "`#{$consequent}` needs to be a number." 34 | } 35 | 36 | &.u-#{$antecedent}\:#{$consequent}::before { 37 | padding-bottom: ($consequent/$antecedent) * 100%; 38 | } 39 | } 40 | } 41 | 42 | /* stylelint-enable */ 43 | -------------------------------------------------------------------------------- /assets/styles/utilities/_spacing.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Spacing 3 | // ========================================================================== 4 | 5 | //// 6 | /// Utility classes to put specific spacing values onto elements. The below loop 7 | /// will generate us a suite of classes like: 8 | /// 9 | /// @example 10 | /// .u-margin-top {} 11 | /// .u-padding-left-large {} 12 | /// .u-margin-right-small {} 13 | /// .u-padding {} 14 | /// .u-padding-right-none {} 15 | /// .u-padding-horizontal {} 16 | /// .u-padding-vertical-small {} 17 | /// 18 | /// @link https://github.com/inuitcss/inuitcss/blob/512977a/utilities/_utilities.spacing.scss 19 | //// 20 | 21 | /* stylelint-disable string-quotes */ 22 | 23 | $spacing-directions: ( 24 | null: null, 25 | '-top': '-top', 26 | '-right': '-right', 27 | '-bottom': '-bottom', 28 | '-left': '-left', 29 | '-horizontal': '-left' '-right', 30 | '-vertical': '-top' '-bottom', 31 | ) !default; 32 | 33 | $spacing-properties: ( 34 | 'padding': 'padding', 35 | 'margin': 'margin', 36 | ) !default; 37 | 38 | $spacing-sizes: ( 39 | null: $unit, 40 | '-small': $unit-small, 41 | '-none': 0 42 | ) !default; 43 | 44 | @each $property-namespace, $property in $spacing-properties { 45 | @each $direction-namespace, $direction-rules in $spacing-directions { 46 | @each $size-namespace, $size in $spacing-sizes { 47 | .u-#{$property-namespace}#{$direction-namespace}#{$size-namespace} { 48 | @each $direction in $direction-rules { 49 | #{$property}#{$direction}: $size !important; 50 | } 51 | } 52 | } 53 | } 54 | } 55 | 56 | /* stylelint-enable string-quotes */ 57 | -------------------------------------------------------------------------------- /assets/styles/utilities/_states.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / States 3 | // ========================================================================== 4 | 5 | /** 6 | * ARIA roles display visual cursor hints 7 | */ 8 | [aria-busy="true"] { 9 | cursor: progress; 10 | } 11 | 12 | [aria-controls] { 13 | cursor: pointer; 14 | } 15 | 16 | [aria-disabled] { 17 | cursor: default; 18 | } 19 | 20 | /** 21 | * Control visibility without affecting flow. 22 | */ 23 | 24 | .is-visible { 25 | visibility: visible !important; 26 | opacity: 1 !important; 27 | } 28 | 29 | .is-invisible { 30 | visibility: hidden !important; 31 | opacity: 0 !important; 32 | } 33 | 34 | /** 35 | * Completely remove from the flow and screen readers. 36 | */ 37 | 38 | .is-hidden { 39 | @include u-hidden; 40 | } 41 | 42 | @media not print { 43 | .is-hidden\@screen { 44 | @include u-hidden; 45 | } 46 | } 47 | 48 | @media print { 49 | .is-hidden\@print { 50 | @include u-hidden; 51 | } 52 | } 53 | 54 | // .is-hidden\@to-large { 55 | // @media (max-width: $to-large) { 56 | // display: none; 57 | // } 58 | // } 59 | 60 | // .is-hidden\@from-large { 61 | // @media (min-width: $from-large) { 62 | // display: none; 63 | // } 64 | // } 65 | 66 | // /** 67 | // * Display a hidden-by-default element. 68 | // */ 69 | 70 | // .is-shown { 71 | // @include u-shown; 72 | // } 73 | 74 | // table.is-shown { 75 | // display: table !important; 76 | // } 77 | 78 | // tr.is-shown { 79 | // display: table-row !important; 80 | // } 81 | 82 | // td.is-shown, 83 | // th.is-shown { 84 | // display: table-cell !important; 85 | // } 86 | -------------------------------------------------------------------------------- /assets/styles/utilities/_widths.scss: -------------------------------------------------------------------------------- 1 | // ========================================================================== 2 | // Utilities / Widths 3 | // ========================================================================== 4 | 5 | //// 6 | /// @link https://github.com/inuitcss/inuitcss/blob/6eb574f/utilities/_utilities.widths.scss 7 | //// 8 | 9 | /// Which fractions would you like in your grid system(s)? 10 | /// By default, the boilerplate provides fractions of one whole, halves, thirds, 11 | /// quarters, and fifths, e.g.: 12 | /// 13 | /// @example css 14 | /// .u-1/2 15 | /// .u-2/5 16 | /// .u-3/4 17 | /// .u-2/3 18 | $widths-fractions: 1 2 3 4 5 !default; 19 | 20 | @include widths($widths-fractions); 21 | 22 | .u-1\/2\@from-small { 23 | @media (min-width: $from-small) { 24 | width: span(1/2); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /assets/styles/vendors/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/assets/styles/vendors/.gitkeep -------------------------------------------------------------------------------- /build/build.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import postcss from 'gulp-postcss'; 3 | import cssnano from 'cssnano'; 4 | import uglify from 'gulp-uglify'; 5 | import htmlmin from 'gulp-htmlmin'; 6 | import paths from '../mconfig.json'; 7 | 8 | function buildStyles() { 9 | const plugins = [ 10 | cssnano() 11 | ]; 12 | 13 | return gulp 14 | .src(paths.styles.dest + '*.css') 15 | .pipe(postcss(plugins)) 16 | .pipe(gulp.dest(paths.styles.dest)); 17 | } 18 | 19 | function buildScripts() { 20 | return gulp 21 | .src(paths.scripts.dest + '*.js') 22 | .pipe(uglify()) 23 | .pipe(gulp.dest(paths.scripts.dest)); 24 | } 25 | 26 | function buildViews() { 27 | return gulp 28 | .src(paths.dest + '*.html') 29 | .pipe(htmlmin('collapseWhitespace: true')) 30 | .pipe(gulp.dest(paths.dest)); 31 | } 32 | 33 | export { buildStyles, buildScripts, buildViews }; 34 | -------------------------------------------------------------------------------- /build/concat.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import gulpConcat from 'gulp-concat'; 3 | import paths from '../mconfig.json'; 4 | 5 | function concat() { 6 | return gulp 7 | .src([ 8 | `${paths.scripts.vendors.src}*.js`, 9 | 'node_modules/gsap/dist/gsap.min.js', 10 | 'node_modules/dat.gui/build/dat.gui.min.js' 11 | ]) 12 | .pipe(gulpConcat(`${paths.scripts.vendors.main}.js`)) 13 | .pipe(gulp.dest(paths.scripts.dest)); 14 | } 15 | 16 | export default concat; 17 | -------------------------------------------------------------------------------- /build/error.js: -------------------------------------------------------------------------------- 1 | import notify from './notify.js'; 2 | 3 | function error(object, error, type) { 4 | const message = (type == 'stack') ? error.stack : error.toString(); 5 | console.error(message); 6 | notify('Error', error.message); 7 | object.emit('end'); 8 | } 9 | 10 | export default error; 11 | -------------------------------------------------------------------------------- /build/notify.js: -------------------------------------------------------------------------------- 1 | import notifier from 'node-notifier'; 2 | 3 | function notify(title, message) { 4 | notifier.notify({ 5 | title: title, 6 | message: message 7 | }); 8 | } 9 | 10 | export default notify; 11 | -------------------------------------------------------------------------------- /build/scripts.js: -------------------------------------------------------------------------------- 1 | import { rollup } from 'rollup'; 2 | import resolve from 'rollup-plugin-node-resolve'; 3 | import babel from 'rollup-plugin-babel'; 4 | import common from 'rollup-plugin-commonjs'; 5 | import paths from '../mconfig.json'; 6 | 7 | function scripts() { 8 | return rollup({ 9 | input: paths.scripts.src + paths.scripts.main + '.js', 10 | plugins: [ 11 | resolve(), 12 | babel({ 13 | exclude: 'node_modules/**' 14 | }), 15 | common({ 16 | include: 'node_modules/**' 17 | }), 18 | ] 19 | }).then(bundle => { 20 | return bundle.write({ 21 | file: paths.scripts.dest + paths.scripts.main + '.js', 22 | name: paths.scripts.main, 23 | format: 'iife', 24 | sourcemap: true 25 | }); 26 | }); 27 | } 28 | 29 | export default scripts; 30 | -------------------------------------------------------------------------------- /build/serve.js: -------------------------------------------------------------------------------- 1 | import browserSync from 'browser-sync'; 2 | import paths from '../mconfig.json'; 3 | 4 | export const server = browserSync.create(); 5 | 6 | function serve(done) { 7 | server.init({ 8 | notify: false, 9 | proxy: paths.url, 10 | host: paths.url, 11 | open: 'external' 12 | }); 13 | done(); 14 | } 15 | 16 | export default serve; 17 | -------------------------------------------------------------------------------- /build/styles.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import sass from 'gulp-sass'; 3 | import autoprefixer from 'gulp-autoprefixer'; 4 | import paths from '../mconfig.json'; 5 | import error from './error.js'; 6 | import { server } from './serve.js'; 7 | 8 | function styles() { 9 | return gulp 10 | .src(paths.styles.src + '**/*.scss') 11 | .pipe(sass()) 12 | .on('error', function(err) { 13 | error(this, err, 'stack'); 14 | }) 15 | .pipe(autoprefixer({ 16 | cascade: false 17 | })) 18 | .pipe(gulp.dest(paths.styles.dest)) 19 | .pipe(server.stream()); 20 | } 21 | 22 | export default styles; 23 | -------------------------------------------------------------------------------- /build/svgs.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import path from 'path'; 3 | import rename from 'gulp-rename'; 4 | import svgstore from 'gulp-svgstore'; 5 | import paths from '../mconfig.json'; 6 | import error from './error.js'; 7 | 8 | function svgs() { 9 | return gulp 10 | .src(paths.svgs.src + '**/*.svg', { base: paths.svgs.src }) 11 | .pipe(rename(function(file) { 12 | if (file.dirname != '.') { 13 | const name = file.dirname.split(path.sep); 14 | name.push(file.basename); 15 | file.basename = name.join('-'); 16 | } 17 | })) 18 | .pipe(svgstore()) 19 | .on('error', function(err) { 20 | error(this, err); 21 | }) 22 | .pipe(gulp.dest(paths.svgs.dest)); 23 | } 24 | 25 | export default svgs; 26 | -------------------------------------------------------------------------------- /build/watch.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import paths from '../mconfig.json'; 3 | import styles from './styles.js'; 4 | import scripts from './scripts.js'; 5 | import svgs from './svgs.js'; 6 | import concat from './concat.js'; 7 | import { server } from './serve.js'; 8 | 9 | function watch() { 10 | gulp.watch(paths.styles.src, styles); 11 | gulp.watch(paths.scripts.src, gulp.series(scripts, reload)); 12 | gulp.watch(paths.scripts.vendors.src, concat); 13 | gulp.watch(paths.views.src, reload); 14 | gulp.watch(paths.svgs.src, gulp.series(svgs, reload)); 15 | } 16 | 17 | function reload(done) { 18 | server.reload(); 19 | done(); 20 | } 21 | 22 | export default watch; 23 | -------------------------------------------------------------------------------- /docs/axis.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/docs/axis.jpg -------------------------------------------------------------------------------- /docs/positionExample.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/docs/positionExample.jpg -------------------------------------------------------------------------------- /gulpfile.babel.js: -------------------------------------------------------------------------------- 1 | import gulp from 'gulp'; 2 | import styles from './build/styles.js'; 3 | import scripts from './build/scripts.js'; 4 | import concat from './build/concat.js'; 5 | import svgs from './build/svgs.js'; 6 | import serve from './build/serve.js'; 7 | import watch from './build/watch.js'; 8 | import { buildStyles, buildScripts } from './build/build.js'; 9 | 10 | const compile = gulp.series(styles, scripts, svgs, concat); 11 | const main = gulp.series(compile, serve, watch); 12 | const build = gulp.series(compile, buildStyles, buildScripts); 13 | 14 | gulp.task('default', main); 15 | gulp.task('compile', compile); 16 | gulp.task('build', build); 17 | -------------------------------------------------------------------------------- /mconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "url": "webgl-images.test", 3 | "src": "./assets/", 4 | "dest": "./www/", 5 | "build": "./build/", 6 | "styles": { 7 | "src": "./assets/styles/", 8 | "dest": "./www/assets/styles/", 9 | "main": "main" 10 | }, 11 | "scripts": { 12 | "src": "./assets/scripts/", 13 | "dest": "./www/assets/scripts/", 14 | "main": "app", 15 | "vendors": { 16 | "src": "./assets/scripts/vendors/", 17 | "main": "vendors" 18 | } 19 | }, 20 | "svgs": { 21 | "src": "./assets/images/sprite/", 22 | "dest": "./www/assets/images/" 23 | }, 24 | "views": { 25 | "src": "./*.html" 26 | }, 27 | "modules": { 28 | "build": "gulp", 29 | "style": "sass", 30 | "script": "js", 31 | "view": false 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "@locomotivemtl/boilerplate", 4 | "title": "Locomotive Boilerplate", 5 | "version": "1.0.0", 6 | "author": "Locomotive ", 7 | "dependencies": { 8 | "dat.gui": "^0.7.6", 9 | "gsap": "^3.6.0", 10 | "locomotive-scroll": "*", 11 | "modujs": "*", 12 | "modularload": "*", 13 | "normalize.css": "*", 14 | "ogl": "0.0.46", 15 | "svg4everybody": "*" 16 | }, 17 | "devDependencies": { 18 | "@modularbp/gulp": "^1.0.5", 19 | "@modularbp/gulp-build": "^1.0.1", 20 | "@modularbp/gulp-error": "^1.0.3", 21 | "@modularbp/gulp-js": "^1.0.8", 22 | "@modularbp/gulp-notify": "^1.0.3", 23 | "@modularbp/gulp-sass": "^1.0.7", 24 | "@modularbp/gulp-serve": "^1.0.5", 25 | "@modularbp/gulp-svg": "^1.0.5", 26 | "@modularbp/gulp-watch": "^1.0.5", 27 | "gulp-concat": "*", 28 | "mbp": "^1.3.0" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /www/assets/emails/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Boilerplate 6 | 7 | 8 |
9 | 10 | 11 | 32 | 33 |
12 | 13 | 14 | 29 | 30 |
15 | 16 | 17 | 26 | 27 |
18 |

Heading 1

19 |

Heading 2

20 |

Heading 3

21 |

Heading 4

22 |

23 | After you enter your content, highlight the text you want to style and select the options you set in the style editor in the "styles" drop down box. Want to 24 |

25 |
28 |
31 |
34 |
35 | 36 | 37 | -------------------------------------------------------------------------------- /www/assets/fonts/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/fonts/.gitkeep -------------------------------------------------------------------------------- /www/assets/images/favicons/android-chrome-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/favicons/android-chrome-144x144.png -------------------------------------------------------------------------------- /www/assets/images/favicons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/favicons/apple-touch-icon.png -------------------------------------------------------------------------------- /www/assets/images/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /www/assets/images/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /www/assets/images/favicons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/favicons/mstile-150x150.png -------------------------------------------------------------------------------- /www/assets/images/favicons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.11, written by Peter Selinger 2001-2013 9 | 10 | 12 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /www/assets/images/image-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/image-1.jpg -------------------------------------------------------------------------------- /www/assets/images/image-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/image-2.jpg -------------------------------------------------------------------------------- /www/assets/images/image-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/image-3.jpg -------------------------------------------------------------------------------- /www/assets/images/image-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/image-4.jpg -------------------------------------------------------------------------------- /www/assets/images/linear-h-displacement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/linear-h-displacement.jpg -------------------------------------------------------------------------------- /www/assets/images/linear-v-displacement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/linear-v-displacement.jpg -------------------------------------------------------------------------------- /www/assets/images/radial-displacement.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/radial-displacement.jpg -------------------------------------------------------------------------------- /www/assets/images/radial-displacement.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/assets/images/radial-displacement.png -------------------------------------------------------------------------------- /www/assets/styles/main.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ 2 | /* Document 3 | ========================================================================== */ 4 | /** 5 | * 1. Correct the line height in all browsers. 6 | * 2. Prevent adjustments of font size after orientation changes in iOS. 7 | */ 8 | html { 9 | line-height: 1.15; 10 | /* 1 */ 11 | -webkit-text-size-adjust: 100%; 12 | /* 2 */ } 13 | 14 | /* Sections 15 | ========================================================================== */ 16 | /** 17 | * Remove the margin in all browsers. 18 | */ 19 | body { 20 | margin: 0; } 21 | 22 | /** 23 | * Render the `main` element consistently in IE. 24 | */ 25 | main { 26 | display: block; } 27 | 28 | /** 29 | * Correct the font size and margin on `h1` elements within `section` and 30 | * `article` contexts in Chrome, Firefox, and Safari. 31 | */ 32 | h1 { 33 | font-size: 2em; 34 | margin: 0.67em 0; } 35 | 36 | /* Grouping content 37 | ========================================================================== */ 38 | /** 39 | * 1. Add the correct box sizing in Firefox. 40 | * 2. Show the overflow in Edge and IE. 41 | */ 42 | hr { 43 | box-sizing: content-box; 44 | /* 1 */ 45 | height: 0; 46 | /* 1 */ 47 | overflow: visible; 48 | /* 2 */ } 49 | 50 | /** 51 | * 1. Correct the inheritance and scaling of font size in all browsers. 52 | * 2. Correct the odd `em` font sizing in all browsers. 53 | */ 54 | pre { 55 | font-family: monospace, monospace; 56 | /* 1 */ 57 | font-size: 1em; 58 | /* 2 */ } 59 | 60 | /* Text-level semantics 61 | ========================================================================== */ 62 | /** 63 | * Remove the gray background on active links in IE 10. 64 | */ 65 | a { 66 | background-color: transparent; } 67 | 68 | /** 69 | * 1. Remove the bottom border in Chrome 57- 70 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 71 | */ 72 | abbr[title] { 73 | border-bottom: none; 74 | /* 1 */ 75 | text-decoration: underline; 76 | /* 2 */ 77 | -webkit-text-decoration: underline dotted; 78 | text-decoration: underline dotted; 79 | /* 2 */ } 80 | 81 | /** 82 | * Add the correct font weight in Chrome, Edge, and Safari. 83 | */ 84 | b, 85 | strong { 86 | font-weight: bolder; } 87 | 88 | /** 89 | * 1. Correct the inheritance and scaling of font size in all browsers. 90 | * 2. Correct the odd `em` font sizing in all browsers. 91 | */ 92 | code, 93 | kbd, 94 | samp { 95 | font-family: monospace, monospace; 96 | /* 1 */ 97 | font-size: 1em; 98 | /* 2 */ } 99 | 100 | /** 101 | * Add the correct font size in all browsers. 102 | */ 103 | small { 104 | font-size: 80%; } 105 | 106 | /** 107 | * Prevent `sub` and `sup` elements from affecting the line height in 108 | * all browsers. 109 | */ 110 | sub, 111 | sup { 112 | font-size: 75%; 113 | line-height: 0; 114 | position: relative; 115 | vertical-align: baseline; } 116 | 117 | sub { 118 | bottom: -0.25em; } 119 | 120 | sup { 121 | top: -0.5em; } 122 | 123 | /* Embedded content 124 | ========================================================================== */ 125 | /** 126 | * Remove the border on images inside links in IE 10. 127 | */ 128 | img { 129 | border-style: none; } 130 | 131 | /* Forms 132 | ========================================================================== */ 133 | /** 134 | * 1. Change the font styles in all browsers. 135 | * 2. Remove the margin in Firefox and Safari. 136 | */ 137 | button, 138 | input, 139 | optgroup, 140 | select, 141 | textarea { 142 | font-family: inherit; 143 | /* 1 */ 144 | font-size: 100%; 145 | /* 1 */ 146 | line-height: 1.15; 147 | /* 1 */ 148 | margin: 0; 149 | /* 2 */ } 150 | 151 | /** 152 | * Show the overflow in IE. 153 | * 1. Show the overflow in Edge. 154 | */ 155 | button, 156 | input { 157 | /* 1 */ 158 | overflow: visible; } 159 | 160 | /** 161 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 162 | * 1. Remove the inheritance of text transform in Firefox. 163 | */ 164 | button, 165 | select { 166 | /* 1 */ 167 | text-transform: none; } 168 | 169 | /** 170 | * Correct the inability to style clickable types in iOS and Safari. 171 | */ 172 | button, 173 | [type="button"], 174 | [type="reset"], 175 | [type="submit"] { 176 | -webkit-appearance: button; } 177 | 178 | /** 179 | * Remove the inner border and padding in Firefox. 180 | */ 181 | button::-moz-focus-inner, 182 | [type="button"]::-moz-focus-inner, 183 | [type="reset"]::-moz-focus-inner, 184 | [type="submit"]::-moz-focus-inner { 185 | border-style: none; 186 | padding: 0; } 187 | 188 | /** 189 | * Restore the focus styles unset by the previous rule. 190 | */ 191 | button:-moz-focusring, 192 | [type="button"]:-moz-focusring, 193 | [type="reset"]:-moz-focusring, 194 | [type="submit"]:-moz-focusring { 195 | outline: 1px dotted ButtonText; } 196 | 197 | /** 198 | * Correct the padding in Firefox. 199 | */ 200 | fieldset { 201 | padding: 0.35em 0.75em 0.625em; } 202 | 203 | /** 204 | * 1. Correct the text wrapping in Edge and IE. 205 | * 2. Correct the color inheritance from `fieldset` elements in IE. 206 | * 3. Remove the padding so developers are not caught out when they zero out 207 | * `fieldset` elements in all browsers. 208 | */ 209 | legend { 210 | box-sizing: border-box; 211 | /* 1 */ 212 | color: inherit; 213 | /* 2 */ 214 | display: table; 215 | /* 1 */ 216 | max-width: 100%; 217 | /* 1 */ 218 | padding: 0; 219 | /* 3 */ 220 | white-space: normal; 221 | /* 1 */ } 222 | 223 | /** 224 | * Add the correct vertical alignment in Chrome, Firefox, and Opera. 225 | */ 226 | progress { 227 | vertical-align: baseline; } 228 | 229 | /** 230 | * Remove the default vertical scrollbar in IE 10+. 231 | */ 232 | textarea { 233 | overflow: auto; } 234 | 235 | /** 236 | * 1. Add the correct box sizing in IE 10. 237 | * 2. Remove the padding in IE 10. 238 | */ 239 | [type="checkbox"], 240 | [type="radio"] { 241 | box-sizing: border-box; 242 | /* 1 */ 243 | padding: 0; 244 | /* 2 */ } 245 | 246 | /** 247 | * Correct the cursor style of increment and decrement buttons in Chrome. 248 | */ 249 | [type="number"]::-webkit-inner-spin-button, 250 | [type="number"]::-webkit-outer-spin-button { 251 | height: auto; } 252 | 253 | /** 254 | * 1. Correct the odd appearance in Chrome and Safari. 255 | * 2. Correct the outline style in Safari. 256 | */ 257 | [type="search"] { 258 | -webkit-appearance: textfield; 259 | /* 1 */ 260 | outline-offset: -2px; 261 | /* 2 */ } 262 | 263 | /** 264 | * Remove the inner padding in Chrome and Safari on macOS. 265 | */ 266 | [type="search"]::-webkit-search-decoration { 267 | -webkit-appearance: none; } 268 | 269 | /** 270 | * 1. Correct the inability to style clickable types in iOS and Safari. 271 | * 2. Change font properties to `inherit` in Safari. 272 | */ 273 | ::-webkit-file-upload-button { 274 | -webkit-appearance: button; 275 | /* 1 */ 276 | font: inherit; 277 | /* 2 */ } 278 | 279 | /* Interactive 280 | ========================================================================== */ 281 | /* 282 | * Add the correct display in Edge, IE 10+, and Firefox. 283 | */ 284 | details { 285 | display: block; } 286 | 287 | /* 288 | * Add the correct display in all browsers. 289 | */ 290 | summary { 291 | display: list-item; } 292 | 293 | /* Misc 294 | ========================================================================== */ 295 | /** 296 | * Add the correct display in IE 10+. 297 | */ 298 | template { 299 | display: none; } 300 | 301 | /** 302 | * Add the correct display in IE 10. 303 | */ 304 | [hidden] { 305 | display: none; } 306 | 307 | html { 308 | box-sizing: border-box; } 309 | 310 | template, 311 | [hidden] { 312 | display: none; } 313 | 314 | *, 315 | :before, 316 | :after { 317 | box-sizing: inherit; } 318 | 319 | address { 320 | font-style: inherit; } 321 | 322 | dfn, 323 | cite, 324 | em, 325 | i { 326 | font-style: italic; } 327 | 328 | b, 329 | strong { 330 | font-weight: 700; } 331 | 332 | a { 333 | text-decoration: none; } 334 | a svg { 335 | pointer-events: none; } 336 | 337 | ul, 338 | ol { 339 | margin: 0; 340 | padding: 0; 341 | list-style: none; } 342 | 343 | p, 344 | figure { 345 | margin: 0; 346 | padding: 0; } 347 | 348 | h1, h2, h3, h4, h5, h6 { 349 | margin: 0; } 350 | 351 | /** 352 | * 1. Single taps should be dispatched immediately on clickable elements 353 | */ 354 | a, area, button, input, label, select, textarea, [tabindex] { 355 | /* [1] */ 356 | touch-action: manipulation; } 357 | 358 | [hreflang] > abbr[title] { 359 | text-decoration: none; } 360 | 361 | table { 362 | border-spacing: 0; 363 | border-collapse: collapse; } 364 | 365 | hr { 366 | display: block; 367 | margin: 1em 0; 368 | padding: 0; 369 | height: 1px; 370 | border: 0; 371 | border-top: 1px solid #CCCCCC; } 372 | 373 | audio, 374 | canvas, 375 | iframe, 376 | img, 377 | svg, 378 | video { 379 | vertical-align: middle; 380 | /* [1] */ } 381 | 382 | audio:not([controls]) { 383 | display: none; 384 | height: 0; } 385 | 386 | img, 387 | svg { 388 | max-width: 100%; 389 | /* [2] */ 390 | height: auto; } 391 | img[width], img[height], 392 | svg[width], 393 | svg[height] { 394 | /* [4] */ 395 | max-width: none; } 396 | 397 | img { 398 | font-style: italic; 399 | /* [4] */ } 400 | 401 | svg { 402 | fill: currentColor; 403 | /* [5] */ } 404 | 405 | button, 406 | .c-button { 407 | display: inline-block; 408 | /* [1] */ 409 | overflow: visible; 410 | /* [2] */ 411 | margin: 0; 412 | /* [3] */ 413 | padding: 0; 414 | outline: 0; 415 | border: 0; 416 | background: none transparent; 417 | color: inherit; 418 | vertical-align: middle; 419 | /* [4] */ 420 | text-align: center; 421 | /* [3] */ 422 | text-decoration: none; 423 | text-transform: none; 424 | font: inherit; 425 | /* [5] */ 426 | line-height: normal; 427 | cursor: pointer; 428 | /* [6] */ 429 | -webkit-user-select: none; 430 | -moz-user-select: none; 431 | -ms-user-select: none; 432 | user-select: none; } 433 | button:focus, button:hover, 434 | .c-button:focus, 435 | .c-button:hover { 436 | text-decoration: none; } 437 | 438 | html { 439 | overflow-y: scroll; 440 | /* [2] */ 441 | min-height: 100%; 442 | /* [3] */ 443 | color: #222222; 444 | font-family: sans-serif; 445 | line-height: 1.5; 446 | /* [1] */ } 447 | @media (max-width: 699px) { 448 | html { 449 | font-size: 12px; } } 450 | @media (min-width: 700px) and (max-width: 999px) { 451 | html { 452 | font-size: 13px; } } 453 | @media (min-width: 1000px) and (max-width: 1199px) { 454 | html { 455 | font-size: 14px; } } 456 | @media (min-width: 1200px) and (max-width: 1599px) { 457 | html { 458 | font-size: 16px; 459 | /* [1] */ } } 460 | @media (min-width: 1600px) and (max-width: 1999px) { 461 | html { 462 | font-size: 18px; } } 463 | @media (min-width: 2000px) and (max-width: 2399px) { 464 | html { 465 | font-size: 21px; } } 466 | @media (min-width: 2400px) { 467 | html { 468 | font-size: 24px; } } 469 | html.is-loading { 470 | cursor: wait; } 471 | html.has-scroll-smooth { 472 | overflow: hidden; } 473 | html.has-scroll-dragging { 474 | -webkit-user-select: none; 475 | -moz-user-select: none; 476 | -ms-user-select: none; 477 | user-select: none; } 478 | 479 | .has-scroll-smooth body { 480 | overflow: hidden; } 481 | 482 | ::-moz-selection { 483 | background-color: #FFFFFF; 484 | color: #3297FD; 485 | text-shadow: none; } 486 | 487 | ::selection { 488 | background-color: #FFFFFF; 489 | color: #3297FD; 490 | text-shadow: none; } 491 | 492 | a { 493 | color: #1A0DAB; } 494 | a:focus, a:hover { 495 | color: #13097c; } 496 | 497 | .o-scroll { 498 | min-height: 100vh; } 499 | 500 | .o-container { 501 | margin-right: auto; 502 | margin-left: auto; 503 | padding-right: 3.75rem; 504 | padding-left: 3.75rem; 505 | max-width: 132.5rem; } 506 | 507 | /** 508 | * Create ratio-bound content blocks, to keep media (e.g. images, videos) in 509 | * their correct aspect ratios. 510 | * 511 | * http://alistapart.com/article/creating-intrinsic-ratios-for-video 512 | * 513 | * 1. Default cropping is a 1:1 ratio (i.e. a perfect square). 514 | */ 515 | .o-ratio { 516 | position: relative; 517 | display: block; 518 | overflow: hidden; } 519 | .o-ratio:before { 520 | display: block; 521 | padding-bottom: 100%; 522 | /* [1] */ 523 | width: 100%; 524 | content: ""; } 525 | 526 | .o-ratio_content, 527 | .o-ratio > img, 528 | .o-ratio > iframe, 529 | .o-ratio > embed, 530 | .o-ratio > object { 531 | position: absolute; 532 | top: 0; 533 | bottom: 0; 534 | left: 0; 535 | width: 100%; } 536 | 537 | .o-layout { 538 | margin: 0; 539 | padding: 0; 540 | list-style: none; 541 | font-size: 0; 542 | margin-left: 0; } 543 | .o-layout.-gutter { 544 | margin-left: -3.75rem; } 545 | .o-layout.-gutter-small { 546 | margin-left: -1.875rem; } 547 | .o-layout.-center { 548 | text-align: center; } 549 | .o-layout.-right { 550 | text-align: right; } 551 | .o-layout.-reverse { 552 | direction: rtl; } 553 | .o-layout.-reverse.-flex { 554 | -webkit-box-orient: horizontal; 555 | -webkit-box-direction: reverse; 556 | flex-direction: row-reverse; } 557 | .o-layout.-flex { 558 | display: -webkit-box; 559 | display: flex; } 560 | .o-layout.-flex.-top { 561 | -webkit-box-align: start; 562 | align-items: flex-start; } 563 | .o-layout.-flex.-middle { 564 | -webkit-box-align: center; 565 | align-items: center; } 566 | .o-layout.-flex.-bottom { 567 | -webkit-box-align: end; 568 | align-items: flex-end; } 569 | .o-layout.-stretch { 570 | -webkit-box-align: stretch; 571 | align-items: stretch; } 572 | 573 | .o-layout_item { 574 | display: inline-block; 575 | width: 100%; 576 | vertical-align: top; 577 | font-size: 1rem; 578 | padding-left: 0; } 579 | .o-layout.-gutter > .o-layout_item { 580 | padding-left: 3.75rem; } 581 | .o-layout.-gutter-small > .o-layout_item { 582 | padding-left: 1.875rem; } 583 | .o-layout.-middle > .o-layout_item { 584 | vertical-align: middle; } 585 | .o-layout.-bottom > .o-layout_item { 586 | vertical-align: bottom; } 587 | .o-layout.-center > .o-layout_item, 588 | .o-layout.-right > .o-layout_item, 589 | .o-layout.-reverse > .o-layout_item { 590 | text-align: left; } 591 | .o-layout.-reverse > .o-layout_item { 592 | direction: ltr; } 593 | 594 | .c-scrollbar { 595 | position: absolute; 596 | right: 0; 597 | top: 0; 598 | width: 11px; 599 | height: 100vh; 600 | -webkit-transform-origin: center right; 601 | transform-origin: center right; 602 | -webkit-transition: opacity 0.3s, -webkit-transform 0.3s; 603 | transition: opacity 0.3s, -webkit-transform 0.3s; 604 | transition: transform 0.3s, opacity 0.3s; 605 | transition: transform 0.3s, opacity 0.3s, -webkit-transform 0.3s; 606 | opacity: 0; } 607 | .c-scrollbar:hover { 608 | -webkit-transform: scaleX(1.45); 609 | transform: scaleX(1.45); } 610 | .c-scrollbar:hover, .has-scroll-scrolling .c-scrollbar, .has-scroll-dragging .c-scrollbar { 611 | opacity: 1; } 612 | 613 | .c-scrollbar_thumb { 614 | position: absolute; 615 | top: 0; 616 | right: 0; 617 | background-color: black; 618 | opacity: 0.5; 619 | width: 7px; 620 | border-radius: 10px; 621 | margin: 2px; 622 | cursor: -webkit-grab; 623 | cursor: grab; } 624 | .has-scroll-dragging .c-scrollbar_thumb { 625 | cursor: -webkit-grabbing; 626 | cursor: grabbing; } 627 | 628 | .c-heading { 629 | line-height: 1.5; 630 | margin-bottom: 1.875rem; } 631 | .c-heading.-h1 { 632 | font-size: 2.25rem; } 633 | .c-heading.-h2 { 634 | font-size: 1.75rem; } 635 | .c-heading.-h3 { 636 | font-size: 1.5rem; } 637 | .c-heading.-h4 { 638 | font-size: 1.25rem; } 639 | .c-heading.-h5 { 640 | font-size: 1.125rem; } 641 | .c-heading.-h6 { 642 | font-size: 1rem; } 643 | 644 | .c-button { 645 | padding: 0.9375rem 1.25rem; 646 | background-color: lightgray; } 647 | .c-button:focus, .c-button:hover { 648 | background-color: darkgray; } 649 | 650 | .c-gl-image { 651 | display: inline-block; 652 | width: 100%; 653 | vertical-align: top; 654 | font-size: 1rem; 655 | padding-left: 0; 656 | position: relative; 657 | margin: 0; 658 | display: inline-block; } 659 | .c-gl-image::before { 660 | content: ""; 661 | display: block; 662 | padding-bottom: 78%; } 663 | @media (min-width: 1000px) { 664 | .c-gl-image { 665 | width: 40%; } } 666 | .c-gl-image.is-loading { 667 | background-color: rgba(0, 0, 0, 0.2); } 668 | 669 | .c-gl-image_wrap { 670 | position: absolute; 671 | top: 0; 672 | bottom: 0; 673 | right: 0; 674 | left: 0; } 675 | .c-gl-image_wrap canvas { 676 | position: absolute; 677 | top: 0; 678 | bottom: 0; 679 | right: 0; 680 | left: 0; } 681 | 682 | /* stylelint-disable */ 683 | .u-2\:1::before { 684 | padding-bottom: 50%; } 685 | 686 | .u-4\:3::before { 687 | padding-bottom: 75%; } 688 | 689 | .u-16\:9::before { 690 | padding-bottom: 56.25%; } 691 | 692 | /* stylelint-enable */ 693 | .u-1\/1 { 694 | width: 100% !important; } 695 | 696 | .u-1\/2 { 697 | width: 50% !important; } 698 | 699 | .u-2\/2 { 700 | width: 100% !important; } 701 | 702 | .u-1\/3 { 703 | width: 33.33333% !important; } 704 | 705 | .u-2\/3 { 706 | width: 66.66667% !important; } 707 | 708 | .u-3\/3 { 709 | width: 100% !important; } 710 | 711 | .u-1\/4 { 712 | width: 25% !important; } 713 | 714 | .u-2\/4 { 715 | width: 50% !important; } 716 | 717 | .u-3\/4 { 718 | width: 75% !important; } 719 | 720 | .u-4\/4 { 721 | width: 100% !important; } 722 | 723 | .u-1\/5 { 724 | width: 20% !important; } 725 | 726 | .u-2\/5 { 727 | width: 40% !important; } 728 | 729 | .u-3\/5 { 730 | width: 60% !important; } 731 | 732 | .u-4\/5 { 733 | width: 80% !important; } 734 | 735 | .u-5\/5 { 736 | width: 100% !important; } 737 | 738 | @media (min-width: 700px) { 739 | .u-1\/2\@from-small { 740 | width: 50%; } } 741 | -------------------------------------------------------------------------------- /www/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #ffffff 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /www/example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Webgl images - GUI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/locomotivemtl/webgl-images/50aa6c50d7c1c0ee4cc99107046e16044fe8f9ed/www/favicon.ico -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GL Images 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 22 | 23 | 24 | 25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /www/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Boilerplate", 3 | "short_name": "Boilerplate", 4 | "icons": [ 5 | { 6 | "src": "assets/images/favicons/android-chrome-144x144.png", 7 | "sizes": "144x144", 8 | "type": "image/png" 9 | } 10 | ], 11 | "theme_color": "#ffffff", 12 | "background_color": "#ffffff", 13 | "display": "standalone" 14 | } 15 | --------------------------------------------------------------------------------