├── .gitignore ├── 001-repetition-hover-effect-round ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 002-repetition-hover-effect-square ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 003-repetition-hover-effect-rotated ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 004-repetition-hover-effect-filter ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 005-image-motion-trail-opaque ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 006-image-motion-trail-semitransparent ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 007-image-motion-trail-rotation ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 008-image-motion-trail-circle ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 009-image-motion-trail-perspective ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 010-image-motion-trail-perspective ├── css │ └── base.css ├── img │ ├── 1.jpg │ └── bg.png ├── index.html └── js │ └── index.js ├── 011-custom-cursor-filled-circle ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 012-custom-cursor-two-circles ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 013-custom-cursor-filter ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 014-custom-cursor-filter-2 ├── css │ └── base.css ├── favicon.ico ├── index.html └── js │ └── index.js ├── 015-custom-cursor-filter-3 ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 016-custom-cursor-filter-4 ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 017-custom-cursor-filter-5 ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 018-custom-cursor-filter-6 ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 019-image-motion-svg-filter ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 020-image-motion-svg-filter-2 ├── css │ └── base.css ├── img │ └── 1.jpg ├── index.html └── js │ └── index.js ├── 021-svg-path-page-transition-vertical ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 022-svg-path-page-transition-horizontal ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 023-theme-picker ├── css │ └── base.css ├── index.html └── js │ └── index.js ├── 024-infinite-loop-scrolling ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── index.html └── js │ └── index.js ├── 025-infinite-loop-scrolling-horizontal ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ └── 4.jpg ├── index.html └── js │ └── index.js ├── 026-infinite-loop-scrolling-animation ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── index.html └── js │ └── index.js ├── 027-infinite-loop-scrolling-animation-2 ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── index.html └── js │ └── index.js ├── 028-infinite-loop-scrolling-animation-3 ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── index.html └── js │ └── index.js ├── 029-infinite-loop-scrolling-animation-4 ├── css │ └── base.css ├── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── index.html └── js │ └── index.js ├── LICENSE ├── README.md └── favicon.ico /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | -------------------------------------------------------------------------------- /001-repetition-hover-effect-round/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #858fe7; 14 | --color-bg: #0e0e0e; 15 | --color-link: #fff; 16 | --color-link-hover: #858fe7; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | color: var(--color-link); 28 | outline: none; 29 | } 30 | 31 | a:hover { 32 | color: var(--color-link-hover); 33 | outline: none; 34 | } 35 | 36 | a:focus { 37 | outline: none; 38 | background: lightgrey; 39 | } 40 | 41 | a:focus:not(:focus-visible) { 42 | background: transparent; 43 | } 44 | 45 | a:focus-visible { 46 | outline: 2px solid red; 47 | background: transparent; 48 | } 49 | 50 | .frame { 51 | padding: 1.5rem 2rem 10vh; 52 | text-align: center; 53 | position: relative; 54 | } 55 | 56 | .frame__title { 57 | margin: 0; 58 | font-size: 1rem; 59 | font-weight: 500; 60 | } 61 | 62 | .frame__links { 63 | margin: 0.5rem 0 2rem; 64 | } 65 | 66 | .frame__links a:not(:last-child) { 67 | margin-right: 1rem; 68 | } 69 | 70 | .content { 71 | flex: 1; 72 | display: grid; 73 | place-items: center; 74 | } 75 | 76 | .image { 77 | margin: 0 auto; 78 | display: grid; 79 | cursor: pointer; 80 | position: relative; 81 | overflow: hidden; 82 | width: min(70vmin, 450px); 83 | height: min(70vmin, 450px); 84 | border-radius: 50%; 85 | background-size: cover; 86 | background-position: 50% 50%; 87 | } 88 | 89 | .image__element { 90 | transform-origin: inherit; 91 | position: relative; 92 | grid-area: 1 / 1 / 2 / 2; 93 | width: 100%; 94 | height: 100%; 95 | will-change: transform; 96 | border-radius: inherit; 97 | background-size: inherit; 98 | background-position: inherit; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | main { 103 | height: 100vh; 104 | display: flex; 105 | flex-direction: column; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /001-repetition-hover-effect-round/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/001-repetition-hover-effect-round/img/1.jpg -------------------------------------------------------------------------------- /001-repetition-hover-effect-round/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 001: Repetition Hover Effect (Round) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 001: Repetition Hover Effect (Round)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /001-repetition-hover-effect-round/js/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class representing an image that has the repetitive hover effect 3 | */ 4 | class ImageHover { 5 | // DOM elements 6 | DOM = { 7 | // main element (.image) 8 | el: null, 9 | // .image__element 10 | innerElems: null, 11 | } 12 | // Main element background image path 13 | bgImage; 14 | // Options that can be passed in data attributes. These are the defaults: 15 | // Duration 16 | duration = 0.5; 17 | // Easing function 18 | ease = 'power2.inOut'; 19 | // Stagger value between inner image elements 20 | stagger = 0; 21 | // Scale interval between inner image elements 22 | scaleInterval = 0.1; 23 | // Rotation interval between inner image elements 24 | rotationInterval = 0; 25 | // Total number of inner image elements 26 | innerTotal = 4; 27 | // Main element transform origin 28 | transformOrigin = '50% 50%'; 29 | // GSAP hover timeline 30 | hoverTimeline; 31 | 32 | /** 33 | * Constructor. 34 | * @param {Element} DOM_el - the .image element 35 | */ 36 | constructor(DOM_el) { 37 | // Main element 38 | this.DOM = {el: DOM_el}; 39 | 40 | // Options that can be passed in data attributes 41 | this.duration = this.DOM.el.dataset.repetitionDuration || this.duration; 42 | this.ease = this.DOM.el.dataset.repetitionEase || this.ease; 43 | this.stagger = this.DOM.el.dataset.repetitionStagger || this.stagger; 44 | this.scaleInterval = this.DOM.el.dataset.repetitionScaleInterval || this.scaleInterval; 45 | this.rotationInterval = this.DOM.el.dataset.repetitionRotationInterval || this.rotationInterval; 46 | this.innerTotal = this.DOM.el.dataset.repetitionCount || this.innerTotal; 47 | this.transformOrigin = this.DOM.el.dataset.repetitionOrigin || this.transformOrigin; 48 | 49 | // Get the main element's background image url 50 | this.bgImage = /(?:\(['"]?)(.*?)(?:['"]?\))/.exec(this.DOM.el.style.backgroundImage)[1] 51 | 52 | // Remove the background image from the main element 53 | // The dynamically created inner elements will have that background image 54 | gsap.set(this.DOM.el, {backgroundImage: 'none'}); 55 | 56 | // Add the .image__element inner elements (data-repetition-elems times) 57 | // Condition: minimum of 2 inner elments 58 | this.innerTotal = this.innerTotal <= 1 ? 2 : this.innerTotal; 59 | 60 | let innerHTML = ''; 61 | for (let i = 0, len = this.innerTotal; i <= len - 1; ++i) { 62 | innerHTML += `
`; 63 | } 64 | 65 | // Append to the main element 66 | this.DOM.el.innerHTML = innerHTML; 67 | 68 | // Get inner .image__element 69 | this.DOM.innerElems = this.DOM.el.querySelectorAll('.image__element'); 70 | 71 | // Set transform origin 72 | gsap.set(this.DOM.el, {transformOrigin: this.transformOrigin}); 73 | 74 | // Hover timeline 75 | this.createHoverTimeline(); 76 | 77 | // Init the hover events 78 | this.initEvents(); 79 | } 80 | 81 | /** 82 | * Create the gsap timeline for the hover in/out animation 83 | */ 84 | createHoverTimeline() { 85 | // Get the scale value based on the scale interval passed in data-repetition-scale-interval 86 | // e.g. if the scale interval is 0.1 then the inner elements will have the following scale values: 87 | // first element: 1; second: 0.9, third: 0.8 ... 88 | // If the value goes below 0 (too many inner elements) then the scale value defaults to 0 89 | const getScaleValue = i => { 90 | let scaleValue = 1 - this.scaleInterval * i; 91 | return scaleValue >= 0 ? scaleValue : 0; 92 | }; 93 | 94 | const getRotationValue = i => i ? i*this.rotationInterval : 0; 95 | 96 | // Create the gsap timeline 97 | this.hoverTimeline = gsap.timeline({paused: true}) 98 | .to(this.DOM.innerElems, { 99 | scale: i => getScaleValue(i), 100 | rotation: i => getRotationValue(i), 101 | duration: this.duration, 102 | ease: this.ease, 103 | stagger: this.stagger 104 | }); 105 | } 106 | 107 | /** 108 | * Initializes the events on the image elemment 109 | */ 110 | initEvents() { 111 | this.onMouseEnterFn = () => this.mouseEnter(); 112 | this.onMouseLeaveFn = () => this.mouseLeave(); 113 | this.DOM.el.addEventListener('mouseenter', this.onMouseEnterFn); 114 | this.DOM.el.addEventListener('mouseleave', this.onMouseLeaveFn); 115 | } 116 | 117 | /** 118 | * mouse enter 119 | */ 120 | mouseEnter() { 121 | // Play the hover timeline 122 | this.hoverTimeline.play(); 123 | } 124 | 125 | /** 126 | * mouse leave 127 | */ 128 | mouseLeave() { 129 | // Reverse the hover timeline 130 | this.hoverTimeline.reverse(); 131 | } 132 | } 133 | 134 | // The image element 135 | const theImage = document.querySelector('.image'); 136 | new ImageHover(theImage); 137 | 138 | -------------------------------------------------------------------------------- /002-repetition-hover-effect-square/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #091f22; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | color: var(--color-link); 28 | outline: none; 29 | } 30 | 31 | a:hover { 32 | color: var(--color-link-hover); 33 | outline: none; 34 | } 35 | 36 | a:focus { 37 | outline: none; 38 | background: lightgrey; 39 | } 40 | 41 | a:focus:not(:focus-visible) { 42 | background: transparent; 43 | } 44 | 45 | a:focus-visible { 46 | outline: 2px solid red; 47 | background: transparent; 48 | } 49 | 50 | .frame { 51 | padding: 1.5rem 2rem 10vh; 52 | text-align: center; 53 | position: relative; 54 | } 55 | 56 | .frame__title { 57 | margin: 0; 58 | font-size: 1rem; 59 | font-weight: 500; 60 | } 61 | 62 | .frame__links { 63 | margin: 0.5rem 0 2rem; 64 | } 65 | 66 | .frame__links a:not(:last-child) { 67 | margin-right: 1rem; 68 | } 69 | 70 | .content { 71 | flex: 1; 72 | display: grid; 73 | place-items: center; 74 | } 75 | 76 | .image { 77 | margin: 0 auto; 78 | display: grid; 79 | cursor: pointer; 80 | position: relative; 81 | overflow: hidden; 82 | width: 60vmin; 83 | height: 60vmin; 84 | background-size: cover; 85 | background-position: 50% 50%; 86 | } 87 | 88 | .image__element { 89 | transform-origin: inherit; 90 | position: relative; 91 | grid-area: 1 / 1 / 2 / 2; 92 | width: 100%; 93 | height: 100%; 94 | will-change: transform; 95 | border-radius: inherit; 96 | background-size: inherit; 97 | background-position: inherit; 98 | } 99 | 100 | @media screen and (min-width: 53em) { 101 | main { 102 | height: 100vh; 103 | display: flex; 104 | flex-direction: column; 105 | } 106 | .frame { 107 | padding: 1.5rem 2rem 0; 108 | display: grid; 109 | grid-template-columns: auto 1fr auto; 110 | grid-template-areas: 'title links sponsor'; 111 | grid-gap: 3vw; 112 | justify-content: space-between; 113 | text-align: left; 114 | } 115 | .frame__links { 116 | margin: 0; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /002-repetition-hover-effect-square/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/002-repetition-hover-effect-square/img/1.jpg -------------------------------------------------------------------------------- /002-repetition-hover-effect-square/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 002: Repetition Hover Effect (Square) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 002: Repetition Hover Effect (Square)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /002-repetition-hover-effect-square/js/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class representing an image that has the repetitive hover effect 3 | */ 4 | class ImageHover { 5 | // DOM elements 6 | DOM = { 7 | // main element (.image) 8 | el: null, 9 | // .image__element 10 | innerElems: null, 11 | } 12 | // Main element background image path 13 | bgImage; 14 | // Options that can be passed in data attributes. These are the defaults: 15 | // Duration 16 | duration = 0.5; 17 | // Easing function 18 | ease = 'power2.inOut'; 19 | // Stagger value between inner image elements 20 | stagger = 0; 21 | // Scale interval between inner image elements 22 | scaleInterval = 0.1; 23 | // Rotation interval between inner image elements 24 | rotationInterval = 0; 25 | // Total number of inner image elements 26 | innerTotal = 4; 27 | // Main element transform origin 28 | transformOrigin = '50% 50%'; 29 | // GSAP hover timeline 30 | hoverTimeline; 31 | 32 | /** 33 | * Constructor. 34 | * @param {Element} DOM_el - the .image element 35 | */ 36 | constructor(DOM_el) { 37 | // Main element 38 | this.DOM = {el: DOM_el}; 39 | 40 | // Options that can be passed in data attributes 41 | this.duration = this.DOM.el.dataset.repetitionDuration || this.duration; 42 | this.ease = this.DOM.el.dataset.repetitionEase || this.ease; 43 | this.stagger = this.DOM.el.dataset.repetitionStagger || this.stagger; 44 | this.scaleInterval = this.DOM.el.dataset.repetitionScaleInterval || this.scaleInterval; 45 | this.rotationInterval = this.DOM.el.dataset.repetitionRotationInterval || this.rotationInterval; 46 | this.innerTotal = this.DOM.el.dataset.repetitionCount || this.innerTotal; 47 | this.transformOrigin = this.DOM.el.dataset.repetitionOrigin || this.transformOrigin; 48 | 49 | // Get the main element's background image url 50 | this.bgImage = /(?:\(['"]?)(.*?)(?:['"]?\))/.exec(this.DOM.el.style.backgroundImage)[1] 51 | 52 | // Remove the background image from the main element 53 | // The dynamically created inner elements will have that background image 54 | gsap.set(this.DOM.el, {backgroundImage: 'none'}); 55 | 56 | // Add the .image__element inner elements (data-repetition-elems times) 57 | // Condition: minimum of 2 inner elments 58 | this.innerTotal = this.innerTotal <= 1 ? 2 : this.innerTotal; 59 | 60 | let innerHTML = ''; 61 | for (let i = 0, len = this.innerTotal; i <= len - 1; ++i) { 62 | innerHTML += `
`; 63 | } 64 | 65 | // Append to the main element 66 | this.DOM.el.innerHTML = innerHTML; 67 | 68 | // Get inner .image__element 69 | this.DOM.innerElems = this.DOM.el.querySelectorAll('.image__element'); 70 | 71 | // Set transform origin 72 | gsap.set(this.DOM.el, {transformOrigin: this.transformOrigin}); 73 | 74 | // Hover timeline 75 | this.createHoverTimeline(); 76 | 77 | // Init the hover events 78 | this.initEvents(); 79 | } 80 | 81 | /** 82 | * Create the gsap timeline for the hover in/out animation 83 | */ 84 | createHoverTimeline() { 85 | // Get the scale value based on the scale interval passed in data-repetition-scale-interval 86 | // e.g. if the scale interval is 0.1 then the inner elements will have the following scale values: 87 | // first element: 1; second: 0.9, third: 0.8 ... 88 | // If the value goes below 0 (too many inner elements) then the scale value defaults to 0 89 | const getScaleValue = i => { 90 | let scaleValue = 1 - this.scaleInterval * i; 91 | return scaleValue >= 0 ? scaleValue : 0; 92 | }; 93 | 94 | const getRotationValue = i => i ? i*this.rotationInterval : 0; 95 | 96 | // Create the gsap timeline 97 | this.hoverTimeline = gsap.timeline({paused: true}) 98 | .to(this.DOM.innerElems, { 99 | scale: i => getScaleValue(i), 100 | rotation: i => getRotationValue(i), 101 | duration: this.duration, 102 | ease: this.ease, 103 | stagger: this.stagger 104 | }); 105 | } 106 | 107 | /** 108 | * Initializes the events on the image elemment 109 | */ 110 | initEvents() { 111 | this.onMouseEnterFn = () => this.mouseEnter(); 112 | this.onMouseLeaveFn = () => this.mouseLeave(); 113 | this.DOM.el.addEventListener('mouseenter', this.onMouseEnterFn); 114 | this.DOM.el.addEventListener('mouseleave', this.onMouseLeaveFn); 115 | } 116 | 117 | /** 118 | * mouse enter 119 | */ 120 | mouseEnter() { 121 | // Play the hover timeline 122 | this.hoverTimeline.play(); 123 | } 124 | 125 | /** 126 | * mouse leave 127 | */ 128 | mouseLeave() { 129 | // Reverse the hover timeline 130 | this.hoverTimeline.reverse(); 131 | } 132 | } 133 | 134 | // The image element 135 | const theImage = document.querySelector('.image'); 136 | new ImageHover(theImage); 137 | 138 | -------------------------------------------------------------------------------- /003-repetition-hover-effect-rotated/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #333; 14 | --color-bg: #9caba0; 15 | --color-link: #000; 16 | --color-link-hover: #333; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | color: var(--color-link); 28 | outline: none; 29 | } 30 | 31 | a:hover { 32 | color: var(--color-link-hover); 33 | outline: none; 34 | } 35 | 36 | a:focus { 37 | outline: none; 38 | background: lightgrey; 39 | } 40 | 41 | a:focus:not(:focus-visible) { 42 | background: transparent; 43 | } 44 | 45 | a:focus-visible { 46 | outline: 2px solid red; 47 | background: transparent; 48 | } 49 | 50 | .frame { 51 | padding: 1.5rem 2rem 10vh; 52 | text-align: center; 53 | position: relative; 54 | } 55 | 56 | .frame__title { 57 | margin: 0; 58 | font-size: 1rem; 59 | font-weight: 500; 60 | } 61 | 62 | .frame__links { 63 | margin: 0.5rem 0 2rem; 64 | } 65 | 66 | .frame__links a:not(:last-child) { 67 | margin-right: 1rem; 68 | } 69 | 70 | .content { 71 | flex: 1; 72 | display: grid; 73 | place-items: center; 74 | } 75 | 76 | .image { 77 | margin: 0 auto; 78 | display: grid; 79 | cursor: pointer; 80 | position: relative; 81 | width: 60vw; 82 | height: 40vh; 83 | background-size: cover; 84 | background-position: 50% 50%; 85 | border: 1px solid black; 86 | } 87 | 88 | .image__element { 89 | transform-origin: inherit; 90 | position: relative; 91 | grid-area: 1 / 1 / 2 / 2; 92 | width: 100%; 93 | height: 100%; 94 | will-change: transform; 95 | border-radius: inherit; 96 | background-size: inherit; 97 | background-position: inherit; 98 | border: inherit; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | main { 103 | height: 100vh; 104 | display: flex; 105 | flex-direction: column; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /003-repetition-hover-effect-rotated/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/003-repetition-hover-effect-rotated/img/1.jpg -------------------------------------------------------------------------------- /003-repetition-hover-effect-rotated/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 003: Repetition Hover Effect (Rotated) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 003: Repetition Hover Effect (Rotated)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /003-repetition-hover-effect-rotated/js/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Class representing an image that has the repetitive hover effect 3 | */ 4 | class ImageHover { 5 | // DOM elements 6 | DOM = { 7 | // main element (.image) 8 | el: null, 9 | // .image__element 10 | innerElems: null, 11 | } 12 | // Main element background image path 13 | bgImage; 14 | // Options that can be passed in data attributes. These are the defaults: 15 | // Duration 16 | duration = 0.5; 17 | // Easing function 18 | ease = 'power2.inOut'; 19 | // Stagger value between inner image elements 20 | stagger = 0; 21 | // Scale interval between inner image elements 22 | scaleInterval = 0.1; 23 | // Rotation interval between inner image elements 24 | rotationInterval = 0; 25 | // Total number of inner image elements 26 | innerTotal = 4; 27 | // Main element transform origin 28 | transformOrigin = '50% 50%'; 29 | // GSAP hover timeline 30 | hoverTimeline; 31 | 32 | /** 33 | * Constructor. 34 | * @param {Element} DOM_el - the .image element 35 | */ 36 | constructor(DOM_el) { 37 | // Main element 38 | this.DOM = {el: DOM_el}; 39 | 40 | // Options that can be passed in data attributes 41 | this.duration = this.DOM.el.dataset.repetitionDuration || this.duration; 42 | this.ease = this.DOM.el.dataset.repetitionEase || this.ease; 43 | this.stagger = this.DOM.el.dataset.repetitionStagger || this.stagger; 44 | this.scaleInterval = this.DOM.el.dataset.repetitionScaleInterval || this.scaleInterval; 45 | this.rotationInterval = this.DOM.el.dataset.repetitionRotationInterval || this.rotationInterval; 46 | this.innerTotal = this.DOM.el.dataset.repetitionCount || this.innerTotal; 47 | this.transformOrigin = this.DOM.el.dataset.repetitionOrigin || this.transformOrigin; 48 | 49 | // Get the main element's background image url 50 | this.bgImage = /(?:\(['"]?)(.*?)(?:['"]?\))/.exec(this.DOM.el.style.backgroundImage)[1] 51 | 52 | // Remove the background image from the main element 53 | // The dynamically created inner elements will have that background image 54 | gsap.set(this.DOM.el, {backgroundImage: 'none'}); 55 | 56 | // Add the .image__element inner elements (data-repetition-elems times) 57 | // Condition: minimum of 2 inner elments 58 | this.innerTotal = this.innerTotal <= 1 ? 2 : this.innerTotal; 59 | 60 | let innerHTML = ''; 61 | for (let i = 0, len = this.innerTotal; i <= len - 1; ++i) { 62 | innerHTML += `
`; 63 | } 64 | 65 | // Append to the main element 66 | this.DOM.el.innerHTML = innerHTML; 67 | 68 | // Get inner .image__element 69 | this.DOM.innerElems = this.DOM.el.querySelectorAll('.image__element'); 70 | 71 | // Set transform origin 72 | gsap.set(this.DOM.el, {transformOrigin: this.transformOrigin}); 73 | 74 | // Hover timeline 75 | this.createHoverTimeline(); 76 | 77 | // Init the hover events 78 | this.initEvents(); 79 | } 80 | 81 | /** 82 | * Create the gsap timeline for the hover in/out animation 83 | */ 84 | createHoverTimeline() { 85 | // Get the scale value based on the scale interval passed in data-repetition-scale-interval 86 | // e.g. if the scale interval is 0.1 then the inner elements will have the following scale values: 87 | // first element: 1; second: 0.9, third: 0.8 ... 88 | // If the value goes below 0 (too many inner elements) then the scale value defaults to 0 89 | const getScaleValue = i => { 90 | let scaleValue = 1 - this.scaleInterval * i; 91 | return scaleValue >= 0 ? scaleValue : 0; 92 | }; 93 | 94 | const getRotationValue = i => i ? i*this.rotationInterval : 0; 95 | 96 | // Create the gsap timeline 97 | this.hoverTimeline = gsap.timeline({paused: true}) 98 | .to(this.DOM.innerElems, { 99 | scale: i => getScaleValue(i), 100 | rotation: i => getRotationValue(i), 101 | duration: this.duration, 102 | ease: this.ease, 103 | stagger: this.stagger 104 | }); 105 | } 106 | 107 | /** 108 | * Initializes the events on the image elemment 109 | */ 110 | initEvents() { 111 | this.onMouseEnterFn = () => this.mouseEnter(); 112 | this.onMouseLeaveFn = () => this.mouseLeave(); 113 | this.DOM.el.addEventListener('mouseenter', this.onMouseEnterFn); 114 | this.DOM.el.addEventListener('mouseleave', this.onMouseLeaveFn); 115 | } 116 | 117 | /** 118 | * mouse enter 119 | */ 120 | mouseEnter() { 121 | // Play the hover timeline 122 | this.hoverTimeline.play(); 123 | } 124 | 125 | /** 126 | * mouse leave 127 | */ 128 | mouseLeave() { 129 | // Reverse the hover timeline 130 | this.hoverTimeline.reverse(); 131 | } 132 | } 133 | 134 | // The image element 135 | const theImage = document.querySelector('.image'); 136 | new ImageHover(theImage); 137 | 138 | -------------------------------------------------------------------------------- /004-repetition-hover-effect-filter/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #000; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | a { 26 | text-decoration: none; 27 | color: var(--color-link); 28 | outline: none; 29 | } 30 | 31 | a:hover { 32 | color: var(--color-link-hover); 33 | outline: none; 34 | } 35 | 36 | a:focus { 37 | outline: none; 38 | background: lightgrey; 39 | } 40 | 41 | a:focus:not(:focus-visible) { 42 | background: transparent; 43 | } 44 | 45 | a:focus-visible { 46 | outline: 2px solid red; 47 | background: transparent; 48 | } 49 | 50 | .frame { 51 | padding: 1.5rem 2rem 10vh; 52 | text-align: center; 53 | position: relative; 54 | } 55 | 56 | .frame__title { 57 | margin: 0; 58 | font-size: 1rem; 59 | font-weight: 500; 60 | } 61 | 62 | .frame__links { 63 | margin: 0.5rem 0 2rem; 64 | } 65 | 66 | .frame__links a:not(:last-child) { 67 | margin-right: 1rem; 68 | } 69 | 70 | .content { 71 | flex: 1; 72 | display: grid; 73 | place-items: center; 74 | } 75 | 76 | .image { 77 | margin: 0 auto; 78 | display: grid; 79 | cursor: pointer; 80 | position: relative; 81 | overflow: hidden; 82 | width: 50vmin; 83 | height: 60vmin; 84 | border-radius: 3%; 85 | background-size: cover; 86 | background-position: 50% 50%; 87 | } 88 | 89 | .image__element { 90 | transform-origin: inherit; 91 | position: relative; 92 | grid-area: 1 / 1 / 2 / 2; 93 | width: 100%; 94 | height: 100%; 95 | will-change: transform, filter; 96 | border-radius: inherit; 97 | background-size: inherit; 98 | background-position: inherit; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | main { 103 | height: 100vh; 104 | display: flex; 105 | flex-direction: column; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /004-repetition-hover-effect-filter/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/004-repetition-hover-effect-filter/img/1.jpg -------------------------------------------------------------------------------- /004-repetition-hover-effect-filter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 004: Repetition Hover Effect (Filter) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 004: Repetition Hover Effect (Filter)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /005-image-motion-trail-opaque/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #161b1b; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 45vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | } 95 | 96 | @media screen and (min-width: 53em) { 97 | main { 98 | height: 100vh; 99 | display: flex; 100 | flex-direction: column; 101 | } 102 | .frame { 103 | padding: 1.5rem 2rem 0; 104 | display: grid; 105 | grid-template-columns: auto 1fr auto; 106 | grid-template-areas: 'title links sponsor'; 107 | grid-gap: 3vw; 108 | justify-content: space-between; 109 | text-align: left; 110 | } 111 | .frame__links { 112 | margin: 0; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /005-image-motion-trail-opaque/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/005-image-motion-trail-opaque/img/1.jpg -------------------------------------------------------------------------------- /005-image-motion-trail-opaque/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/005-image-motion-trail-opaque/img/bg.png -------------------------------------------------------------------------------- /005-image-motion-trail-opaque/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 005: Image Motion Trail (Opaque) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 005: Image Motion Trail (Opaque)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /006-image-motion-trail-semitransparent/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #161b1b; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 45vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | border-radius: 10px; 95 | } 96 | 97 | @media screen and (min-width: 53em) { 98 | main { 99 | height: 100vh; 100 | display: flex; 101 | flex-direction: column; 102 | } 103 | .frame { 104 | padding: 1.5rem 2rem 0; 105 | display: grid; 106 | grid-template-columns: auto 1fr auto; 107 | grid-template-areas: 'title links sponsor'; 108 | grid-gap: 3vw; 109 | justify-content: space-between; 110 | text-align: left; 111 | } 112 | .frame__links { 113 | margin: 0; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /006-image-motion-trail-semitransparent/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/006-image-motion-trail-semitransparent/img/1.jpg -------------------------------------------------------------------------------- /006-image-motion-trail-semitransparent/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/006-image-motion-trail-semitransparent/img/bg.png -------------------------------------------------------------------------------- /006-image-motion-trail-semitransparent/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 006: Image Motion Trail (Semi-transparent) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 006: Image Motion Trail (Semi-transparent)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /007-image-motion-trail-rotation/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #161b1b; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 55vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | } 95 | 96 | @media screen and (min-width: 53em) { 97 | main { 98 | height: 100vh; 99 | display: flex; 100 | flex-direction: column; 101 | } 102 | .frame { 103 | padding: 1.5rem 2rem 0; 104 | display: grid; 105 | grid-template-columns: auto 1fr auto; 106 | grid-template-areas: 'title links sponsor'; 107 | grid-gap: 3vw; 108 | justify-content: space-between; 109 | text-align: left; 110 | } 111 | .frame__links { 112 | margin: 0; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /007-image-motion-trail-rotation/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/007-image-motion-trail-rotation/img/1.jpg -------------------------------------------------------------------------------- /007-image-motion-trail-rotation/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/007-image-motion-trail-rotation/img/bg.png -------------------------------------------------------------------------------- /007-image-motion-trail-rotation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 007: Image Motion Trail (Rotation) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 007: Image Motion Trail (Rotation)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /008-image-motion-trail-circle/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #000000; 14 | --color-bg: #ede5da; 15 | --color-link: #ff0037; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 45vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | border-radius: 50%; 95 | } 96 | 97 | @media screen and (min-width: 53em) { 98 | main { 99 | height: 100vh; 100 | display: flex; 101 | flex-direction: column; 102 | } 103 | .frame { 104 | padding: 1.5rem 2rem 0; 105 | display: grid; 106 | grid-template-columns: auto 1fr auto; 107 | grid-template-areas: 'title links sponsor'; 108 | grid-gap: 3vw; 109 | justify-content: space-between; 110 | text-align: left; 111 | } 112 | .frame__links { 113 | margin: 0; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /008-image-motion-trail-circle/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/008-image-motion-trail-circle/img/1.jpg -------------------------------------------------------------------------------- /008-image-motion-trail-circle/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/008-image-motion-trail-circle/img/bg.png -------------------------------------------------------------------------------- /008-image-motion-trail-circle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 008: Image Motion Trail (Circle) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 008: Image Motion Trail (Circle)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /009-image-motion-trail-perspective/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #b2b8ac; 14 | --color-bg: #161b1b; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 65vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | } 95 | 96 | @media screen and (min-width: 53em) { 97 | main { 98 | height: 100vh; 99 | display: flex; 100 | flex-direction: column; 101 | } 102 | .frame { 103 | padding: 1.5rem 2rem 0; 104 | display: grid; 105 | grid-template-columns: auto 1fr auto; 106 | grid-template-areas: 'title links sponsor'; 107 | grid-gap: 3vw; 108 | justify-content: space-between; 109 | text-align: left; 110 | } 111 | .frame__links { 112 | margin: 0; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /009-image-motion-trail-perspective/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/009-image-motion-trail-perspective/img/1.jpg -------------------------------------------------------------------------------- /009-image-motion-trail-perspective/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/009-image-motion-trail-perspective/img/bg.png -------------------------------------------------------------------------------- /009-image-motion-trail-perspective/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 009: Image Motion Trail (Perspective) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 009: Image Motion Trail (Perspective)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /010-image-motion-trail-perspective/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #ae7b7c; 14 | --color-bg: #25201a; 15 | --color-link: #fff; 16 | --color-link-hover: #b2b8ac; 17 | color: var(--color-text); 18 | background: var(--color-bg) url(../img/bg.png); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | } 25 | 26 | a { 27 | text-decoration: none; 28 | color: var(--color-link); 29 | outline: none; 30 | } 31 | 32 | a:hover { 33 | color: var(--color-link-hover); 34 | outline: none; 35 | } 36 | 37 | a:focus { 38 | outline: none; 39 | background: lightgrey; 40 | } 41 | 42 | a:focus:not(:focus-visible) { 43 | background: transparent; 44 | } 45 | 46 | a:focus-visible { 47 | outline: 2px solid red; 48 | background: transparent; 49 | } 50 | 51 | .frame { 52 | padding: 1.5rem 2rem 10vh; 53 | text-align: center; 54 | position: relative; 55 | } 56 | 57 | .frame__title { 58 | margin: 0; 59 | font-size: 1rem; 60 | font-weight: 500; 61 | } 62 | 63 | .frame__links { 64 | margin: 0.5rem 0 2rem; 65 | } 66 | 67 | .frame__links a:not(:last-child) { 68 | margin-right: 1rem; 69 | } 70 | 71 | .content { 72 | flex: 1; 73 | display: grid; 74 | place-items: center; 75 | } 76 | 77 | .trail { 78 | position: relative; 79 | display: grid; 80 | place-items: center; 81 | } 82 | 83 | .no-js .trail { 84 | width: 250px; 85 | height: 375px; 86 | background-size: cover; 87 | } 88 | 89 | .trail__img { 90 | max-height: 45vh; 91 | position: relative; 92 | will-change: transform; 93 | grid-area: 1 / 1 / 2 / 2; 94 | } 95 | 96 | @media screen and (min-width: 53em) { 97 | main { 98 | height: 100vh; 99 | display: flex; 100 | flex-direction: column; 101 | } 102 | .frame { 103 | padding: 1.5rem 2rem 0; 104 | display: grid; 105 | grid-template-columns: auto 1fr auto; 106 | grid-template-areas: 'title links sponsor'; 107 | grid-gap: 3vw; 108 | justify-content: space-between; 109 | text-align: left; 110 | } 111 | .frame__links { 112 | margin: 0; 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /010-image-motion-trail-perspective/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/010-image-motion-trail-perspective/img/1.jpg -------------------------------------------------------------------------------- /010-image-motion-trail-perspective/img/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/010-image-motion-trail-perspective/img/bg.png -------------------------------------------------------------------------------- /010-image-motion-trail-perspective/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 010: Image Motion Trail (Perspective) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 010: Image Motion Trail (Perspective)

19 | 21 |
22 |
23 |
24 |
25 |
26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /011-custom-cursor-filled-circle/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-text-alt: #747474; 15 | --color-bg: #5b5b5f; 16 | --color-link: #e9c58f; 17 | --color-link-hover: #fff; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-inner: #fff; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 4vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: var(--cursor-fill); 133 | } 134 | 135 | .no-js .cursor { 136 | display: none; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /011-custom-cursor-filled-circle/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 011: Custom Cursor (filled circle) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 011: Custom Cursor (filled circle)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /012-custom-cursor-two-circles/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-text-alt: #747474; 15 | --color-bg: #151518; 16 | --color-link: #e9c58f; 17 | --color-link-hover: #fff; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-dot: #fff; 25 | --cursor-circle: #fff; 26 | } 27 | 28 | a { 29 | text-decoration: none; 30 | color: var(--color-link); 31 | outline: none; 32 | } 33 | 34 | a:hover { 35 | color: var(--color-link-hover); 36 | outline: none; 37 | } 38 | 39 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 40 | a:focus { 41 | /* Provide a fallback style for browsers 42 | that don't support :focus-visible */ 43 | outline: none; 44 | background: lightgrey; 45 | } 46 | 47 | a:focus:not(:focus-visible) { 48 | /* Remove the focus indicator on mouse-focus for browsers 49 | that do support :focus-visible */ 50 | background: transparent; 51 | } 52 | 53 | a:focus-visible { 54 | /* Draw a very noticeable focus style for 55 | keyboard-focus on browsers that do support 56 | :focus-visible */ 57 | outline: 2px solid red; 58 | background: transparent; 59 | } 60 | 61 | main { 62 | height: 100vh; 63 | display: flex; 64 | flex-direction: column; 65 | } 66 | 67 | .frame { 68 | padding: 1.5rem 2rem 10vh; 69 | text-align: center; 70 | position: relative; 71 | } 72 | 73 | .frame__title { 74 | margin: 0; 75 | font-size: 1rem; 76 | font-weight: 500; 77 | } 78 | 79 | .frame__links { 80 | margin: 0.5rem 0 2rem; 81 | } 82 | 83 | .frame__links a:not(:last-child) { 84 | margin-right: 1rem; 85 | } 86 | 87 | .menu { 88 | flex: 1; 89 | display: grid; 90 | place-items: center; 91 | align-self: center; 92 | grid-gap: 7vw; 93 | font-size: 2rem; 94 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 95 | 96 | } 97 | 98 | .cursor { 99 | display: none; 100 | } 101 | 102 | @media screen and (min-width: 53em) { 103 | .menu { 104 | font-size: 4vw; 105 | grid-auto-flow: column; 106 | max-width: min-content; 107 | } 108 | .frame { 109 | padding: 1.5rem 2rem 0; 110 | display: grid; 111 | grid-template-columns: auto 1fr auto; 112 | grid-template-areas: 'title links sponsor'; 113 | grid-gap: 3vw; 114 | justify-content: space-between; 115 | text-align: left; 116 | } 117 | .frame__links { 118 | margin: 0; 119 | } 120 | } 121 | 122 | @media (any-pointer:fine) { 123 | .cursor { 124 | position: fixed; 125 | top: 0; 126 | left: 0; 127 | display: block; 128 | pointer-events: none; 129 | z-index: 10000; 130 | } 131 | 132 | .cursor--1 .cursor__inner { 133 | fill: var(--cursor-dot); 134 | } 135 | 136 | .cursor--2 .cursor__inner { 137 | fill: none; 138 | stroke: var(--cursor-circle); 139 | stroke-width: 1px; 140 | } 141 | 142 | .no-js .cursor { 143 | display: none; 144 | } 145 | } -------------------------------------------------------------------------------- /012-custom-cursor-two-circles/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 012: Custom Cursor (two circles, one filled) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 012: Custom Cursor (two circles, one filled)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /013-custom-cursor-filter/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #919191; 14 | --color-text-alt: #747474; 15 | --color-bg: #eaeaea; 16 | --color-link: #000000; 17 | --color-link-hover: #104ed6; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-stroke: #104ed6; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 4vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: none; 133 | stroke: var(--cursor-stroke); 134 | stroke-width: 1px; 135 | } 136 | 137 | .no-js .cursor { 138 | display: none; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /013-custom-cursor-filter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 013: Custom Cursor (two circles with filter effect) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 013: Custom Cursor (two circles with filter effect)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /014-custom-cursor-filter-2/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #919191; 14 | --color-text-alt: #747474; 15 | --color-bg: #c9cac1; 16 | --color-link: #000000; 17 | --color-link-hover: #ffffff; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-stroke: #000000; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 4vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: none; 133 | stroke: var(--cursor-stroke); 134 | stroke-width: 1.2px; 135 | } 136 | 137 | .no-js .cursor { 138 | display: none; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /014-custom-cursor-filter-2/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/014-custom-cursor-filter-2/favicon.ico -------------------------------------------------------------------------------- /014-custom-cursor-filter-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 014: Custom Cursor (filter effect and delayed motion) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 014: Custom Cursor (filter effect and delayed motion)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /015-custom-cursor-filter-3/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #919191; 14 | --color-text-alt: #747474; 15 | --color-bg: #0f0e0e; 16 | --color-link: #e5e5e5; 17 | --color-link-hover: #d6cecb; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-stroke: #f1490a; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 4vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: none; 133 | stroke: var(--cursor-stroke); 134 | stroke-width: 1px; 135 | } 136 | 137 | .no-js .cursor { 138 | display: none; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /015-custom-cursor-filter-3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 015: Custom Cursor (multiple circles with filter effect) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 015: Custom Cursor (multiple circles with filter effect)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /016-custom-cursor-filter-4/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #a5a5a5; 14 | --color-text-alt: #747474; 15 | --color-bg: #f3ede8; 16 | --color-link: #000000; 17 | --color-link-hover: #d6106c; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-fill: #d6106c; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 3vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: var(--cursor-fill); 133 | } 134 | 135 | .no-js .cursor { 136 | display: none; 137 | } 138 | 139 | } -------------------------------------------------------------------------------- /016-custom-cursor-filter-4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 016: Custom Cursor (filled circle with filter effect) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 016: Custom Cursor (filled circle with filter effect)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /017-custom-cursor-filter-5/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #cda3a3; 14 | --color-text-alt: #747474; 15 | --color-bg: #131111; 16 | --color-link: #d7d7d7; 17 | --color-link-hover: #848484; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-stroke: #c03030; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 3vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: none; 133 | stroke: var(--cursor-stroke); 134 | stroke-width: 3px; 135 | } 136 | 137 | .no-js .cursor { 138 | display: none; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /017-custom-cursor-filter-5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 017: Custom Cursor (stroke circle with filter effect) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 017: Custom Cursor (stroke circle with filter effect)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /018-custom-cursor-filter-6/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #a3abcd; 14 | --color-text-alt: #747474; 15 | --color-bg: #f1f1f1; 16 | --color-link: #161616; 17 | --color-link-hover: #797979; 18 | color: var(--color-text); 19 | background: var(--color-bg); 20 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 21 | font-weight: 500; 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | --cursor-stroke: #000000; 25 | } 26 | 27 | a { 28 | text-decoration: none; 29 | color: var(--color-link); 30 | outline: none; 31 | } 32 | 33 | a:hover { 34 | color: var(--color-link-hover); 35 | outline: none; 36 | } 37 | 38 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 39 | a:focus { 40 | /* Provide a fallback style for browsers 41 | that don't support :focus-visible */ 42 | outline: none; 43 | background: lightgrey; 44 | } 45 | 46 | a:focus:not(:focus-visible) { 47 | /* Remove the focus indicator on mouse-focus for browsers 48 | that do support :focus-visible */ 49 | background: transparent; 50 | } 51 | 52 | a:focus-visible { 53 | /* Draw a very noticeable focus style for 54 | keyboard-focus on browsers that do support 55 | :focus-visible */ 56 | outline: 2px solid red; 57 | background: transparent; 58 | } 59 | 60 | main { 61 | height: 100vh; 62 | display: flex; 63 | flex-direction: column; 64 | } 65 | 66 | .frame { 67 | padding: 1.5rem 2rem 10vh; 68 | text-align: center; 69 | position: relative; 70 | } 71 | 72 | .frame__title { 73 | margin: 0; 74 | font-size: 1rem; 75 | font-weight: 500; 76 | } 77 | 78 | .frame__links { 79 | margin: 0.5rem 0 2rem; 80 | } 81 | 82 | .frame__links a:not(:last-child) { 83 | margin-right: 1rem; 84 | } 85 | 86 | .menu { 87 | flex: 1; 88 | display: grid; 89 | place-items: center; 90 | align-self: center; 91 | grid-gap: 7vw; 92 | font-size: 2rem; 93 | font-family: "Goudy Old Style", Garamond, "Big Caslon", "Times New Roman", serif; 94 | 95 | } 96 | 97 | .cursor { 98 | display: none; 99 | } 100 | 101 | @media screen and (min-width: 53em) { 102 | .menu { 103 | font-size: 3vw; 104 | grid-auto-flow: column; 105 | max-width: min-content; 106 | } 107 | .frame { 108 | padding: 1.5rem 2rem 0; 109 | display: grid; 110 | grid-template-columns: auto 1fr auto; 111 | grid-template-areas: 'title links sponsor'; 112 | grid-gap: 3vw; 113 | justify-content: space-between; 114 | text-align: left; 115 | } 116 | .frame__links { 117 | margin: 0; 118 | } 119 | } 120 | 121 | @media (any-pointer:fine) { 122 | .cursor { 123 | position: fixed; 124 | top: 0; 125 | left: 0; 126 | display: block; 127 | pointer-events: none; 128 | z-index: 10000; 129 | } 130 | 131 | .cursor__inner { 132 | fill: none; 133 | stroke: var(--cursor-stroke); 134 | stroke-width: 1.2px; 135 | } 136 | 137 | .no-js .cursor { 138 | display: none; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /018-custom-cursor-filter-6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 018: Custom Cursor (two circles with filter effect and motion delay) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 018: Custom Cursor (two circles with filter and delays)

19 | 21 |
22 | 28 |
29 | 30 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /019-image-motion-svg-filter/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #0d0d0e; 15 | --color-link: #b3382c; 16 | --color-link-hover: #d6665b; 17 | color: var(--color-text); 18 | background: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | width: 100%; 24 | height: 100vh; 25 | overflow: hidden; 26 | } 27 | 28 | a { 29 | text-decoration: none; 30 | color: var(--color-link); 31 | outline: none; 32 | } 33 | 34 | a:hover { 35 | color: var(--color-link-hover); 36 | outline: none; 37 | } 38 | 39 | a:focus { 40 | outline: none; 41 | background: lightgrey; 42 | } 43 | 44 | a:focus:not(:focus-visible) { 45 | background: transparent; 46 | } 47 | 48 | a:focus-visible { 49 | outline: 2px solid red; 50 | background: transparent; 51 | } 52 | 53 | .frame { 54 | padding: 1.5rem 2rem 10vh; 55 | text-align: center; 56 | position: relative; 57 | z-index: 100; 58 | } 59 | 60 | .frame__title { 61 | margin: 0; 62 | font-size: 1rem; 63 | font-weight: 500; 64 | } 65 | 66 | .frame__links { 67 | margin: 0.5rem 0 2rem; 68 | } 69 | 70 | .frame__links a:not(:last-child) { 71 | margin-right: 1rem; 72 | } 73 | 74 | .content { 75 | flex: 1; 76 | display: grid; 77 | place-items: center; 78 | position: absolute; 79 | width: 100%; 80 | height: 100%; 81 | } 82 | 83 | #theSVG { 84 | position: relative; 85 | display: grid; 86 | place-items: center; 87 | max-height: 65vh; 88 | grid-area: 1 / 1 / 2 / 2; 89 | will-change: transform; 90 | } 91 | 92 | @media screen and (min-width: 53em) { 93 | main { 94 | height: 100vh; 95 | display: flex; 96 | flex-direction: column; 97 | } 98 | .frame { 99 | padding: 1.5rem 2rem 0; 100 | display: grid; 101 | grid-template-columns: auto 1fr auto; 102 | grid-template-areas: 'title links sponsor'; 103 | grid-gap: 3vw; 104 | justify-content: space-between; 105 | text-align: left; 106 | } 107 | .frame__links { 108 | margin: 0; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /019-image-motion-svg-filter/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/019-image-motion-svg-filter/img/1.jpg -------------------------------------------------------------------------------- /019-image-motion-svg-filter/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 019: Image Motion Effect with SVG Filter Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 019: Image Motion Effect with SVG Filter

19 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /019-image-motion-svg-filter/js/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Linear interpolation 3 | * @param {Number} a - first value to interpolate 4 | * @param {Number} b - second value to interpolate 5 | * @param {Number} n - amount to interpolate 6 | */ 7 | const lerp = (a, b, n) => (1 - n) * a + n * b; 8 | 9 | /** 10 | * Gets the cursor position 11 | * @param {Event} ev - mousemove event 12 | */ 13 | const getCursorPos = ev => { 14 | return { 15 | x : ev.clientX, 16 | y : ev.clientY 17 | }; 18 | }; 19 | 20 | /** 21 | * Map number x from range [a, b] to [c, d] 22 | * @param {Number} x - changing value 23 | * @param {Number} a 24 | * @param {Number} b 25 | * @param {Number} c 26 | * @param {Number} d 27 | */ 28 | const map = (x, a, b, c, d) => (x - a) * (d - c) / (b - a) + c; 29 | 30 | /** 31 | * Distance between point A(x1,y1) and B(x2,y2) 32 | * @param {Number} x1 33 | * @param {Number} x2 34 | * @param {Number} y1 35 | * @param {Number} y2 36 | */ 37 | const distance = (x1,x2,y1,y2) => { 38 | var a = x1 - x2; 39 | var b = y1 - y2; 40 | return Math.hypot(a,b); 41 | }; 42 | 43 | /** 44 | * Calculates the viewport size 45 | */ 46 | const calcWinsize = () => { 47 | return { 48 | width: window.innerWidth, 49 | height: window.innerHeight 50 | } 51 | } 52 | 53 | // Viewport size 54 | let winsize = calcWinsize(); 55 | // Re-calculate on resize 56 | window.addEventListener('resize', () => winsize = calcWinsize()); 57 | 58 | // Track the cursor position 59 | let cursor = {x: winsize.width/2, y: winsize.height/2}; 60 | let cachedCursor = cursor; 61 | window.addEventListener('mousemove', ev => cursor = getCursorPos(ev)); 62 | 63 | /** 64 | * Class representing an SVG image that follows the cursor 65 | * and gets "distorted" as the cursor moves faster. 66 | */ 67 | class SVGImageFilterEffect { 68 | // DOM elements 69 | DOM = { 70 | // Main element (SVG element) 71 | el: null, 72 | // the SVG image 73 | image: null, 74 | // feDisplacementMap element 75 | feDisplacementMapEl: null, 76 | }; 77 | // option defaults 78 | defaults = { 79 | // How much to translate and rotate the image 80 | // Also the range of the displacementScale values 81 | valuesFromTo: { 82 | transform: { 83 | x: [-120,120], 84 | y: [-120,120], 85 | rz: [-10,10] 86 | }, 87 | displacementScale: [0, 400], 88 | }, 89 | // The "amt" is the amount to interpolate. 90 | // With interpolation, we can achieve a smooth animation effect when moving the cursor. 91 | amt: { 92 | transform: 0.1, 93 | displacementScale: 0.06, 94 | }, 95 | }; 96 | // Values that change when moving the cursor (transform and feDisplacementMap scale values) 97 | imgValues = { 98 | imgTransforms: {x: 0, y: 0, rz: 0}, 99 | displacementScale: 0, 100 | }; 101 | 102 | /** 103 | * Constructor. 104 | * @param {Element} DOM_el - the SVG element 105 | * @param {JSON} options 106 | */ 107 | constructor(DOM_el, options) { 108 | this.DOM.el = DOM_el; 109 | this.DOM.image = this.DOM.el.querySelector('image'); 110 | this.DOM.feDisplacementMapEl = this.DOM.el.querySelector('feDisplacementMap'); 111 | 112 | this.options = Object.assign(this.defaults, options); 113 | 114 | requestAnimationFrame(() => this.render()); 115 | } 116 | /** 117 | * Loop / Interpolation 118 | */ 119 | render() { 120 | // Apply interpolated values (smooth effect) 121 | this.imgValues.imgTransforms.x = lerp(this.imgValues.imgTransforms.x, map(cursor.x, 0, winsize.width, this.options.valuesFromTo.transform.x[0], this.options.valuesFromTo.transform.x[1]), this.options.amt.transform); 122 | this.imgValues.imgTransforms.y = lerp(this.imgValues.imgTransforms.y, map(cursor.y, 0, winsize.height, this.options.valuesFromTo.transform.y[0], this.options.valuesFromTo.transform.y[1]), this.options.amt.transform); 123 | this.imgValues.imgTransforms.rz = lerp(this.imgValues.imgTransforms.rz, map(cursor.x, 0, winsize.width, this.options.valuesFromTo.transform.rz[0], this.options.valuesFromTo.transform.rz[1]), this.options.amt.transform); 124 | 125 | this.DOM.el.style.transform = `translateX(${(this.imgValues.imgTransforms.x)}px) translateY(${this.imgValues.imgTransforms.y}px) rotateZ(${this.imgValues.imgTransforms.rz}deg)`; 126 | 127 | const cursorTravelledDistance = distance(cachedCursor.x, cursor.x, cachedCursor.y, cursor.y); 128 | this.imgValues.displacementScale = lerp(this.imgValues.displacementScale, map(cursorTravelledDistance, 0, 200, this.options.valuesFromTo.displacementScale[0], this.options.valuesFromTo.displacementScale[1]), this.options.amt.displacementScale); 129 | this.DOM.feDisplacementMapEl.scale.baseVal = this.imgValues.displacementScale; 130 | 131 | cachedCursor = cursor; 132 | 133 | // loop... 134 | requestAnimationFrame(() => this.render()); 135 | } 136 | } 137 | 138 | // Initialize trail effect 139 | new SVGImageFilterEffect(document.querySelector('#theSVG')); -------------------------------------------------------------------------------- /020-image-motion-svg-filter-2/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #162533; 15 | --color-link: #dba653; 16 | --color-link-hover: #d7b785; 17 | color: var(--color-text); 18 | background: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | width: 100%; 24 | height: 100vh; 25 | overflow: hidden; 26 | } 27 | 28 | a { 29 | text-decoration: none; 30 | color: var(--color-link); 31 | outline: none; 32 | } 33 | 34 | a:hover { 35 | color: var(--color-link-hover); 36 | outline: none; 37 | } 38 | 39 | a:focus { 40 | outline: none; 41 | background: lightgrey; 42 | } 43 | 44 | a:focus:not(:focus-visible) { 45 | background: transparent; 46 | } 47 | 48 | a:focus-visible { 49 | outline: 2px solid red; 50 | background: transparent; 51 | } 52 | 53 | .frame { 54 | padding: 1.5rem 2rem 10vh; 55 | text-align: center; 56 | position: relative; 57 | z-index: 100; 58 | } 59 | 60 | .frame__title { 61 | margin: 0; 62 | font-size: 1rem; 63 | font-weight: 500; 64 | } 65 | 66 | .frame__links { 67 | margin: 0.5rem 0 2rem; 68 | } 69 | 70 | .frame__links a:not(:last-child) { 71 | margin-right: 1rem; 72 | } 73 | 74 | .content { 75 | flex: 1; 76 | display: grid; 77 | place-items: center; 78 | position: absolute; 79 | width: 100%; 80 | height: 100%; 81 | } 82 | 83 | #theSVG { 84 | position: relative; 85 | display: grid; 86 | place-items: center; 87 | max-height: 65vh; 88 | grid-area: 1 / 1 / 2 / 2; 89 | will-change: transform; 90 | } 91 | 92 | @media screen and (min-width: 53em) { 93 | main { 94 | height: 100vh; 95 | display: flex; 96 | flex-direction: column; 97 | } 98 | .frame { 99 | padding: 1.5rem 2rem 0; 100 | display: grid; 101 | grid-template-columns: auto 1fr auto; 102 | grid-template-areas: 'title links sponsor'; 103 | grid-gap: 3vw; 104 | justify-content: space-between; 105 | text-align: left; 106 | } 107 | .frame__links { 108 | margin: 0; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /020-image-motion-svg-filter-2/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/020-image-motion-svg-filter-2/img/1.jpg -------------------------------------------------------------------------------- /020-image-motion-svg-filter-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 020: Image Motion Effect with SVG Filter Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 020: Image Motion Effect with SVG Filter

19 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /021-svg-path-page-transition-vertical/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #000; 14 | --color-bg-view-1: #f3efe6; 15 | --color-bg-view-2: #cbb37e; 16 | --color-link: #000; 17 | --color-link-hover: #000; 18 | --color-button: #000; 19 | --color-button-hover: #634c18; 20 | color: var(--color-text); 21 | background-color: var(--color-bg-view-1); 22 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 23 | font-weight: 500; 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | overflow: hidden; 27 | } 28 | 29 | a { 30 | text-decoration: none; 31 | color: var(--color-link); 32 | outline: none; 33 | } 34 | 35 | a:hover { 36 | color: var(--color-link-hover); 37 | outline: none; 38 | } 39 | 40 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 41 | a:focus { 42 | /* Provide a fallback style for browsers 43 | that don't support :focus-visible */ 44 | outline: none; 45 | background: lightgrey; 46 | } 47 | 48 | a:focus:not(:focus-visible) { 49 | /* Remove the focus indicator on mouse-focus for browsers 50 | that do support :focus-visible */ 51 | background: transparent; 52 | } 53 | 54 | a:focus-visible { 55 | /* Draw a very noticeable focus style for 56 | keyboard-focus on browsers that do support 57 | :focus-visible */ 58 | outline: 2px solid #fff; 59 | background: transparent; 60 | } 61 | 62 | .unbutton { 63 | background: none; 64 | border: 0; 65 | padding: 0; 66 | margin: 0; 67 | font: inherit; 68 | cursor: pointer; 69 | } 70 | 71 | .unbutton:focus { 72 | outline: none; 73 | } 74 | 75 | main { 76 | display: grid; 77 | grid-template-columns: 100%; 78 | grid-template-rows: 100vh; 79 | } 80 | 81 | .frame { 82 | grid-area: 1 / 1 / 2 / 2; 83 | padding: 1.5rem 2rem 10vh; 84 | text-align: center; 85 | position: relative; 86 | z-index: 100; 87 | pointer-events: none; 88 | } 89 | 90 | .frame a { 91 | pointer-events: auto; 92 | } 93 | 94 | .frame__title { 95 | margin: 0; 96 | font-size: 1rem; 97 | font-weight: 500; 98 | } 99 | 100 | .frame__links { 101 | margin: 0.5rem 0 2rem; 102 | } 103 | 104 | .frame__links a:not(:last-child) { 105 | margin-right: 1rem; 106 | } 107 | 108 | .button { 109 | color: var(--color-button); 110 | border-radius: 30px; 111 | min-width: 150px; 112 | padding: 1rem 2rem; 113 | border: 1px solid currentColor; 114 | } 115 | 116 | .button:hover, 117 | .button:focus-visible { 118 | color: var(--color-button-hover); 119 | } 120 | 121 | .frame--view-open .button-open { 122 | opacity: 0; 123 | pointer-events: none; 124 | } 125 | 126 | .view { 127 | position: relative; 128 | grid-area: 1 / 1 / 2 / 2; 129 | display: grid; 130 | place-items: center; 131 | } 132 | 133 | .view--2 { 134 | background: var(--color-bg-view-2); 135 | pointer-events: none; 136 | opacity: 0; 137 | } 138 | 139 | .view.view--open { 140 | pointer-events: auto; 141 | opacity: 1; 142 | } 143 | 144 | .overlay { 145 | grid-area: 1 / 1 / 2 / 2; 146 | position: relative; 147 | z-index: 1000; 148 | pointer-events: none; 149 | width: 100%; 150 | height: 100%; 151 | } 152 | 153 | @media screen and (min-width: 53em) { 154 | .frame { 155 | padding: 1.5rem 2rem 0; 156 | display: grid; 157 | grid-template-columns: auto 1fr auto; 158 | grid-template-areas: 'title links sponsor'; 159 | grid-gap: 3vw; 160 | justify-content: space-between; 161 | text-align: left; 162 | } 163 | .frame__links { 164 | margin: 0; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /021-svg-path-page-transition-vertical/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 021: SVG Path Page Transition (Vertical) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 021: SVG Path Page Transition (Vertical)

19 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /021-svg-path-page-transition-vertical/js/index.js: -------------------------------------------------------------------------------- 1 | // frame element 2 | const frame = document.querySelector('.frame'); 3 | 4 | // overlay (SVG path element) 5 | const overlayPath = document.querySelector('.overlay__path'); 6 | 7 | // paths 8 | // edit here: https://yqnn.github.io/svg-path-editor/ 9 | const paths = { 10 | step1: { 11 | unfilled: 'M 0 100 V 100 Q 50 100 100 100 V 100 z', 12 | inBetween: { 13 | curve1: 'M 0 100 V 50 Q 50 0 100 50 V 100 z', 14 | curve2: 'M 0 100 V 50 Q 50 100 100 50 V 100 z' 15 | }, 16 | filled: 'M 0 100 V 0 Q 50 0 100 0 V 100 z', 17 | }, 18 | step2: { 19 | filled: 'M 0 0 V 100 Q 50 100 100 100 V 0 z', 20 | inBetween: { 21 | curve1: 'M 0 0 V 50 Q 50 0 100 50 V 0 z', 22 | curve2: 'M 0 0 V 50 Q 50 100 100 50 V 0 z' 23 | }, 24 | unfilled: 'M 0 0 V 0 Q 50 0 100 0 V 0 z', 25 | } 26 | }; 27 | 28 | // landing page/content element 29 | const landingEl = document.querySelector('.view--2'); 30 | 31 | // transition trigger button 32 | const switchCtrl = document.querySelector('button.button--open'); 33 | 34 | // back button 35 | const backCtrl = landingEl.querySelector('.button--close'); 36 | 37 | let isAnimating = false; 38 | 39 | let page = 1; 40 | 41 | // reveals the second content view 42 | const reveal = () => { 43 | 44 | if ( isAnimating ) return; 45 | isAnimating = true; 46 | 47 | page = 2; 48 | 49 | gsap.timeline({ 50 | onComplete: () => isAnimating = false 51 | }) 52 | .set(overlayPath, { 53 | attr: { d: paths.step1.unfilled } 54 | }) 55 | .to(overlayPath, { 56 | duration: 0.8, 57 | ease: 'power4.in', 58 | attr: { d: paths.step1.inBetween.curve1 } 59 | }, 0) 60 | .to(overlayPath, { 61 | duration: 0.2, 62 | ease: 'power1', 63 | attr: { d: paths.step1.filled }, 64 | onComplete: () => switchPages() 65 | }) 66 | 67 | .set(overlayPath, { 68 | attr: { d: paths.step2.filled } 69 | }) 70 | 71 | .to(overlayPath, { 72 | duration: 0.2, 73 | ease: 'sine.in', 74 | attr: { d: paths.step2.inBetween.curve1 } 75 | }) 76 | .to(overlayPath, { 77 | duration: 1, 78 | ease: 'power4', 79 | attr: { d: paths.step2.unfilled } 80 | }); 81 | } 82 | 83 | const switchPages = () => { 84 | if ( page === 2 ) { 85 | frame.classList.add('frame--view-open'); 86 | landingEl.classList.add('view--open'); 87 | } 88 | else { 89 | frame.classList.remove('frame--view-open'); 90 | landingEl.classList.remove('view--open'); 91 | } 92 | } 93 | 94 | // back to first content view 95 | const unreveal = () => { 96 | 97 | if ( isAnimating ) return; 98 | isAnimating = true; 99 | 100 | page = 1; 101 | 102 | gsap.timeline({ 103 | onComplete: () => isAnimating = false 104 | }) 105 | .set(overlayPath, { 106 | attr: { d: paths.step2.unfilled } 107 | }) 108 | .to(overlayPath, { 109 | duration: 0.8, 110 | ease: 'power4.in', 111 | attr: { d: paths.step2.inBetween.curve2 } 112 | }, 0) 113 | .to(overlayPath, { 114 | duration: 0.2, 115 | ease: 'power1', 116 | attr: { d: paths.step2.filled }, 117 | onComplete: () => switchPages() 118 | }) 119 | // now reveal 120 | .set(overlayPath, { 121 | attr: { d: paths.step1.filled } 122 | }) 123 | .to(overlayPath, { 124 | duration: 0.2, 125 | ease: 'sine.in', 126 | attr: { d: paths.step1.inBetween.curve2 } 127 | }) 128 | .to(overlayPath, { 129 | duration: 1, 130 | ease: 'power4', 131 | attr: { d: paths.step1.unfilled } 132 | }); 133 | } 134 | 135 | // click on menu button 136 | switchCtrl.addEventListener('click', reveal); 137 | // click on close menu button 138 | backCtrl.addEventListener('click', unreveal); -------------------------------------------------------------------------------- /022-svg-path-page-transition-horizontal/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #000; 14 | --color-bg-view-1: #9da0dd; 15 | --color-bg-view-2: #5d61b4; 16 | --color-link: #000; 17 | --color-link-hover: #000; 18 | --color-button: #000; 19 | --color-button-hover: #22267d; 20 | color: var(--color-text); 21 | background-color: var(--color-bg-view-1); 22 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 23 | font-weight: 500; 24 | -webkit-font-smoothing: antialiased; 25 | -moz-osx-font-smoothing: grayscale; 26 | overflow: hidden; 27 | } 28 | 29 | a { 30 | text-decoration: none; 31 | color: var(--color-link); 32 | outline: none; 33 | } 34 | 35 | a:hover { 36 | color: var(--color-link-hover); 37 | outline: none; 38 | } 39 | 40 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 41 | a:focus { 42 | /* Provide a fallback style for browsers 43 | that don't support :focus-visible */ 44 | outline: none; 45 | background: lightgrey; 46 | } 47 | 48 | a:focus:not(:focus-visible) { 49 | /* Remove the focus indicator on mouse-focus for browsers 50 | that do support :focus-visible */ 51 | background: transparent; 52 | } 53 | 54 | a:focus-visible { 55 | /* Draw a very noticeable focus style for 56 | keyboard-focus on browsers that do support 57 | :focus-visible */ 58 | outline: 2px solid #fff; 59 | background: transparent; 60 | } 61 | 62 | .unbutton { 63 | background: none; 64 | border: 0; 65 | padding: 0; 66 | margin: 0; 67 | font: inherit; 68 | cursor: pointer; 69 | } 70 | 71 | .unbutton:focus { 72 | outline: none; 73 | } 74 | 75 | main { 76 | display: grid; 77 | grid-template-columns: 100%; 78 | grid-template-rows: 100vh; 79 | } 80 | 81 | .frame { 82 | grid-area: 1 / 1 / 2 / 2; 83 | padding: 1.5rem 2rem 10vh; 84 | text-align: center; 85 | position: relative; 86 | z-index: 100; 87 | pointer-events: none; 88 | } 89 | 90 | .frame a { 91 | pointer-events: auto; 92 | } 93 | 94 | .frame__title { 95 | margin: 0; 96 | font-size: 1rem; 97 | font-weight: 500; 98 | } 99 | 100 | .frame__links { 101 | margin: 0.5rem 0 2rem; 102 | } 103 | 104 | .frame__links a:not(:last-child) { 105 | margin-right: 1rem; 106 | } 107 | 108 | .button { 109 | color: var(--color-button); 110 | border-radius: 30px; 111 | min-width: 150px; 112 | padding: 1rem 2rem; 113 | border: 1px solid currentColor; 114 | } 115 | 116 | .button:hover, 117 | .button:focus-visible { 118 | color: var(--color-button-hover); 119 | } 120 | 121 | .frame--view-open .button-open { 122 | opacity: 0; 123 | pointer-events: none; 124 | } 125 | 126 | .view { 127 | position: relative; 128 | grid-area: 1 / 1 / 2 / 2; 129 | display: grid; 130 | place-items: center; 131 | } 132 | 133 | .view--2 { 134 | background: var(--color-bg-view-2); 135 | pointer-events: none; 136 | opacity: 0; 137 | } 138 | 139 | .view.view--open { 140 | pointer-events: auto; 141 | opacity: 1; 142 | } 143 | 144 | .overlay { 145 | grid-area: 1 / 1 / 2 / 2; 146 | position: relative; 147 | z-index: 1000; 148 | pointer-events: none; 149 | width: 100%; 150 | height: 100%; 151 | } 152 | 153 | @media screen and (min-width: 53em) { 154 | .frame { 155 | padding: 1.5rem 2rem 0; 156 | display: grid; 157 | grid-template-columns: auto 1fr auto; 158 | grid-template-areas: 'title links sponsor'; 159 | grid-gap: 3vw; 160 | justify-content: space-between; 161 | text-align: left; 162 | } 163 | .frame__links { 164 | margin: 0; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /022-svg-path-page-transition-horizontal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 022: SVG Path Page Transition (Horizontal) Demo | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 022: SVG Path Page Transition (Horizontal)

19 | 22 |
23 |
24 | 25 |
26 |
27 | 28 |
29 | 30 | 31 | 32 | 33 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /022-svg-path-page-transition-horizontal/js/index.js: -------------------------------------------------------------------------------- 1 | // frame element 2 | const frame = document.querySelector('.frame'); 3 | 4 | // overlay (SVG path element) 5 | const overlayPath = document.querySelector('.overlay__path'); 6 | 7 | // paths 8 | // edit here: https://yqnn.github.io/svg-path-editor/ 9 | const paths = { 10 | step1: { 11 | unfilled: 'M 0 0 h 0 c 0 50 0 50 0 100 H 0 V 0 Z', 12 | inBetween: 'M 0 0 h 33 c -30 54 113 65 0 100 H 0 V 0 Z', 13 | /* 14 | M 0 0 h 34 c 73 7 73 94 0 100 H 0 V 0 Z 15 | M 0 0 h 33 c -30 54 113 65 0 100 H 0 V 0 Z 16 | M 0 0 h 34 c 112 44 -32 49 0 100 H 0 V 0 Z 17 | */ 18 | filled: 'M 0 0 h 100 c 0 50 0 50 0 100 H 0 V 0 Z', 19 | }, 20 | step2: { 21 | filled: 'M 100 0 H 0 c 0 50 0 50 0 100 h 100 V 50 Z', 22 | //inBetween: 'M 100 0 H 50 c 20 33 20 67 0 100 h 50 V 0 Z', 23 | inBetween: 'M 100 0 H 50 c 28 43 4 81 0 100 h 50 V 0 Z', 24 | unfilled: 'M 100 0 H 100 c 0 50 0 50 0 100 h 0 V 0 Z', 25 | } 26 | }; 27 | 28 | // landing page/content element 29 | const landingEl = document.querySelector('.view--2'); 30 | 31 | // transition trigger button 32 | const switchCtrl = document.querySelector('button.button--open'); 33 | 34 | // back button 35 | const backCtrl = landingEl.querySelector('.button--close'); 36 | 37 | let isAnimating = false; 38 | 39 | let page = 1; 40 | 41 | const pageSwitchTimeline = gsap.timeline({ 42 | paused: true, 43 | onComplete: () => isAnimating = false 44 | }) 45 | .set(overlayPath, { 46 | attr: { d: paths.step1.unfilled } 47 | }) 48 | .to(overlayPath, { 49 | duration: 0.8, 50 | ease: 'power3.in', 51 | attr: { d: paths.step1.inBetween } 52 | }, 0) 53 | .to(overlayPath, { 54 | duration: 0.2, 55 | ease: 'power1', 56 | attr: { d: paths.step1.filled }, 57 | onComplete: () => switchPages() 58 | }) 59 | 60 | .set(overlayPath, { 61 | attr: { d: paths.step2.filled } 62 | }) 63 | 64 | .to(overlayPath, { 65 | duration: 0.15, 66 | ease: 'sine.in', 67 | attr: { d: paths.step2.inBetween } 68 | }) 69 | .to(overlayPath, { 70 | duration: 1, 71 | ease: 'power4', 72 | attr: { d: paths.step2.unfilled } 73 | }); 74 | 75 | const switchPages = () => { 76 | if ( page === 2 ) { 77 | frame.classList.add('frame--view-open'); 78 | landingEl.classList.add('view--open'); 79 | } 80 | else { 81 | frame.classList.remove('frame--view-open'); 82 | landingEl.classList.remove('view--open'); 83 | } 84 | } 85 | 86 | // reveals the second content view 87 | const reveal = () => { 88 | 89 | if ( isAnimating ) return; 90 | isAnimating = true; 91 | 92 | page = 2; 93 | 94 | pageSwitchTimeline.play(0); 95 | } 96 | 97 | // back to first content view 98 | const unreveal = () => { 99 | 100 | if ( isAnimating ) return; 101 | isAnimating = true; 102 | 103 | page = 1; 104 | 105 | pageSwitchTimeline.play(0); 106 | } 107 | 108 | // click on menu button 109 | switchCtrl.addEventListener('click', reveal); 110 | // click on close menu button 111 | backCtrl.addEventListener('click', unreveal); -------------------------------------------------------------------------------- /023-theme-picker/js/index.js: -------------------------------------------------------------------------------- 1 | const body = document.body; 2 | 3 | const selectInput = document.querySelector('#colorpicker'); 4 | 5 | const picker = document.querySelector('.picker'); 6 | 7 | const lines = { 8 | vertical: picker.querySelectorAll('.picker__item:nth-child(-n+16) i'), 9 | horizontal: picker.querySelectorAll('.picker__item:nth-child(16n+17) i') 10 | }; 11 | 12 | const cells = picker.querySelectorAll('.picker__item-inner'); 13 | 14 | let tl; 15 | 16 | const init = () => { 17 | 18 | gsap.set(lines.horizontal, { 19 | scaleX: 0, 20 | transformOrigin: '0% 50%' 21 | }); 22 | gsap.set(lines.vertical, { 23 | scaleY: 0, 24 | transformOrigin: '50% 0%' 25 | }); 26 | gsap.set(cells, { 27 | scale: 0 28 | }); 29 | 30 | tl = gsap.timeline({ 31 | paused: true, 32 | onStart: () => picker.classList.remove('hidden'), 33 | onReverseComplete: () => picker.classList.add('hidden'), 34 | defaults: { 35 | duration: 1.5, 36 | ease: 'power2.inOut' 37 | } 38 | }) 39 | .addLabel('start', 'start') 40 | .to(cells, { 41 | duration: 2.8, 42 | ease: 'power4', 43 | scale: 1, 44 | stagger: { each: 0.08, grid: 'auto', from: 'random' } 45 | }, 'start') 46 | .addLabel('lines', 'start+=0.2') 47 | .to(lines.horizontal, { 48 | scaleX: 1, 49 | stagger: { each: 0.02, grid: 'auto', from: 'random' } 50 | }, 'lines') 51 | .to(lines.vertical, { 52 | scaleY: 1, 53 | stagger: { each: 0.02, grid: 'auto', from: 'random' } 54 | }, 'lines'); 55 | 56 | }; 57 | 58 | const openPicker = () => { 59 | 60 | body.classList.add('picker-visible'); 61 | tl.timeScale(1).play(); 62 | 63 | }; 64 | 65 | const selectColor = cell => { 66 | 67 | selectInput.value = window.getComputedStyle(cell).backgroundImage; 68 | body.style.backgroundImage = selectInput.value; 69 | closePicker(); 70 | 71 | }; 72 | 73 | const closePicker = () => { 74 | 75 | body.classList.remove('picker-visible'); 76 | tl.timeScale(3).reverse(); 77 | 78 | }; 79 | 80 | selectInput.addEventListener('click', openPicker); 81 | 82 | cells.forEach(cell => { 83 | 84 | cell.addEventListener('click', () => { 85 | 86 | selectColor(cell); 87 | 88 | }); 89 | 90 | }); 91 | 92 | // Esc key 93 | document.onkeydown = evt => { 94 | 95 | evt = evt || window.event; 96 | var isEscape = false; 97 | 98 | if ('key' in evt) { 99 | isEscape = (evt.key === 'Escape' || evt.key === 'Esc'); 100 | } else { 101 | isEscape = (evt.keyCode === 27); 102 | } 103 | 104 | if ( isEscape && body.classList.contains('picker-visible') ) { 105 | closePicker(); 106 | } 107 | 108 | }; 109 | 110 | init(); -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #000; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #fff; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | overflow: hidden; 24 | min-height: 100vh; 25 | } 26 | 27 | /* Page Loader */ 28 | .js .loading::before, 29 | .js .loading::after { 30 | content: ''; 31 | position: fixed; 32 | z-index: 1000; 33 | } 34 | 35 | .js .loading::before { 36 | top: 0; 37 | left: 0; 38 | width: 100%; 39 | height: 100%; 40 | background: var(--color-bg); 41 | } 42 | 43 | .js .loading::after { 44 | top: 50%; 45 | left: 50%; 46 | width: 60px; 47 | height: 60px; 48 | margin: -30px 0 0 -30px; 49 | border-radius: 50%; 50 | opacity: 0.4; 51 | background: var(--color-link); 52 | animation: loaderAnim 0.7s linear infinite alternate forwards; 53 | 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5,0.5,1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | } 68 | 69 | a:hover { 70 | color: var(--color-link-hover); 71 | outline: none; 72 | } 73 | 74 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 75 | a:focus { 76 | /* Provide a fallback style for browsers 77 | that don't support :focus-visible */ 78 | outline: none; 79 | background: lightgrey; 80 | } 81 | 82 | a:focus:not(:focus-visible) { 83 | /* Remove the focus indicator on mouse-focus for browsers 84 | that do support :focus-visible */ 85 | background: transparent; 86 | } 87 | 88 | a:focus-visible { 89 | /* Draw a very noticeable focus style for 90 | keyboard-focus on browsers that do support 91 | :focus-visible */ 92 | outline: 2px solid #fff; 93 | background: transparent; 94 | } 95 | 96 | .unbutton { 97 | background: none; 98 | border: 0; 99 | padding: 0; 100 | margin: 0; 101 | font: inherit; 102 | cursor: pointer; 103 | } 104 | 105 | .unbutton:focus { 106 | outline: none; 107 | } 108 | 109 | .frame { 110 | z-index: 100; 111 | pointer-events: none; 112 | position: fixed; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: auto; 117 | padding: 1.5rem 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr auto; 120 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 121 | grid-column-gap: 3vw; 122 | grid-row-gap: 1rem; 123 | justify-content: space-between; 124 | align-content: space-between; 125 | text-align: left; 126 | } 127 | 128 | .frame a { 129 | pointer-events: auto; 130 | } 131 | 132 | .frame__title { 133 | margin: 0; 134 | font-size: 1rem; 135 | font-weight: 500; 136 | grid-area: title; 137 | } 138 | 139 | .frame__links { 140 | grid-area: links; 141 | } 142 | 143 | .frame__links a:not(:last-child) { 144 | margin-right: 1rem; 145 | } 146 | 147 | .frame__credits { 148 | grid-area: credits; 149 | } 150 | 151 | .grid { 152 | display: grid; 153 | grid-template-columns: repeat(3, 1fr); 154 | gap: 5vh; 155 | } 156 | 157 | .grid__item { 158 | height: 47.5vh; 159 | /* For an item height of 50vh we need to consider the grid gap and remove half of it from the item height. 160 | Like that we guarantee that the looping content starts seamlessly. If the gap would be 2vh, our item height would be 49vh */ 161 | background-size: cover; 162 | background-position: 50% 20%; 163 | } 164 | 165 | .grid__item:nth-child(3n-2) { 166 | border-radius: 0 2rem 2rem 0; 167 | } 168 | 169 | .grid__item:nth-child(3n) { 170 | border-radius: 2rem 0 0 2rem; 171 | } 172 | 173 | .grid__item:nth-child(3n-1) { 174 | border-radius: 2rem; 175 | } 176 | 177 | @media screen and (min-width: 53em) { 178 | .frame { 179 | height: 100vh; 180 | align-items: space-between; 181 | } 182 | } -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/1.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/2.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/3.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/4.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/5.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/024-infinite-loop-scrolling/img/6.jpg -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 024: Infinite Loop Scrolling | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 024: Infinite Loop Scrolling

19 | 23 | Photography by Tony Lewis Manzi 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /024-infinite-loop-scrolling/js/index.js: -------------------------------------------------------------------------------- 1 | const lenis = new Lenis({ 2 | smooth: true, 3 | infinite: true, 4 | }); 5 | 6 | function raf(time) { 7 | lenis.raf(time); 8 | requestAnimationFrame(raf); 9 | } 10 | 11 | requestAnimationFrame(raf); 12 | 13 | // repeat first six items by cloning them and appending them to the .grid 14 | const repeatItems = (parentEl, total = 0) => { 15 | const items = [...parentEl.children]; 16 | for (let i = 0; i <= total-1; ++i) { 17 | var cln = items[i].cloneNode(true); 18 | parentEl.appendChild(cln); 19 | } 20 | }; 21 | repeatItems(document.querySelector('.grid'), 6); 22 | 23 | imagesLoaded( document.querySelectorAll('.grid__item'), { background: true }, () => { 24 | document.body.classList.remove('loading'); 25 | }); -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #9f93b0; 14 | --color-bg: #1e1e2f; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #9f93b0; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | } 24 | 25 | /* Page Loader */ 26 | .js .loading::before, 27 | .js .loading::after { 28 | content: ''; 29 | position: fixed; 30 | z-index: 1000; 31 | } 32 | 33 | .js .loading::before { 34 | top: 0; 35 | left: 0; 36 | width: 100%; 37 | height: 100%; 38 | background: var(--color-bg); 39 | } 40 | 41 | .js .loading::after { 42 | top: 50%; 43 | left: 50%; 44 | width: 60px; 45 | height: 60px; 46 | margin: -30px 0 0 -30px; 47 | border-radius: 50%; 48 | opacity: 0.4; 49 | background: var(--color-link); 50 | animation: loaderAnim 0.7s linear infinite alternate forwards; 51 | 52 | } 53 | 54 | @keyframes loaderAnim { 55 | to { 56 | opacity: 1; 57 | transform: scale3d(0.5,0.5,1); 58 | } 59 | } 60 | 61 | a { 62 | text-decoration: none; 63 | color: var(--color-link); 64 | outline: none; 65 | } 66 | 67 | a:hover { 68 | color: var(--color-link-hover); 69 | outline: none; 70 | } 71 | 72 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 73 | a:focus { 74 | /* Provide a fallback style for browsers 75 | that don't support :focus-visible */ 76 | outline: none; 77 | background: lightgrey; 78 | } 79 | 80 | a:focus:not(:focus-visible) { 81 | /* Remove the focus indicator on mouse-focus for browsers 82 | that do support :focus-visible */ 83 | background: transparent; 84 | } 85 | 86 | a:focus-visible { 87 | /* Draw a very noticeable focus style for 88 | keyboard-focus on browsers that do support 89 | :focus-visible */ 90 | outline: 2px solid #fff; 91 | background: transparent; 92 | } 93 | 94 | .unbutton { 95 | background: none; 96 | border: 0; 97 | padding: 0; 98 | margin: 0; 99 | font: inherit; 100 | cursor: pointer; 101 | } 102 | 103 | .unbutton:focus { 104 | outline: none; 105 | } 106 | 107 | body, 108 | main { 109 | width: min-content; 110 | } 111 | 112 | .frame { 113 | z-index: 100; 114 | pointer-events: none; 115 | position: fixed; 116 | top: 0; 117 | left: 0; 118 | width: 100%; 119 | height: auto; 120 | padding: 1.5rem 2rem; 121 | display: grid; 122 | grid-template-columns: auto 1fr auto; 123 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 124 | grid-column-gap: 3vw; 125 | grid-row-gap: 1rem; 126 | justify-content: space-between; 127 | align-content: space-between; 128 | text-align: left; 129 | } 130 | 131 | .frame a { 132 | pointer-events: auto; 133 | } 134 | 135 | .frame__title { 136 | margin: 0; 137 | font-size: 1rem; 138 | font-weight: 500; 139 | grid-area: title; 140 | } 141 | 142 | .frame__links { 143 | grid-area: links; 144 | } 145 | 146 | .frame__links a:not(:last-child) { 147 | margin-right: 1rem; 148 | } 149 | 150 | .frame__credits { 151 | grid-area: credits; 152 | } 153 | 154 | .grid { 155 | height: 65vh; 156 | margin-top: 17.5vh; 157 | display: grid; 158 | grid-auto-columns: 23.5vw; /* 25vw - gap - 1/2*gap */ 159 | grid-auto-flow: column; 160 | width: min-content; 161 | gap: 2vw; 162 | } 163 | 164 | .grid__item { 165 | height: 100%; 166 | background-size: cover; 167 | background-position: 50% 50%; 168 | border-radius: 2rem; 169 | } 170 | 171 | @media screen and (min-width: 53em) { 172 | .frame { 173 | height: 100vh; 174 | align-items: space-between; 175 | } 176 | } -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/025-infinite-loop-scrolling-horizontal/img/1.jpg -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/025-infinite-loop-scrolling-horizontal/img/2.jpg -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/025-infinite-loop-scrolling-horizontal/img/3.jpg -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/025-infinite-loop-scrolling-horizontal/img/4.jpg -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 025: Infinite Loop Scrolling (Horizontal) | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 025: Infinite Loop Scrolling (Horizontal)

19 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /025-infinite-loop-scrolling-horizontal/js/index.js: -------------------------------------------------------------------------------- 1 | const lenis = new Lenis({ 2 | smooth: true, 3 | infinite: true, 4 | direction: 'horizontal', 5 | gestureDirection: 'both' 6 | }); 7 | 8 | function raf(time) { 9 | lenis.raf(time); 10 | requestAnimationFrame(raf); 11 | } 12 | 13 | requestAnimationFrame(raf); 14 | 15 | // repeat first four items by cloning them and appending them to the .grid 16 | const repeatItems = (parentEl, total = 0) => { 17 | const items = [...parentEl.children]; 18 | for (let i = 0; i <= total-1; ++i) { 19 | var cln = items[i].cloneNode(true); 20 | parentEl.appendChild(cln); 21 | } 22 | }; 23 | 24 | repeatItems(document.querySelector('.grid'), 4); 25 | 26 | imagesLoaded( document.querySelectorAll('.grid__item'), { background: true }, () => { 27 | document.body.classList.remove('loading'); 28 | }); -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #000; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #fff; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | 24 | min-height: 100vh; 25 | } 26 | 27 | /* Page Loader */ 28 | .js .loading::before, 29 | .js .loading::after { 30 | content: ''; 31 | position: fixed; 32 | z-index: 1000; 33 | } 34 | 35 | .js .loading::before { 36 | top: 0; 37 | left: 0; 38 | width: 100%; 39 | height: 100%; 40 | background: var(--color-bg); 41 | } 42 | 43 | .js .loading::after { 44 | top: 50%; 45 | left: 50%; 46 | width: 60px; 47 | height: 60px; 48 | margin: -30px 0 0 -30px; 49 | border-radius: 50%; 50 | opacity: 0.4; 51 | background: var(--color-link); 52 | animation: loaderAnim 0.7s linear infinite alternate forwards; 53 | 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5,0.5,1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | } 68 | 69 | a:hover { 70 | color: var(--color-link-hover); 71 | outline: none; 72 | } 73 | 74 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 75 | a:focus { 76 | /* Provide a fallback style for browsers 77 | that don't support :focus-visible */ 78 | outline: none; 79 | background: lightgrey; 80 | } 81 | 82 | a:focus:not(:focus-visible) { 83 | /* Remove the focus indicator on mouse-focus for browsers 84 | that do support :focus-visible */ 85 | background: transparent; 86 | } 87 | 88 | a:focus-visible { 89 | /* Draw a very noticeable focus style for 90 | keyboard-focus on browsers that do support 91 | :focus-visible */ 92 | outline: 2px solid #fff; 93 | background: transparent; 94 | } 95 | 96 | .unbutton { 97 | background: none; 98 | border: 0; 99 | padding: 0; 100 | margin: 0; 101 | font: inherit; 102 | cursor: pointer; 103 | } 104 | 105 | .unbutton:focus { 106 | outline: none; 107 | } 108 | 109 | .frame { 110 | z-index: 100; 111 | pointer-events: none; 112 | position: fixed; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: auto; 117 | padding: 1.5rem 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr auto; 120 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 121 | grid-column-gap: 3vw; 122 | grid-row-gap: 1rem; 123 | justify-content: space-between; 124 | align-content: space-between; 125 | text-align: left; 126 | } 127 | 128 | .frame a { 129 | pointer-events: auto; 130 | } 131 | 132 | .frame__title { 133 | margin: 0; 134 | font-size: 1rem; 135 | font-weight: 500; 136 | grid-area: title; 137 | } 138 | 139 | .frame__links { 140 | grid-area: links; 141 | } 142 | 143 | .frame__links a:not(:last-child) { 144 | margin-right: 1rem; 145 | } 146 | 147 | .frame__credits { 148 | grid-area: credits; 149 | } 150 | 151 | .grid { 152 | display: grid; 153 | grid-template-columns: repeat(3, 1fr); 154 | gap: 5vh; 155 | } 156 | 157 | .grid__item { 158 | height: 100vh; 159 | background-size: cover; 160 | background-position: 50% 50%; 161 | } 162 | 163 | @media screen and (min-width: 53em) { 164 | .frame { 165 | height: 100vh; 166 | align-items: space-between; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/1.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/2.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/3.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/4.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/5.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/026-infinite-loop-scrolling-animation/img/6.jpg -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 026: Infinite Loop Scrolling (Animation) | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 026: Infinite Loop (Animation)

19 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /026-infinite-loop-scrolling-animation/js/index.js: -------------------------------------------------------------------------------- 1 | gsap.registerPlugin(ScrollTrigger); 2 | 3 | // repeat first three items by cloning them and appending them to the .grid 4 | const repeatItems = (parentEl, total = 0) => { 5 | const items = [...parentEl.children]; 6 | for (let i = 0; i <= total-1; ++i) { 7 | var cln = items[i].cloneNode(true); 8 | parentEl.appendChild(cln); 9 | } 10 | }; 11 | 12 | const lenis = new Lenis({ 13 | smooth: true, 14 | infinite: true 15 | }); 16 | 17 | lenis.on('scroll',()=>{ 18 | ScrollTrigger.update() 19 | }) 20 | 21 | function raf(time) { 22 | lenis.raf(time); 23 | requestAnimationFrame(raf); 24 | } 25 | 26 | imagesLoaded( document.querySelectorAll('.grid__item'), { background: true }, () => { 27 | document.body.classList.remove('loading'); 28 | 29 | repeatItems(document.querySelector('.grid'), 3); 30 | 31 | // first three items 32 | [...document.querySelectorAll('.grid__item:nth-child(-n+3)')].forEach(el => { 33 | 34 | gsap.set(el, {transformOrigin: `0% 100%`}) 35 | gsap.to(el, { 36 | ease: 'none', 37 | startAt: {scale: 1}, 38 | scale: 0, 39 | scrollTrigger: { 40 | trigger: el, 41 | start: "center center", 42 | end: "bottom top", 43 | scrub: true, 44 | fastScrollEnd: true, 45 | onLeave: () => { 46 | gsap.set(el, {scale: 1}) 47 | }, 48 | } 49 | }); 50 | 51 | }); 52 | 53 | // last three items 54 | [...document.querySelectorAll('.grid__item:nth-last-child(-n+3)')].forEach(el => { 55 | 56 | gsap.set(el, {transformOrigin: `100% 0%`, scale: 0}) 57 | gsap.to(el, { 58 | ease: 'none', 59 | startAt: {scale: 0}, 60 | scale: 1, 61 | scrollTrigger: { 62 | trigger: el, 63 | start: "top bottom", 64 | end: "bottom top", 65 | scrub: true, 66 | fastScrollEnd: true, 67 | onLeaveBack: () => { 68 | gsap.set(el, {scale: 1}) 69 | } 70 | } 71 | }); 72 | 73 | }); 74 | 75 | // in between 76 | let ft; 77 | let st; 78 | [...document.querySelectorAll('.grid__item:nth-child(4), .grid__item:nth-child(5), .grid__item:nth-child(6)')].forEach(el => { 79 | 80 | ft = gsap.timeline() 81 | .to(el, { 82 | scrollTrigger: { 83 | trigger: el, 84 | start: 'top bottom', 85 | end: 'center center', 86 | scrub: true, 87 | onEnter: () => gsap.set(el, {transformOrigin: `100% 0%`}), 88 | onEnterBack: () => gsap.set(el, {transformOrigin: `100% 0%`}), 89 | onLeave: () => gsap.set(el, {transformOrigin: `0% 100%`}), 90 | onLeaveBack: () => gsap.set(el, {transformOrigin: `0% 100%`}), 91 | }, 92 | onStart: () => { 93 | if (st) st.kill() 94 | }, 95 | startAt: {scale: 0}, 96 | scale: 1, 97 | ease: 'none' 98 | }); 99 | 100 | st = gsap.timeline() 101 | .to(el, { 102 | scrollTrigger: { 103 | trigger: el, 104 | start: 'center center', 105 | end: 'bottom top', 106 | scrub: true, 107 | onEnter: () => gsap.set(el, {transformOrigin: `0% 100%`}), 108 | onEnterBack: () => gsap.set(el, {transformOrigin: `0% 100%`}), 109 | onLeave: () => gsap.set(el, {transformOrigin: `100% 0%`}), 110 | onLeaveBack: () => gsap.set(el, {transformOrigin: `100% 0%`}), 111 | }, 112 | onStart: () => { 113 | if (ft) ft.kill() 114 | }, 115 | startAt: {scale: 1}, 116 | scale: 0, 117 | ease: 'none' 118 | }); 119 | 120 | }); 121 | 122 | requestAnimationFrame(raf); 123 | 124 | const refresh = () => { 125 | ScrollTrigger.clearScrollMemory(); 126 | window.history.scrollRestoration = 'manual'; 127 | ScrollTrigger.refresh(true); 128 | } 129 | 130 | refresh(); 131 | window.addEventListener('resize', refresh); 132 | }); -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #000; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #fff; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | 24 | min-height: 100vh; 25 | } 26 | 27 | /* Page Loader */ 28 | .js .loading::before, 29 | .js .loading::after { 30 | content: ''; 31 | position: fixed; 32 | z-index: 1000; 33 | } 34 | 35 | .js .loading::before { 36 | top: 0; 37 | left: 0; 38 | width: 100%; 39 | height: 100%; 40 | background: var(--color-bg); 41 | } 42 | 43 | .js .loading::after { 44 | top: 50%; 45 | left: 50%; 46 | width: 60px; 47 | height: 60px; 48 | margin: -30px 0 0 -30px; 49 | border-radius: 50%; 50 | opacity: 0.4; 51 | background: var(--color-link); 52 | animation: loaderAnim 0.7s linear infinite alternate forwards; 53 | 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5,0.5,1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | } 68 | 69 | a:hover { 70 | color: var(--color-link-hover); 71 | outline: none; 72 | } 73 | 74 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 75 | a:focus { 76 | /* Provide a fallback style for browsers 77 | that don't support :focus-visible */ 78 | outline: none; 79 | background: lightgrey; 80 | } 81 | 82 | a:focus:not(:focus-visible) { 83 | /* Remove the focus indicator on mouse-focus for browsers 84 | that do support :focus-visible */ 85 | background: transparent; 86 | } 87 | 88 | a:focus-visible { 89 | /* Draw a very noticeable focus style for 90 | keyboard-focus on browsers that do support 91 | :focus-visible */ 92 | outline: 2px solid #fff; 93 | background: transparent; 94 | } 95 | 96 | .unbutton { 97 | background: none; 98 | border: 0; 99 | padding: 0; 100 | margin: 0; 101 | font: inherit; 102 | cursor: pointer; 103 | } 104 | 105 | .unbutton:focus { 106 | outline: none; 107 | } 108 | 109 | .frame { 110 | z-index: 100; 111 | pointer-events: none; 112 | position: fixed; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: auto; 117 | padding: 1.5rem 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr auto; 120 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 121 | grid-column-gap: 3vw; 122 | grid-row-gap: 1rem; 123 | justify-content: space-between; 124 | align-content: space-between; 125 | text-align: left; 126 | } 127 | 128 | .frame a { 129 | pointer-events: auto; 130 | } 131 | 132 | .frame__title { 133 | margin: 0; 134 | font-size: 1rem; 135 | font-weight: 500; 136 | grid-area: title; 137 | } 138 | 139 | .frame__links { 140 | grid-area: links; 141 | } 142 | 143 | .frame__links a:not(:last-child) { 144 | margin-right: 1rem; 145 | } 146 | 147 | .frame__credits { 148 | grid-area: credits; 149 | } 150 | 151 | .grid { 152 | display: grid; 153 | grid-template-columns: repeat(3, 1fr); 154 | gap: 5vh; 155 | } 156 | 157 | .grid__item { 158 | height: 100vh; 159 | background-size: cover; 160 | background-position: 50% 50%; 161 | } 162 | 163 | @media screen and (min-width: 53em) { 164 | .frame { 165 | height: 100vh; 166 | align-items: space-between; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/1.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/2.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/3.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/4.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/5.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/027-infinite-loop-scrolling-animation-2/img/6.jpg -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 027: Infinite Loop Scrolling (scaleY and opacity) | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 027: Infinite Loop (scaleY and opacity)

19 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /027-infinite-loop-scrolling-animation-2/js/index.js: -------------------------------------------------------------------------------- 1 | gsap.registerPlugin(ScrollTrigger); 2 | 3 | // repeat first three items by cloning them and appending them to the .grid 4 | const repeatItems = (parentEl, total = 0) => { 5 | const items = [...parentEl.children]; 6 | for (let i = 0; i <= total-1; ++i) { 7 | var cln = items[i].cloneNode(true); 8 | parentEl.appendChild(cln); 9 | } 10 | }; 11 | 12 | const lenis = new Lenis({ 13 | smooth: true, 14 | infinite: true 15 | }); 16 | 17 | lenis.on('scroll',()=>{ 18 | ScrollTrigger.update() 19 | }) 20 | 21 | function raf(time) { 22 | lenis.raf(time); 23 | requestAnimationFrame(raf); 24 | } 25 | 26 | imagesLoaded( document.querySelectorAll('.grid__item'), { background: true }, () => { 27 | document.body.classList.remove('loading'); 28 | 29 | repeatItems(document.querySelector('.grid'), 3); 30 | 31 | // first three items 32 | [...document.querySelectorAll('.grid__item:nth-child(-n+3)')].forEach(el => { 33 | 34 | gsap.set(el, {transformOrigin: '50% 100%'}) 35 | gsap.to(el, { 36 | ease: 'none', 37 | startAt: {scaleY: 1, opacity: 1}, 38 | scaleY: 0, 39 | opacity: 0, 40 | scrollTrigger: { 41 | trigger: el, 42 | start: 'center center', 43 | end: 'bottom top', 44 | scrub: true, 45 | fastScrollEnd: true, 46 | onLeave: () => { 47 | gsap.set(el, {scaleY: 1, opacity: 1}) 48 | }, 49 | } 50 | }); 51 | 52 | }); 53 | 54 | // last three items 55 | [...document.querySelectorAll('.grid__item:nth-last-child(-n+3)')].forEach(el => { 56 | 57 | gsap.set(el, {transformOrigin: '50% 0%', scaleY: 0}) 58 | gsap.to(el, { 59 | ease: 'none', 60 | startAt: {scaleY: 0, opacity: 0}, 61 | scaleY: 1, 62 | opacity: 1, 63 | scrollTrigger: { 64 | trigger: el, 65 | start: 'top bottom', 66 | end: 'bottom top', 67 | scrub: true, 68 | fastScrollEnd: true, 69 | onLeaveBack: () => { 70 | gsap.set(el, {scaleY: 1, opacity: 1}) 71 | } 72 | } 73 | }); 74 | 75 | }); 76 | 77 | // in between 78 | let ft; 79 | let st; 80 | [...document.querySelectorAll('.grid__item:nth-child(4), .grid__item:nth-child(5), .grid__item:nth-child(6)')].forEach(el => { 81 | 82 | ft = gsap.timeline() 83 | .to(el, { 84 | ease: 'none', 85 | onStart: () => { 86 | if (st) st.kill() 87 | }, 88 | startAt: {scaleY: 0, opacity: 0}, 89 | scaleY: 1, 90 | opacity: 1, 91 | scrollTrigger: { 92 | trigger: el, 93 | start: 'top bottom', 94 | end: 'center center', 95 | scrub: true, 96 | onEnter: () => gsap.set(el, {transformOrigin: '50% 0%'}), 97 | onEnterBack: () => gsap.set(el, {transformOrigin: '50% 0%'}), 98 | onLeave: () => gsap.set(el, {transformOrigin: '50% 100%'}), 99 | onLeaveBack: () => gsap.set(el, {transformOrigin: '50% 100%'}), 100 | }, 101 | }); 102 | 103 | st = gsap.timeline() 104 | .to(el, { 105 | ease: 'none', 106 | onStart: () => { 107 | if (ft) ft.kill() 108 | }, 109 | startAt: {scaleY: 1, opacity: 1}, 110 | scaleY: 0, 111 | opacity: 0, 112 | scrollTrigger: { 113 | trigger: el, 114 | start: 'center center', 115 | end: 'bottom top', 116 | scrub: true, 117 | onEnter: () => gsap.set(el, {transformOrigin: '50% 100%'}), 118 | onEnterBack: () => gsap.set(el, {transformOrigin: '50% 100%'}), 119 | onLeave: () => gsap.set(el, {transformOrigin: '50% 0%'}), 120 | onLeaveBack: () => gsap.set(el, {transformOrigin: '50% 0%'}), 121 | }, 122 | }); 123 | 124 | }); 125 | 126 | requestAnimationFrame(raf); 127 | 128 | const refresh = () => { 129 | ScrollTrigger.clearScrollMemory(); 130 | window.history.scrollRestoration = 'manual'; 131 | ScrollTrigger.refresh(true); 132 | } 133 | 134 | refresh(); 135 | window.addEventListener('resize', refresh); 136 | }); -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #000; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #fff; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | 24 | min-height: 100vh; 25 | } 26 | 27 | /* Page Loader */ 28 | .js .loading::before, 29 | .js .loading::after { 30 | content: ''; 31 | position: fixed; 32 | z-index: 1000; 33 | } 34 | 35 | .js .loading::before { 36 | top: 0; 37 | left: 0; 38 | width: 100%; 39 | height: 100%; 40 | background: var(--color-bg); 41 | } 42 | 43 | .js .loading::after { 44 | top: 50%; 45 | left: 50%; 46 | width: 60px; 47 | height: 60px; 48 | margin: -30px 0 0 -30px; 49 | border-radius: 50%; 50 | opacity: 0.4; 51 | background: var(--color-link); 52 | animation: loaderAnim 0.7s linear infinite alternate forwards; 53 | 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5,0.5,1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | } 68 | 69 | a:hover { 70 | color: var(--color-link-hover); 71 | outline: none; 72 | } 73 | 74 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 75 | a:focus { 76 | /* Provide a fallback style for browsers 77 | that don't support :focus-visible */ 78 | outline: none; 79 | background: lightgrey; 80 | } 81 | 82 | a:focus:not(:focus-visible) { 83 | /* Remove the focus indicator on mouse-focus for browsers 84 | that do support :focus-visible */ 85 | background: transparent; 86 | } 87 | 88 | a:focus-visible { 89 | /* Draw a very noticeable focus style for 90 | keyboard-focus on browsers that do support 91 | :focus-visible */ 92 | outline: 2px solid #fff; 93 | background: transparent; 94 | } 95 | 96 | .unbutton { 97 | background: none; 98 | border: 0; 99 | padding: 0; 100 | margin: 0; 101 | font: inherit; 102 | cursor: pointer; 103 | } 104 | 105 | .unbutton:focus { 106 | outline: none; 107 | } 108 | 109 | .frame { 110 | z-index: 100; 111 | pointer-events: none; 112 | position: fixed; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: auto; 117 | padding: 1.5rem 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr auto; 120 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 121 | grid-column-gap: 3vw; 122 | grid-row-gap: 1rem; 123 | justify-content: space-between; 124 | align-content: space-between; 125 | text-align: left; 126 | } 127 | 128 | .frame a { 129 | pointer-events: auto; 130 | } 131 | 132 | .frame__title { 133 | margin: 0; 134 | font-size: 1rem; 135 | font-weight: 500; 136 | grid-area: title; 137 | } 138 | 139 | .frame__links { 140 | grid-area: links; 141 | } 142 | 143 | .frame__links a:not(:last-child) { 144 | margin-right: 1rem; 145 | } 146 | 147 | .frame__credits { 148 | grid-area: credits; 149 | } 150 | 151 | .grid { 152 | display: grid; 153 | grid-template-columns: repeat(3, 1fr); 154 | gap: 5vh; 155 | } 156 | 157 | .grid__item { 158 | height: 100vh; 159 | background-size: cover; 160 | background-position: 50% 50%; 161 | } 162 | -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/1.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/2.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/3.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/4.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/5.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/028-infinite-loop-scrolling-animation-3/img/6.jpg -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 028: Infinite Loop Scrolling (scaleX and scaleY) | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 028: Infinite Loop (scaleX and scaleY)

19 | 23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /028-infinite-loop-scrolling-animation-3/js/index.js: -------------------------------------------------------------------------------- 1 | gsap.registerPlugin(ScrollTrigger); 2 | 3 | // repeat first three items by cloning them and appending them to the .grid 4 | const repeatItems = (parentEl, total = 0) => { 5 | const items = [...parentEl.children]; 6 | for (let i = 0; i <= total-1; ++i) { 7 | var cln = items[i].cloneNode(true); 8 | parentEl.appendChild(cln); 9 | } 10 | }; 11 | 12 | const lenis = new Lenis({ 13 | smooth: true, 14 | infinite: true 15 | }); 16 | 17 | lenis.on('scroll',()=>{ 18 | ScrollTrigger.update() 19 | }) 20 | 21 | function raf(time) { 22 | lenis.raf(time); 23 | requestAnimationFrame(raf); 24 | } 25 | 26 | imagesLoaded( document.querySelectorAll('.grid__item'), { background: true }, () => { 27 | document.body.classList.remove('loading'); 28 | 29 | repeatItems(document.querySelector('.grid'), 3); 30 | 31 | // first three items 32 | [...document.querySelectorAll('.grid__item:nth-child(-n+3)')].forEach(el => { 33 | 34 | gsap.set(el, {transformOrigin: '50% 100%'}) 35 | gsap.to(el, { 36 | ease: 'none', 37 | startAt: {scaleY: 1, scaleX: .8}, 38 | scaleY: 0, 39 | scaleX: 1, 40 | scrollTrigger: { 41 | trigger: el, 42 | start: 'center center', 43 | end: 'bottom top', 44 | scrub: true, 45 | fastScrollEnd: true, 46 | onLeave: () => { 47 | gsap.set(el, {scaleY: 1, scaleX: .8}) 48 | } 49 | } 50 | }); 51 | 52 | }); 53 | 54 | // last three items 55 | [...document.querySelectorAll('.grid__item:nth-last-child(-n+3)')].forEach(el => { 56 | 57 | gsap.set(el, {transformOrigin: '50% 0%', scaleY: 0}) 58 | gsap.to(el, { 59 | ease: 'none', 60 | startAt: {scaleY: 0, scaleX: 1}, 61 | scaleY: 1, 62 | scaleX: .8, 63 | scrollTrigger: { 64 | trigger: el, 65 | start: 'top bottom', 66 | end: 'bottom top', 67 | scrub: true, 68 | fastScrollEnd: true, 69 | onLeaveBack: () => { 70 | gsap.set(el, {scaleY: 1, scaleX: .8}) 71 | } 72 | } 73 | }); 74 | 75 | }); 76 | 77 | // in between 78 | let ft; 79 | let st; 80 | [...document.querySelectorAll('.grid__item:nth-child(4), .grid__item:nth-child(5), .grid__item:nth-child(6)')].forEach(el => { 81 | 82 | ft = gsap.timeline() 83 | .to(el, { 84 | ease: 'none', 85 | onStart: () => { 86 | if (st) st.kill() 87 | }, 88 | startAt: {scaleY: 0, scaleX: 1}, 89 | scaleY: 1, 90 | scaleX: .8, 91 | scrollTrigger: { 92 | trigger: el, 93 | start: 'top bottom', 94 | end: 'center center', 95 | scrub: true, 96 | onEnter: () => gsap.set(el, {transformOrigin: '50% 0%'}), 97 | onEnterBack: () => gsap.set(el, {transformOrigin: '50% 0%'}), 98 | onLeave: () => gsap.set(el, {transformOrigin: '50% 100%'}), 99 | onLeaveBack: () => gsap.set(el, {transformOrigin: '50% 100%'}), 100 | }, 101 | }); 102 | 103 | st = gsap.timeline() 104 | .to(el, { 105 | ease: 'none', 106 | onStart: () => { 107 | if (ft) ft.kill() 108 | }, 109 | startAt: {scaleY: 1, scaleX: .8}, 110 | scaleY: 0, 111 | scaleX: 1, 112 | scrollTrigger: { 113 | trigger: el, 114 | start: 'center center', 115 | end: 'bottom top', 116 | scrub: true, 117 | onEnter: () => gsap.set(el, {transformOrigin: '50% 100%'}), 118 | onEnterBack: () => gsap.set(el, {transformOrigin: '50% 100%'}), 119 | onLeave: () => gsap.set(el, {transformOrigin: '50% 0%'}), 120 | onLeaveBack: () => gsap.set(el, {transformOrigin: '50% 0%'}), 121 | } 122 | }); 123 | 124 | }); 125 | 126 | requestAnimationFrame(raf); 127 | 128 | const refresh = () => { 129 | ScrollTrigger.clearScrollMemory(); 130 | window.history.scrollRestoration = 'manual'; 131 | ScrollTrigger.refresh(true); 132 | } 133 | 134 | refresh(); 135 | window.addEventListener('resize', refresh); 136 | }); -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/css/base.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::after, 3 | *::before { 4 | box-sizing: border-box; 5 | } 6 | 7 | :root { 8 | font-size: 15px; 9 | } 10 | 11 | body { 12 | margin: 0; 13 | --color-text: #fff; 14 | --color-bg: #000; 15 | --color-link: rgba(255,255,255,0.7); 16 | --color-link-hover: #fff; 17 | color: var(--color-text); 18 | background-color: var(--color-bg); 19 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif; 20 | font-weight: 500; 21 | -webkit-font-smoothing: antialiased; 22 | -moz-osx-font-smoothing: grayscale; 23 | 24 | min-height: 100vh; 25 | } 26 | 27 | /* Page Loader */ 28 | .js .loading::before, 29 | .js .loading::after { 30 | content: ''; 31 | position: fixed; 32 | z-index: 1000; 33 | } 34 | 35 | .js .loading::before { 36 | top: 0; 37 | left: 0; 38 | width: 100%; 39 | height: 100%; 40 | background: var(--color-bg); 41 | } 42 | 43 | .js .loading::after { 44 | top: 50%; 45 | left: 50%; 46 | width: 60px; 47 | height: 60px; 48 | margin: -30px 0 0 -30px; 49 | border-radius: 50%; 50 | opacity: 0.4; 51 | background: var(--color-link); 52 | animation: loaderAnim 0.7s linear infinite alternate forwards; 53 | 54 | } 55 | 56 | @keyframes loaderAnim { 57 | to { 58 | opacity: 1; 59 | transform: scale3d(0.5,0.5,1); 60 | } 61 | } 62 | 63 | a { 64 | text-decoration: none; 65 | color: var(--color-link); 66 | outline: none; 67 | } 68 | 69 | a:hover { 70 | color: var(--color-link-hover); 71 | outline: none; 72 | } 73 | 74 | /* Better focus styles from https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible */ 75 | a:focus { 76 | /* Provide a fallback style for browsers 77 | that don't support :focus-visible */ 78 | outline: none; 79 | background: lightgrey; 80 | } 81 | 82 | a:focus:not(:focus-visible) { 83 | /* Remove the focus indicator on mouse-focus for browsers 84 | that do support :focus-visible */ 85 | background: transparent; 86 | } 87 | 88 | a:focus-visible { 89 | /* Draw a very noticeable focus style for 90 | keyboard-focus on browsers that do support 91 | :focus-visible */ 92 | outline: 2px solid #fff; 93 | background: transparent; 94 | } 95 | 96 | .unbutton { 97 | background: none; 98 | border: 0; 99 | padding: 0; 100 | margin: 0; 101 | font: inherit; 102 | cursor: pointer; 103 | } 104 | 105 | .unbutton:focus { 106 | outline: none; 107 | } 108 | 109 | .frame { 110 | z-index: 100; 111 | pointer-events: none; 112 | position: fixed; 113 | top: 0; 114 | left: 0; 115 | width: 100%; 116 | height: auto; 117 | padding: 1.5rem 2rem; 118 | display: grid; 119 | grid-template-columns: auto 1fr auto; 120 | grid-template-areas: 'title links sponsor' 'credits credits credits'; 121 | grid-column-gap: 3vw; 122 | grid-row-gap: 1rem; 123 | justify-content: space-between; 124 | align-content: space-between; 125 | text-align: left; 126 | } 127 | 128 | .frame a { 129 | pointer-events: auto; 130 | } 131 | 132 | .frame__title { 133 | margin: 0; 134 | font-size: 1rem; 135 | font-weight: 500; 136 | grid-area: title; 137 | } 138 | 139 | .frame__links { 140 | grid-area: links; 141 | } 142 | 143 | .frame__links a:not(:last-child) { 144 | margin-right: 1rem; 145 | } 146 | 147 | .frame__credits { 148 | grid-area: credits; 149 | } 150 | 151 | .grid { 152 | display: grid; 153 | grid-template-columns: repeat(3, 1fr); 154 | gap: 5vh; 155 | } 156 | 157 | .grid__item { 158 | height: 100vh; 159 | background-size: cover; 160 | background-position: 50% 50%; 161 | } 162 | 163 | @media screen and (min-width: 53em) { 164 | .frame { 165 | height: 100vh; 166 | align-items: space-between; 167 | } 168 | } -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/1.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/2.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/3.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/4.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/5.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/img/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/029-infinite-loop-scrolling-animation-4/img/6.jpg -------------------------------------------------------------------------------- /029-infinite-loop-scrolling-animation-4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Sketch 029: Infinite Loop Scrolling (3D) | Codrops 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Sketch 029: Infinite Loop (3D)

19 | 23 | Photography by Igor Rand 24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Codrops 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Codrops Sketches 2 | A collection of demo variations, ideas, raw concepts & experiments. 3 | 4 | ## Demos 5 |
6 | 2022 7 | 8 | - [Sketch 001: Repetition Hover Effect (Round)](https://tympanus.net/Sketches/001-repetition-hover-effect-round/) 9 | - [Sketch 002: Repetition Hover Effect (Square)](https://tympanus.net/Sketches/002-repetition-hover-effect-square/) 10 | - [Sketch 003: Repetition Hover Effect (Rotated)](https://tympanus.net/Sketches/003-repetition-hover-effect-rotated/) 11 | - [Sketch 004: Repetition Hover Effect (Filter)](https://tympanus.net/Sketches/004-repetition-hover-effect-filter/) 12 | - [Sketch 005: Image Motion Trail (Opaque)](https://tympanus.net/Sketches/005-image-motion-trail-opaque/) 13 | - [Sketch 006: Image Motion Trail (Semi-transparent)](https://tympanus.net/Sketches/006-image-motion-trail-semitransparent/) 14 | - [Sketch 007: Image Motion Trail (Rotation)](https://tympanus.net/Sketches/007-image-motion-trail-rotation/) 15 | - [Sketch 008: Image Motion Trail (Circle)](https://tympanus.net/Sketches/008-image-motion-trail-circle/) 16 | - [Sketch 009: Image Motion Trail (Perspective)](https://tympanus.net/Sketches/009-image-motion-trail-perspective/) 17 | - [Sketch 010: Image Motion Trail (Perspective)](https://tympanus.net/Sketches/010-image-motion-trail-perspective/) 18 | - [Sketch 011: Custom Cursor (filled circle)](https://tympanus.net/Sketches/011-custom-cursor-filled-circle/) 19 | - [Sketch 012: Custom Cursor (two circles, one filled)](https://tympanus.net/Sketches/012-custom-cursor-two-circles/) 20 | - [Sketch 013: Custom Cursor (two circles with filter effect)](https://tympanus.net/Sketches/013-custom-cursor-filter/) 21 | - [Sketch 014: Custom Cursor (filter effect and delayed motion)](https://tympanus.net/Sketches/014-custom-cursor-filter-2/) 22 | - [Sketch 015: Custom Cursor (multiple circles with filter effect) ](https://tympanus.net/Sketches/015-custom-cursor-filter-3/) 23 | - [Sketch 016: Custom Cursor (filled circle with filter effect)](https://tympanus.net/Sketches/016-custom-cursor-filter-4/) 24 | - [Sketch 017: Custom Cursor (stroke circle with filter effect)](https://tympanus.net/Sketches/017-custom-cursor-filter-5/) 25 | - [Sketch 018: Custom Cursor (two circles with filter and delays)](https://tympanus.net/Sketches/018-custom-cursor-filter-6/) 26 | - [Sketch 019: Image Motion Effect with SVG Filter](https://tympanus.net/Sketches/019-image-motion-svg-filter/) 27 | - [Sketch 020: Image Motion Effect with SVG Filter](https://tympanus.net/Sketches/020-image-motion-svg-filter-2/) 28 | - [Sketch 021: SVG Path Page Transition (Vertical)](https://tympanus.net/Sketches/021-svg-path-page-transition-vertical/) 29 | - [Sketch 022: SVG Path Page Transition (Horizontal)](https://tympanus.net/Sketches/022-svg-path-page-transition-horizontal/) 30 | - [Sketch 023: Background/Theme Picker](https://tympanus.net/Sketches/23-theme-picker/) 31 |
32 | 33 |
34 | 2023 35 | 36 | - [Sketch 024: Infinite Loop Scrolling](https://tympanus.net/Sketches/024-infinite-loop-scrolling/) 37 | - [Sketch 025: Infinite Loop Scrolling (Horizontal)](https://tympanus.net/Sketches/025-infinite-loop-scrolling-horizontal/) 38 | - [Sketch 026: Infinite Loop Scrolling (Animation)](https://tympanus.net/Sketches/026-infinite-loop-scrolling-animation/) 39 | - [Sketch 027: Infinite Loop Scrolling (ScaleY and Opacity)](https://tympanus.net/Sketches/027-infinite-loop-scrolling-animation-2/) 40 | - [Sketch 028: Infinite Loop Scrolling (ScaleX and ScaleY)](https://tympanus.net/Sketches/028-infinite-loop-scrolling-animation-3/) 41 | - [Sketch 029: Infinite Loop Scrolling (3D)](https://tympanus.net/Sketches/029-infinite-loop-scrolling-animation-4/) 42 |
43 | 44 | 45 | ## Credits 46 | 47 | - Images from [Unsplash](https://unsplash.com/) 48 | 49 | ## Misc 50 | 51 | Follow Codrops: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [GitHub](https://github.com/codrops), [Instagram](https://www.instagram.com/codropsss/) 52 | 53 | ## License 54 | [MIT](LICENSE) 55 | 56 | Made with :blue_heart: by [Codrops](http://www.codrops.com) 57 | -------------------------------------------------------------------------------- /favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codrops/codrops-sketches/bbf47ca34766fd2ca5f97d8b376d2eca148bf48f/favicon.ico --------------------------------------------------------------------------------