├── src ├── context.js ├── font-face │ ├── monoton │ │ └── Monoton-Regular.ttf │ └── signika │ │ └── Signika-Regular.otf ├── index.js ├── shaders │ ├── hoc.js │ ├── CurveOne.js │ ├── Parabola.js │ ├── Impulse.js │ ├── CurveTwo.js │ ├── Gain.js │ ├── SineCurve.js │ ├── CurveFive.js │ ├── CurveFour.js │ ├── CurveThree.js │ ├── ExpoStep.js │ ├── PowerCurve.js │ └── CubicPulse.js ├── App.js └── App.css ├── public ├── manifest.json └── index.html ├── .gitignore ├── package.json └── README.md /src/context.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const { Consumer, Provider } = React.createContext() -------------------------------------------------------------------------------- /src/font-face/monoton/Monoton-Regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitin42/shaping-functions/HEAD/src/font-face/monoton/Monoton-Regular.ttf -------------------------------------------------------------------------------- /src/font-face/signika/Signika-Regular.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nitin42/shaping-functions/HEAD/src/font-face/signika/Signika-Regular.otf -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import App from './App'; 4 | 5 | ReactDOM.render(, document.getElementById('root')); 6 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | } 10 | ], 11 | "start_url": ".", 12 | "display": "standalone", 13 | "theme_color": "#000000", 14 | "background_color": "#ffffff" 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /build 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Shaping Functions 9 | 10 | 11 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/shaders/hoc.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Consumer } from '../context' 3 | 4 | export const ShaderCanvas = (Shader, heading) => class extends React.Component { 5 | render() { 6 | return ( 7 | 8 | {timesync => ( 9 |
10 | 11 |
12 |

{heading}

13 |
14 |
15 | )} 16 |
17 | ) 18 | } 19 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shaping-functions", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "glslCanvas": "^0.1.7", 7 | "react": "^16.5.2", 8 | "react-dom": "^16.5.2", 9 | "react-scripts": "2.0.4", 10 | "react-shader-canvas": "^1.0.0", 11 | "react-tooltip": "^3.8.4" 12 | }, 13 | "scripts": { 14 | "start": "SKIP_PREFLIGHT_CHECK=true react-scripts start", 15 | "build": "SKIP_PREFLIGHT_CHECK=true react-scripts build", 16 | "eject": "react-scripts eject" 17 | }, 18 | "eslintConfig": { 19 | "extends": "react-app" 20 | }, 21 | "browserslist": [ 22 | ">0.2%", 23 | "not dead", 24 | "not ie <= 11", 25 | "not op_mini all" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /src/shaders/CurveOne.js: -------------------------------------------------------------------------------- 1 | import {createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({ timeSync = false }) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float plotCurve( float x, float k ) { 14 | return 1.0 - pow(abs(x), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = plotCurve(point.x, ${timeSync ? 'u_time * cp.y' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), sin(cp.y), cos(cp.x)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Kynd Curve One'); -------------------------------------------------------------------------------- /src/shaders/Parabola.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc'; 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float parabola( float x, float k ) { 14 | return pow(4.0 * x * (1.0-x), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = parabola(point.x, ${timeSync ? 'cp.y * u_time' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), sin(u_time), cos(u_time)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Parabola') -------------------------------------------------------------------------------- /src/shaders/Impulse.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float impulse( float k, float x ) { 14 | float h = k*x; 15 | return h*exp(1.0-h); 16 | } 17 | 18 | void main() { 19 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 20 | float px = 1.0 / u_resolution.y; 21 | 22 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 23 | float l = impulse(${timeSync ? 'cp.x * u_time' : 'cp.x'}, point.x); 24 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(u_time), sin(cp.y)); 25 | 26 | gl_FragColor = vec4(color, 1.0); 27 | } 28 | ` 29 | 30 | export default ShaderCanvas(createShaderCanvas(shader), 'Impulse Curve') -------------------------------------------------------------------------------- /src/shaders/CurveTwo.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({ timeSync = false }) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float plotCurve( float x, float k ) { 14 | return pow(cos(3.142 * x / 2.0), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = plotCurve(point.x, ${timeSync ? 'u_time * cp.y' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(cp.y), fract(cp.x)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Kynd Curve Two'); -------------------------------------------------------------------------------- /src/shaders/Gain.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc'; 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float gain(float x, float k) { 14 | float a = 0.5*pow(2.0*((x<0.5)?x:1.0-x), k); 15 | return (x<0.5)?a:1.0-a; 16 | } 17 | 18 | void main() { 19 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 20 | float px = 1.0 / u_resolution.y; 21 | 22 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 23 | float l = gain(point.x, ${timeSync ? 'cp.x * u_time' : 'cp.x'}); 24 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(u_time), sin(cp.y)); 25 | 26 | gl_FragColor = vec4(color, 1.0); 27 | } 28 | ` 29 | 30 | export default ShaderCanvas(createShaderCanvas(shader), 'Gain Curve') -------------------------------------------------------------------------------- /src/shaders/SineCurve.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float sinc( float x, float k ){ 14 | float a = 3.1459265359 * k * x - 1.0; 15 | 16 | return sin(a)/a; 17 | } 18 | 19 | void main() { 20 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 21 | float px = 1.0 / u_resolution.y; 22 | 23 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 24 | float l = sinc(point.x, ${timeSync ? 'cp.x * u_time' : 'cp.x'}); 25 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(u_time), sin(cp.y)); 26 | 27 | gl_FragColor = vec4(color, 1.0); 28 | } 29 | ` 30 | 31 | export default ShaderCanvas(createShaderCanvas(shader), 'Sine Curve') -------------------------------------------------------------------------------- /src/shaders/CurveFive.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({ timeSync = false }) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float plotCurve( float x, float k ) { 14 | return 1.0 - pow(max(0.0, abs(x) * 2.0 - 1.0), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = plotCurve(point.x, ${timeSync ? 'u_time * cp.y' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), sin(cp.y * 0.2), tan(cp.x)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Kynd Curve Five'); -------------------------------------------------------------------------------- /src/shaders/CurveFour.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({ timeSync = false }) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float plotCurve( float x, float k ) { 14 | return pow(min(cos(3.142 * x / 2.0), 1.0 - abs(x)), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = plotCurve(point.x, ${timeSync ? 'u_time * cp.y' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(cp.y), cos(cp.x)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Kynd Curve Four'); -------------------------------------------------------------------------------- /src/shaders/CurveThree.js: -------------------------------------------------------------------------------- 1 | import {createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({ timeSync = false }) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float plotCurve( float x, float k ) { 14 | return 1.0 - pow(abs(sin(3.142 * x / 2.0)), k); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = plotCurve(point.x, ${timeSync ? 'u_time * cp.y' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), sin(cp.y * 0.5), cos(cp.x * 0.8)); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Kynd Curve Three'); -------------------------------------------------------------------------------- /src/shaders/ExpoStep.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc'; 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float expStep( float x, float k, float n ){ 14 | return exp( -k*pow(x,n) ); 15 | } 16 | 17 | void main() { 18 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 19 | float px = 1.0 / u_resolution.y; 20 | 21 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 22 | float l = expStep(point.x, ${timeSync ? 'cp.x * u_time' : 'cp.x'}, ${timeSync ? 'cp.y * u_time' : 'cp.y'}); 23 | vec3 color = vec3(smoothstep(l, l+px, point.y), sin(u_time), cos(cp.y) * 0.5); 24 | 25 | gl_FragColor = vec4(color, 1.0); 26 | } 27 | ` 28 | 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Exponential Step') -------------------------------------------------------------------------------- /src/shaders/PowerCurve.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc'; 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float pcurve( float x, float a, float b ){ 14 | float k = pow(a+b,a+b) / (pow(a,a)*pow(b,b)); 15 | return k * pow( x, a ) * pow( 1.0-x, b ); 16 | } 17 | 18 | void main() { 19 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 20 | float px = 1.0 / u_resolution.y; 21 | 22 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 23 | float l = pcurve(point.x, ${timeSync ? 'cp.x * u_time' : 'cp.x'}, ${timeSync ? 'cp.y * u_time': 'cp.y'}); 24 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(u_time), sin(cp.y)); 25 | 26 | gl_FragColor = vec4(color, 1.0); 27 | } 28 | ` 29 | export default ShaderCanvas(createShaderCanvas(shader), 'Power Curve') -------------------------------------------------------------------------------- /src/shaders/CubicPulse.js: -------------------------------------------------------------------------------- 1 | import { createShaderCanvas } from 'react-shader-canvas' 2 | import { ShaderCanvas } from './hoc' 3 | 4 | const shader = ({timeSync = false}) => ` 5 | #ifdef GL_ES 6 | precision mediump float; 7 | #endif 8 | 9 | uniform float u_time; 10 | uniform vec2 u_mouse; 11 | uniform vec2 u_resolution; 12 | 13 | float cubicPulse( float c, float w, float x ){ 14 | x = abs(x - c); 15 | if( x>w ) return 0.0; 16 | x /= w; 17 | return 1.0 - x*x*(3.0-2.0*x); 18 | } 19 | 20 | void main() { 21 | vec2 point = gl_FragCoord.xy / u_resolution.xy; 22 | float px = 1.0 / u_resolution.y; 23 | 24 | vec2 cp = vec2(cos(u_time),sin(u_time)) * 0.618 + 0.620; 25 | float l = cubicPulse(${timeSync ? 'cp.x * u_time / 10.0' : 'cp.x'}, ${timeSync ? 'cp.y * u_time / 10.0' : 'cp.y'}, point.x); 26 | vec3 color = vec3(smoothstep(l, l+px, point.y), tan(u_time), sin(cp.y)); 27 | 28 | gl_FragColor = vec4(color, 1.0); 29 | } 30 | ` 31 | 32 | export default ShaderCanvas(createShaderCanvas(shader), 'Cubic Pulse') -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shaping-functions 2 | 3 | > Visualisation of shaping functions 4 | 5 | ## Introduction 6 | 7 | This is visualisation of shaping functions used in algorithmic drawing. I am learning shaders and mathematics required for computer graphics. As a part of my learning process and to practice writing my own functions, I decided to port [these](http://www.iquilezles.org/www/articles/functions/functions.html) shaping functions written by [Inigo Quilez](http://www.iquilezles.org/index.html) and also [Kynd's curves](http://www.flickr.com/photos/kynd/9546075099). Inigo Quilez's [blog](http://www.iquilezles.org/www/index.htm) explains the use cases for shaping functions such as - animations, or making envelopes for music. 8 | 9 | ## Future 10 | 11 | I'll keep updating the collection (of shaping functions) as I write my own functions for algorithmic drawing. 12 | 13 | ## Resources 14 | 15 | I am learning about shaders and glsl from [thebookofshaders](https://thebookofshaders.com/). 16 | 17 | Many many thanks to [Patricio Gonzalez Vivo](http://patriciogonzalezvivo.com) and [Jen Lowe](http://jenlowe.net) for **The Book of Shaders** which is such an amazing resource to learn glsl and algorithmic drawing, and made this project possible. 18 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import ReactTooltip from 'react-tooltip' 3 | 4 | import Parabola from './shaders/Parabola' 5 | import Impulse from './shaders/Impulse' 6 | import ExpoStep from './shaders/ExpoStep' 7 | import Gain from './shaders/Gain' 8 | import PowerCurve from './shaders/PowerCurve' 9 | import CubicPulse from './shaders/CubicPulse' 10 | import SineCurve from './shaders/SineCurve' 11 | import CurveOne from './shaders/CurveOne' 12 | import CurveTwo from './shaders/CurveTwo' 13 | import CurveThree from './shaders/CurveThree' 14 | import CurveFour from './shaders/CurveFour' 15 | import CurveFive from './shaders/CurveFive' 16 | 17 | import { Provider } from './context' 18 | 19 | import './App.css' 20 | 21 | class App extends Component { 22 | state = { 23 | timesync: false 24 | } 25 | 26 | handleTimeSync = e => this.setState(state => ({ timesync: !state.timesync })) 27 | 28 | render() { 29 | return ( 30 |
31 |
32 |

Shaping Functions

33 |
34 |
35 |

Preamble{' '}

36 |
37 |
38 | Playback Time - {' '} 39 | 43 | 44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 | 73 |
74 | ); 75 | } 76 | } 77 | 78 | export default App; 79 | -------------------------------------------------------------------------------- /src/App.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: Monoton; 3 | src: url(./font-face/monoton/Monoton-Regular.ttf) 4 | } 5 | 6 | @font-face { 7 | font-family: Signika; 8 | src: url(./font-face/signika/Signika-Regular.otf); 9 | } 10 | 11 | html { 12 | font-family: Signika, sans-serif; 13 | color: #2f2f2f; 14 | } 15 | 16 | h1 { 17 | font-weight: 500; 18 | font-size: 1.8em; 19 | } 20 | 21 | canvas { 22 | box-shadow: 3px 6px 9px 0 #c7c5c7; 23 | -webkit-box-shadow: 3px 6px 9px 0 #c7c5c7; 24 | -moz-box-shadow: 3px 6px 9px 0 #c7c5c7; 25 | border-radius: 5px; 26 | } 27 | 28 | .canvas-grid { 29 | display: grid; 30 | grid-template-columns: repeat(3, 1fr); 31 | justify-items: center; 32 | grid-gap: 10px; 33 | } 34 | 35 | .heading { 36 | font-size: 4em; 37 | font-family: Monoton; 38 | } 39 | 40 | .small-heading { 41 | font-size: 1.2em; 42 | } 43 | 44 | .content-center { 45 | display: flex; 46 | justify-content: center; 47 | } 48 | 49 | .link { 50 | font-size: 1.5em; 51 | } 52 | 53 | a { 54 | text-decoration: none; 55 | color: #2f2f2f; 56 | border-bottom: 2px solid #2f2f2f; 57 | } 58 | 59 | .footer { 60 | margin-top: 5px; 61 | } 62 | 63 | .switch { 64 | position: relative; 65 | display: inline-block; 66 | width: 60px; 67 | height: 34px; 68 | } 69 | 70 | .switch input { 71 | display: none; 72 | } 73 | 74 | .toggle { 75 | position: absolute; 76 | cursor: pointer; 77 | top: 0; 78 | left: 0; 79 | right: 0; 80 | bottom: 0; 81 | background-color: #dedede; 82 | -webkit-transition: 0.4s; 83 | transition: 0.4s; 84 | border-radius: 50px; 85 | } 86 | 87 | .toggle:before { 88 | position: absolute; 89 | content: ''; 90 | height: 26px; 91 | width: 26px; 92 | left: 4px; 93 | bottom: 4px; 94 | background-color: white; 95 | -webkit-transition: 0.4s; 96 | transition: 0.4s; 97 | border-radius: 50px; 98 | } 99 | 100 | input:checked + .toggle { 101 | background-color: #424242; 102 | } 103 | 104 | input:focus + .toggle { 105 | box-shadow: 0 0 1px #4f4f4f; 106 | } 107 | 108 | input:checked + .toggle:before { 109 | -webkit-transform: translateX(26px); 110 | -ms-transform: translateX(26px); 111 | transform: translateX(26px); 112 | } 113 | 114 | .toggle:after { 115 | content: 'OFF'; 116 | color: white; 117 | display: block; 118 | position: absolute; 119 | transform: translate(-50%, -50%); 120 | top: 50%; 121 | left: 72%; 122 | font-size: 12px; 123 | } 124 | 125 | input:checked + .toggle:after { 126 | content: 'ON'; 127 | display: block; 128 | position: absolute; 129 | transform: translate(-50%, -50%); 130 | left: 25%; 131 | font-size: 12px; 132 | } 133 | 134 | input:checked + .toggle .on { 135 | display: block; 136 | } 137 | 138 | input:checked + .toggle .off { 139 | display: none; 140 | } 141 | 142 | @media only screen and (max-width: 480px) { 143 | canvas { 144 | width: 250px; 145 | height: 250px; 146 | } 147 | 148 | .canvas-grid { 149 | display: grid; 150 | grid-template-columns: 1fr; 151 | justify-items: center; 152 | grid-gap: 5px; 153 | } 154 | 155 | .switch { 156 | width: 50px; 157 | height: 25px; 158 | } 159 | 160 | .toggle:before { 161 | height: 20px; 162 | width: 20px; 163 | left: 3px; 164 | bottom: 3px; 165 | border-radius: 25px; 166 | } 167 | 168 | /* .toggle:after { 169 | top: 50%; 170 | left: 42%; 171 | font-size: 10px; 172 | } */ 173 | 174 | .heading { 175 | font-size: 1.5em; 176 | word-spacing: 5px; 177 | } 178 | 179 | h1 { 180 | font-size: 1.5em; 181 | } 182 | 183 | .link { 184 | font-size: 14px; 185 | } 186 | 187 | .small-heading { 188 | font-size: 12px; 189 | } 190 | } --------------------------------------------------------------------------------