├── README.md
├── style.css
├── index.html
├── LICENSE
└── app.js
/README.md:
--------------------------------------------------------------------------------
1 | # HEART-ANIMATION-
2 | Html CSS javascript
3 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #000;
3 | margin: 0;
4 | overflow: hidden;
5 | background-repeat: no-repeat;
6 | }
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Heart Animation
8 |
9 |
10 |
11 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Dzarel Developer
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 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | var canvas = document.getElementById("canvas");
2 |
3 | canvas.width = window.innerWidth;
4 | canvas.height = window.innerHeight;
5 |
6 | var gl = canvas.getContext('webgl');
7 | if(!gl){
8 | console.error("Unable to initialize WebGL.");
9 | }
10 |
11 | var time = 0.0;
12 |
13 | var vertexSource = `
14 | attribute vec2 position;
15 | void main() {
16 | gl_Position = vec4(position, 0.0, 1.0);
17 | }
18 | `;
19 |
20 | var fragmentSource = `
21 | precision highp float;
22 |
23 | uniform float width;
24 | uniform float height;
25 | vec2 resolution = vec2(width, height);
26 |
27 | uniform float time;
28 |
29 | #define POINT_COUNT 8
30 |
31 | vec2 points[POINT_COUNT];
32 | const float speed = -0.5;
33 | const float len = 0.25;
34 | float intensity = 1.3;
35 | float radius = 0.008;
36 |
37 | float sdBezier(vec2 pos, vec2 A, vec2 B, vec2 C){
38 | vec2 a = B - A;
39 | vec2 b = A - 2.0*B + C;
40 | vec2 c = a * 2.0;
41 | vec2 d = A - pos;
42 |
43 | float kk = 1.0 / dot(b,b);
44 | float kx = kk * dot(a,b);
45 | float ky = kk * (2.0*dot(a,a)+dot(d,b)) / 3.0;
46 | float kz = kk * dot(d,a);
47 |
48 | float res = 0.0;
49 |
50 | float p = ky - kx*kx;
51 | float p3 = p*p*p;
52 | float q = kx*(2.0*kx*kx - 3.0*ky) + kz;
53 | float h = q*q + 4.0*p3;
54 |
55 | if(h >= 0.0){
56 | h = sqrt(h);
57 | vec2 x = (vec2(h, -h) - q) / 2.0;
58 | vec2 uv = sign(x)*pow(abs(x), vec2(1.0/3.0));
59 | float t = uv.x + uv.y - kx;
60 | t = clamp( t, 0.0, 1.0 );
61 |
62 | vec2 qos = d + (c + b*t)*t;
63 | res = length(qos);
64 | }else{
65 | float z = sqrt(-p);
66 | float v = acos( q/(p*z*2.0) ) / 3.0;
67 | float m = cos(v);
68 | float n = sin(v)*1.732050808;
69 | vec3 t = vec3(m + m, -n - m, n - m) * z - kx;
70 | t = clamp( t, 0.0, 1.0 );
71 |
72 | vec2 qos = d + (c + b*t.x)*t.x;
73 | float dis = dot(qos,qos);
74 |
75 | res = dis;
76 |
77 | qos = d + (c + b*t.y)*t.y;
78 | dis = dot(qos,qos);
79 | res = min(res,dis);
80 |
81 | qos = d + (c + b*t.z)*t.z;
82 | dis = dot(qos,qos);
83 | res = min(res,dis);
84 |
85 | res = sqrt( res );
86 | }
87 |
88 | return res;
89 | }
90 |
91 |
92 | vec2 getHeartPosition(float t){
93 | return vec2(16.0 * sin(t) * sin(t) * sin(t),
94 | -(13.0 * cos(t) - 5.0 * cos(2.0*t)
95 | - 2.0 * cos(3.0*t) - cos(4.0*t)));
96 | }
97 |
98 | float getGlow(float dist, float radius, float intensity){
99 | return pow(radius/dist, intensity);
100 | }
101 |
102 | float getSegment(float t, vec2 pos, float offset, float scale){
103 | for(int i = 0; i < POINT_COUNT; i++){
104 | points[i] = getHeartPosition(offset + float(i)*len + fract(speed * t) * 6.28);
105 | }
106 |
107 | vec2 c = (points[0] + points[1]) / 2.0;
108 | vec2 c_prev;
109 | float dist = 10000.0;
110 |
111 | for(int i = 0; i < POINT_COUNT-1; i++){
112 | c_prev = c;
113 | c = (points[i] + points[i+1]) / 2.0;
114 | dist = min(dist, sdBezier(pos, scale * c_prev, scale * points[i], scale * c));
115 | }
116 | return max(0.0, dist);
117 | }
118 |
119 | void main(){
120 | vec2 uv = gl_FragCoord.xy/resolution.xy;
121 | float widthHeightRatio = resolution.x/resolution.y;
122 | vec2 centre = vec2(0.5, 0.5);
123 | vec2 pos = centre - uv;
124 | pos.y /= widthHeightRatio;
125 | pos.y += 0.02;
126 | float scale = 0.000015 * height;
127 |
128 | float t = time;
129 |
130 | float dist = getSegment(t, pos, 0.0, scale);
131 | float glow = getGlow(dist, radius, intensity);
132 |
133 | vec3 col = vec3(0.0);
134 |
135 | col += 10.0*vec3(smoothstep(0.003, 0.001, dist));
136 | col += glow * vec3(1.0,0.05,0.3);
137 |
138 | dist = getSegment(t, pos, 3.4, scale);
139 | glow = getGlow(dist, radius, intensity);
140 |
141 | col += 10.0*vec3(smoothstep(0.003, 0.001, dist));
142 | col += glow * vec3(0.1,0.4,1.0);
143 |
144 | col = 1.0 - exp(-col);
145 |
146 | col = pow(col, vec3(0.4545));
147 |
148 | gl_FragColor = vec4(col,1.0);
149 | }
150 | `;
151 |
152 |
153 | window.addEventListener('resize', onWindowResize, false);
154 |
155 | function onWindowResize(){
156 | canvas.width = window.innerWidth;
157 | canvas.height = window.innerHeight;
158 | gl.viewport(0, 0, canvas.width, canvas.height);
159 | gl.uniform1f(widthHandle, window.innerWidth);
160 | gl.uniform1f(heightHandle, window.innerHeight);
161 | }
162 |
163 |
164 | function compileShader(shaderSource, shaderType){
165 | var shader = gl.createShader(shaderType);
166 | gl.shaderSource(shader, shaderSource);
167 | gl.compileShader(shader);
168 | if(!gl.getShaderParameter(shader, gl.COMPILE_STATUS)){
169 | throw "Shader compile failed with: " + gl.getShaderInfoLog(shader);
170 | }
171 | return shader;
172 | }
173 |
174 | function getAttribLocation(program, name) {
175 | var attributeLocation = gl.getAttribLocation(program, name);
176 | if (attributeLocation === -1) {
177 | throw 'Cannot find attribute ' + name + '.';
178 | }
179 | return attributeLocation;
180 | }
181 |
182 | function getUniformLocation(program, name) {
183 | var attributeLocation = gl.getUniformLocation(program, name);
184 | if (attributeLocation === -1) {
185 | throw 'Cannot find uniform ' + name + '.';
186 | }
187 | return attributeLocation;
188 | }
189 |
190 |
191 | var vertexShader = compileShader(vertexSource, gl.VERTEX_SHADER);
192 | var fragmentShader = compileShader(fragmentSource, gl.FRAGMENT_SHADER);
193 |
194 | var program = gl.createProgram();
195 | gl.attachShader(program, vertexShader);
196 | gl.attachShader(program, fragmentShader);
197 | gl.linkProgram(program);
198 |
199 | gl.useProgram(program);
200 |
201 | var vertexData = new Float32Array([
202 | -1.0, 1.0,
203 | -1.0, -1.0,
204 | 1.0, 1.0,
205 | 1.0, -1.0,
206 | ]);
207 |
208 | var vertexDataBuffer = gl.createBuffer();
209 | gl.bindBuffer(gl.ARRAY_BUFFER, vertexDataBuffer);
210 | gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
211 |
212 | var positionHandle = getAttribLocation(program, 'position');
213 |
214 | gl.enableVertexAttribArray(positionHandle);
215 | gl.vertexAttribPointer(positionHandle,
216 | 2,
217 | gl.FLOAT,
218 | false,
219 | 2 * 4,
220 | 0
221 | );
222 |
223 | var timeHandle = getUniformLocation(program, 'time');
224 | var widthHandle = getUniformLocation(program, 'width');
225 | var heightHandle = getUniformLocation(program, 'height');
226 |
227 | gl.uniform1f(widthHandle, window.innerWidth);
228 | gl.uniform1f(heightHandle, window.innerHeight);
229 |
230 | var lastFrame = Date.now();
231 | var thisFrame;
232 |
233 | function draw(){
234 |
235 | thisFrame = Date.now();
236 | time += (thisFrame - lastFrame)/1000;
237 | lastFrame = thisFrame;
238 |
239 | gl.uniform1f(timeHandle, time);
240 | gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
241 |
242 | requestAnimationFrame(draw);
243 | }
244 |
245 | draw();
--------------------------------------------------------------------------------