├── .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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
33 |
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 |
39 |
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 |
39 |
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 |
39 |
42 |
45 |
48 |
51 |
54 |
57 |
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 |
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 |
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 |
39 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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
--------------------------------------------------------------------------------