@sarthak03dot/romantic-animations 1.2.10 → 1.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/index.d.ts +102 -0
- package/package.json +4 -5
- package/dist/index.d.ts +0 -1
- package/src/animations/butterfly.js +0 -92
- package/src/animations/confetti.js +0 -92
- package/src/animations/fireworks.js +0 -112
- package/src/animations/floatingHearts.js +0 -89
- package/src/animations/floatingOrbs.js +0 -76
- package/src/animations/heartBurst.js +0 -113
- package/src/animations/heartTrail.js +0 -85
- package/src/animations/loveRain.js +0 -71
- package/src/animations/magicDust.js +0 -87
- package/src/animations/shootingStars.js +0 -82
- package/src/animations/sparkles.js +0 -93
- package/src/animations/starField.js +0 -100
- package/src/core/engine.js +0 -77
- package/src/index.d.ts +0 -26
- package/src/index.js +0 -224
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
count: 20, // hearts per burst
|
|
5
|
-
minSize: 8,
|
|
6
|
-
maxSize: 20,
|
|
7
|
-
minSpeed: 2,
|
|
8
|
-
maxSpeed: 7,
|
|
9
|
-
gravity: 0.08,
|
|
10
|
-
decay: 0.018,
|
|
11
|
-
colors: ['#ff0a54', '#ff477e', '#ff7096', '#ff85a1', '#fbb1bd', '#ff4d6d'],
|
|
12
|
-
glow: true,
|
|
13
|
-
symbols: ['heart'], // 'heart' | 'star' | 'sparkle'
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
function drawSymbol(ctx, type, cx, cy, r, color, alpha, glow) {
|
|
17
|
-
ctx.save();
|
|
18
|
-
ctx.globalAlpha = Math.max(0, alpha);
|
|
19
|
-
if (glow) { ctx.shadowColor = color; ctx.shadowBlur = r * 2; }
|
|
20
|
-
ctx.fillStyle = color;
|
|
21
|
-
|
|
22
|
-
if (type === 'star') {
|
|
23
|
-
// 5-point star
|
|
24
|
-
ctx.beginPath();
|
|
25
|
-
for (let i = 0; i < 5; i++) {
|
|
26
|
-
const outer = (Math.PI / 2) + (i * 2 * Math.PI) / 5;
|
|
27
|
-
const inner = outer + Math.PI / 5;
|
|
28
|
-
if (i === 0) ctx.moveTo(cx + r * Math.cos(outer), cy - r * Math.sin(outer));
|
|
29
|
-
else ctx.lineTo(cx + r * Math.cos(outer), cy - r * Math.sin(outer));
|
|
30
|
-
ctx.lineTo(cx + (r * 0.4) * Math.cos(inner), cy - (r * 0.4) * Math.sin(inner));
|
|
31
|
-
}
|
|
32
|
-
ctx.closePath();
|
|
33
|
-
ctx.fill();
|
|
34
|
-
} else if (type === 'sparkle') {
|
|
35
|
-
// 4-point sparkle
|
|
36
|
-
for (let i = 0; i < 4; i++) {
|
|
37
|
-
const a = (i * Math.PI) / 2;
|
|
38
|
-
ctx.beginPath();
|
|
39
|
-
ctx.ellipse(cx + Math.cos(a) * r * 0.5, cy + Math.sin(a) * r * 0.5, r * 0.18, r * 0.7, a, 0, Math.PI * 2);
|
|
40
|
-
ctx.fill();
|
|
41
|
-
}
|
|
42
|
-
} else {
|
|
43
|
-
// heart
|
|
44
|
-
ctx.beginPath();
|
|
45
|
-
ctx.moveTo(cx, cy + r * 0.3);
|
|
46
|
-
ctx.bezierCurveTo(cx - r * 1.1, cy - r * 0.5, cx - r * 1.6, cy + r * 0.5, cx, cy + r * 1.4);
|
|
47
|
-
ctx.bezierCurveTo(cx + r * 1.6, cy + r * 0.5, cx + r * 1.1, cy - r * 0.5, cx, cy + r * 0.3);
|
|
48
|
-
ctx.fill();
|
|
49
|
-
}
|
|
50
|
-
ctx.restore();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function heartBurst(canvas, userOptions = {}) {
|
|
54
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
55
|
-
const ctx = canvas.getContext('2d');
|
|
56
|
-
const particles = [];
|
|
57
|
-
let running = true;
|
|
58
|
-
|
|
59
|
-
function spawnBurst(x, y) {
|
|
60
|
-
for (let i = 0; i < opts.count; i++) {
|
|
61
|
-
const angle = Math.random() * Math.PI * 2;
|
|
62
|
-
const speed = opts.minSpeed + Math.random() * (opts.maxSpeed - opts.minSpeed);
|
|
63
|
-
particles.push({
|
|
64
|
-
x, y,
|
|
65
|
-
size: opts.minSize + Math.random() * (opts.maxSize - opts.minSize),
|
|
66
|
-
vx: Math.cos(angle) * speed,
|
|
67
|
-
vy: Math.sin(angle) * speed,
|
|
68
|
-
alpha: 1,
|
|
69
|
-
decay: opts.decay * (0.8 + Math.random() * 0.4),
|
|
70
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
71
|
-
symbol: opts.symbols[Math.floor(Math.random() * opts.symbols.length)],
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const onClick = (e) => {
|
|
77
|
-
const rect = canvas.getBoundingClientRect();
|
|
78
|
-
spawnBurst(e.clientX - rect.left, e.clientY - rect.top);
|
|
79
|
-
};
|
|
80
|
-
const onTouch = (e) => {
|
|
81
|
-
const rect = canvas.getBoundingClientRect();
|
|
82
|
-
Array.from(e.changedTouches).forEach((t) => spawnBurst(t.clientX - rect.left, t.clientY - rect.top));
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
window.addEventListener('click', onClick);
|
|
86
|
-
window.addEventListener('touchend', onTouch, { passive: true });
|
|
87
|
-
|
|
88
|
-
function animate() {
|
|
89
|
-
if (!running) return;
|
|
90
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
91
|
-
|
|
92
|
-
for (let i = particles.length - 1; i >= 0; i--) {
|
|
93
|
-
const p = particles[i];
|
|
94
|
-
p.x += p.vx;
|
|
95
|
-
p.y += p.vy;
|
|
96
|
-
p.vy += opts.gravity; // gravity
|
|
97
|
-
p.alpha -= p.decay;
|
|
98
|
-
drawSymbol(ctx, p.symbol, p.x, p.y, p.size, p.color, p.alpha, opts.glow);
|
|
99
|
-
if (p.alpha <= 0) particles.splice(i, 1);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
requestAnimationFrame(animate);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
animate();
|
|
106
|
-
|
|
107
|
-
return function stop() {
|
|
108
|
-
running = false;
|
|
109
|
-
window.removeEventListener('click', onClick);
|
|
110
|
-
window.removeEventListener('touchend', onTouch);
|
|
111
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
112
|
-
};
|
|
113
|
-
}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
minSize: 6,
|
|
5
|
-
maxSize: 16,
|
|
6
|
-
decay: 0.025,
|
|
7
|
-
colors: ['#ff6b8a', '#ff4d6d', '#ff85a1', '#ffc2d1', '#c9184a'],
|
|
8
|
-
glow: true,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
function drawHeart(ctx, cx, cy, r, color, alpha, glow) {
|
|
12
|
-
ctx.save();
|
|
13
|
-
ctx.globalAlpha = Math.max(0, alpha);
|
|
14
|
-
if (glow) {
|
|
15
|
-
ctx.shadowColor = color;
|
|
16
|
-
ctx.shadowBlur = r * 2;
|
|
17
|
-
}
|
|
18
|
-
ctx.fillStyle = color;
|
|
19
|
-
ctx.beginPath();
|
|
20
|
-
ctx.moveTo(cx, cy + r * 0.3);
|
|
21
|
-
ctx.bezierCurveTo(cx - r * 1.1, cy - r * 0.5, cx - r * 1.6, cy + r * 0.5, cx, cy + r * 1.4);
|
|
22
|
-
ctx.bezierCurveTo(cx + r * 1.6, cy + r * 0.5, cx + r * 1.1, cy - r * 0.5, cx, cy + r * 0.3);
|
|
23
|
-
ctx.fill();
|
|
24
|
-
ctx.restore();
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export function heartTrail(canvas, userOptions = {}) {
|
|
28
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
29
|
-
const ctx = canvas.getContext('2d');
|
|
30
|
-
const hearts = [];
|
|
31
|
-
let running = true;
|
|
32
|
-
|
|
33
|
-
function addHeart(x, y) {
|
|
34
|
-
hearts.push({
|
|
35
|
-
x,
|
|
36
|
-
y,
|
|
37
|
-
size: opts.minSize + Math.random() * (opts.maxSize - opts.minSize),
|
|
38
|
-
alpha: 0.9 + Math.random() * 0.1,
|
|
39
|
-
decay: opts.decay * (0.8 + Math.random() * 0.4),
|
|
40
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
41
|
-
vy: -(0.3 + Math.random() * 0.6), // drift upward
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Mouse support
|
|
46
|
-
const onMouseMove = (e) => {
|
|
47
|
-
const rect = canvas.getBoundingClientRect();
|
|
48
|
-
addHeart(e.clientX - rect.left, e.clientY - rect.top);
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// Touch support
|
|
52
|
-
const onTouchMove = (e) => {
|
|
53
|
-
const rect = canvas.getBoundingClientRect();
|
|
54
|
-
Array.from(e.touches).forEach((t) => {
|
|
55
|
-
addHeart(t.clientX - rect.left, t.clientY - rect.top);
|
|
56
|
-
});
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
window.addEventListener('mousemove', onMouseMove);
|
|
60
|
-
window.addEventListener('touchmove', onTouchMove, { passive: true });
|
|
61
|
-
|
|
62
|
-
function animate() {
|
|
63
|
-
if (!running) return;
|
|
64
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
65
|
-
|
|
66
|
-
for (let i = hearts.length - 1; i >= 0; i--) {
|
|
67
|
-
const h = hearts[i];
|
|
68
|
-
h.y += h.vy;
|
|
69
|
-
drawHeart(ctx, h.x, h.y, h.size, h.color, h.alpha, opts.glow);
|
|
70
|
-
h.alpha -= h.decay;
|
|
71
|
-
if (h.alpha <= 0) hearts.splice(i, 1);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
requestAnimationFrame(animate);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
animate();
|
|
78
|
-
|
|
79
|
-
return function stop() {
|
|
80
|
-
running = false;
|
|
81
|
-
window.removeEventListener('mousemove', onMouseMove);
|
|
82
|
-
window.removeEventListener('touchmove', onTouchMove);
|
|
83
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
84
|
-
};
|
|
85
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
density: 0.15, // probability of a new drop per frame
|
|
5
|
-
symbols: ['❤', '💕', '✨', '💖', '💗', '⭐', '×'],
|
|
6
|
-
minSize: 12,
|
|
7
|
-
maxSize: 28,
|
|
8
|
-
minSpeed: 1,
|
|
9
|
-
maxSpeed: 3.5,
|
|
10
|
-
colors: ['#ff6b8a', '#ff4d6d', '#ffc2d1', '#ff85a1', '#ff0a54', '#a2d2ff'],
|
|
11
|
-
opacity: 0.85,
|
|
12
|
-
glow: true,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
export function loveRain(canvas, userOptions = {}) {
|
|
16
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
17
|
-
const ctx = canvas.getContext('2d');
|
|
18
|
-
const drops = [];
|
|
19
|
-
let running = true;
|
|
20
|
-
|
|
21
|
-
function createDrop() {
|
|
22
|
-
const size = opts.minSize + Math.random() * (opts.maxSize - opts.minSize);
|
|
23
|
-
return {
|
|
24
|
-
x: Math.random() * canvas.width,
|
|
25
|
-
y: -size * 2,
|
|
26
|
-
size,
|
|
27
|
-
speed: opts.minSpeed + Math.random() * (opts.maxSpeed - opts.minSpeed),
|
|
28
|
-
symbol: opts.symbols[Math.floor(Math.random() * opts.symbols.length)],
|
|
29
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
30
|
-
alpha: 0.4 + Math.random() * 0.6,
|
|
31
|
-
angle: (Math.random() - 0.5) * 0.4, // slight tilt
|
|
32
|
-
wobble: Math.random() * Math.PI * 2,
|
|
33
|
-
wobbleSpeed: 0.02 + Math.random() * 0.02,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function animate() {
|
|
38
|
-
if (!running) return;
|
|
39
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
40
|
-
|
|
41
|
-
if (Math.random() < opts.density) drops.push(createDrop());
|
|
42
|
-
|
|
43
|
-
for (let i = drops.length - 1; i >= 0; i--) {
|
|
44
|
-
const d = drops[i];
|
|
45
|
-
d.y += d.speed;
|
|
46
|
-
d.wobble += d.wobbleSpeed;
|
|
47
|
-
const xOff = Math.sin(d.wobble) * d.size * 0.3;
|
|
48
|
-
|
|
49
|
-
ctx.save();
|
|
50
|
-
ctx.globalAlpha = d.alpha * opts.opacity;
|
|
51
|
-
ctx.font = `${d.size}px serif`;
|
|
52
|
-
ctx.fillStyle = d.color;
|
|
53
|
-
if (opts.glow) { ctx.shadowColor = d.color; ctx.shadowBlur = d.size * 0.8; }
|
|
54
|
-
ctx.translate(d.x + xOff, d.y);
|
|
55
|
-
ctx.rotate(d.angle);
|
|
56
|
-
ctx.fillText(d.symbol, 0, 0);
|
|
57
|
-
ctx.restore();
|
|
58
|
-
|
|
59
|
-
if (d.y > canvas.height + d.size * 2) drops.splice(i, 1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
requestAnimationFrame(animate);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
animate();
|
|
66
|
-
|
|
67
|
-
return function stop() {
|
|
68
|
-
running = false;
|
|
69
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
70
|
-
};
|
|
71
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
particleCount: 150,
|
|
5
|
-
minSize: 1,
|
|
6
|
-
maxSize: 4,
|
|
7
|
-
colors: ['#ffd6ff', '#e7c6ff', '#c77dff', '#ffb3c1', '#ffffff'],
|
|
8
|
-
speed: 0.8,
|
|
9
|
-
glow: true,
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
export function magicDust(canvas, userOptions = {}) {
|
|
13
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
14
|
-
const ctx = canvas.getContext('2d');
|
|
15
|
-
const dusts = [];
|
|
16
|
-
let running = true;
|
|
17
|
-
let time = 0;
|
|
18
|
-
|
|
19
|
-
function createDust() {
|
|
20
|
-
return {
|
|
21
|
-
x: Math.random() * canvas.width,
|
|
22
|
-
y: Math.random() * canvas.height,
|
|
23
|
-
size: opts.minSize + Math.random() * (opts.maxSize - opts.minSize),
|
|
24
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
25
|
-
angle: Math.random() * Math.PI * 2,
|
|
26
|
-
orbitRadius: 20 + Math.random() * 80,
|
|
27
|
-
orbitSpeed: (0.01 + Math.random() * 0.03) * (Math.random() > 0.5 ? 1 : -1),
|
|
28
|
-
centerX: Math.random() * canvas.width,
|
|
29
|
-
centerY: canvas.height + 50, // Start below and move up
|
|
30
|
-
upwardSpeed: opts.speed + Math.random() * 1.5,
|
|
31
|
-
alpha: 0,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < opts.particleCount; i++) {
|
|
36
|
-
dusts.push(createDust());
|
|
37
|
-
// Scatter initial positions so they aren't all at the bottom
|
|
38
|
-
dusts[i].centerY = Math.random() * canvas.height;
|
|
39
|
-
dusts[i].alpha = Math.random();
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function animate() {
|
|
43
|
-
if (!running) return;
|
|
44
|
-
time++;
|
|
45
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
46
|
-
|
|
47
|
-
for (let i = 0; i < dusts.length; i++) {
|
|
48
|
-
const d = dusts[i];
|
|
49
|
-
d.angle += d.orbitSpeed;
|
|
50
|
-
d.centerY -= d.upwardSpeed;
|
|
51
|
-
|
|
52
|
-
// Swirling calculation
|
|
53
|
-
d.x = d.centerX + Math.cos(d.angle) * d.orbitRadius + Math.sin(time * 0.01 + d.angle) * 30;
|
|
54
|
-
d.y = d.centerY + Math.sin(d.angle) * (d.orbitRadius * 0.5);
|
|
55
|
-
|
|
56
|
-
if (d.alpha < 1 && d.centerY > 0) d.alpha += 0.01;
|
|
57
|
-
|
|
58
|
-
// Reset when they reach top
|
|
59
|
-
if (d.y < -50) {
|
|
60
|
-
Object.assign(d, createDust());
|
|
61
|
-
d.centerY = canvas.height + 50;
|
|
62
|
-
d.centerX = Math.random() * canvas.width;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
ctx.save();
|
|
66
|
-
ctx.globalAlpha = d.alpha;
|
|
67
|
-
if (opts.glow) {
|
|
68
|
-
ctx.shadowColor = d.color;
|
|
69
|
-
ctx.shadowBlur = d.size * 3;
|
|
70
|
-
}
|
|
71
|
-
ctx.fillStyle = d.color;
|
|
72
|
-
ctx.beginPath();
|
|
73
|
-
ctx.arc(d.x, d.y, d.size, 0, Math.PI * 2);
|
|
74
|
-
ctx.fill();
|
|
75
|
-
ctx.restore();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
requestAnimationFrame(animate);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
animate();
|
|
82
|
-
|
|
83
|
-
return function stop() {
|
|
84
|
-
running = false;
|
|
85
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
86
|
-
};
|
|
87
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
density: 0.02,
|
|
5
|
-
minSpeed: 10,
|
|
6
|
-
maxSpeed: 25,
|
|
7
|
-
colors: ['#ffffff', '#e7c6ff', '#48cae4', '#ffe66d'],
|
|
8
|
-
glow: true,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
export function shootingStars(canvas, userOptions = {}) {
|
|
12
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
13
|
-
const ctx = canvas.getContext('2d');
|
|
14
|
-
const stars = [];
|
|
15
|
-
let running = true;
|
|
16
|
-
|
|
17
|
-
function createStar() {
|
|
18
|
-
return {
|
|
19
|
-
x: Math.random() * canvas.width * 1.5,
|
|
20
|
-
y: -50,
|
|
21
|
-
length: 50 + Math.random() * 100,
|
|
22
|
-
thickness: 1 + Math.random() * 2,
|
|
23
|
-
speed: opts.minSpeed + Math.random() * (opts.maxSpeed - opts.minSpeed),
|
|
24
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
25
|
-
angle: (Math.PI / 4) + (Math.random() * 0.2 - 0.1), // Roughly 45 degrees
|
|
26
|
-
opacity: 1,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function animate() {
|
|
31
|
-
if (!running) return;
|
|
32
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
33
|
-
|
|
34
|
-
if (Math.random() < opts.density) {
|
|
35
|
-
stars.push(createStar());
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
for (let i = stars.length - 1; i >= 0; i--) {
|
|
39
|
-
const s = stars[i];
|
|
40
|
-
const vx = -Math.cos(s.angle) * s.speed;
|
|
41
|
-
const vy = Math.sin(s.angle) * s.speed;
|
|
42
|
-
|
|
43
|
-
s.x += vx;
|
|
44
|
-
s.y += vy;
|
|
45
|
-
s.opacity -= 0.01;
|
|
46
|
-
|
|
47
|
-
ctx.save();
|
|
48
|
-
ctx.globalAlpha = Math.max(0, s.opacity);
|
|
49
|
-
if (opts.glow) {
|
|
50
|
-
ctx.shadowColor = s.color;
|
|
51
|
-
ctx.shadowBlur = s.thickness * 4;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const grad = ctx.createLinearGradient(s.x, s.y, s.x - vx * (s.length / s.speed), s.y - vy * (s.length / s.speed));
|
|
55
|
-
grad.addColorStop(0, s.color);
|
|
56
|
-
grad.addColorStop(1, 'rgba(255,255,255,0)');
|
|
57
|
-
|
|
58
|
-
ctx.strokeStyle = grad;
|
|
59
|
-
ctx.lineWidth = s.thickness;
|
|
60
|
-
ctx.lineCap = 'round';
|
|
61
|
-
|
|
62
|
-
ctx.beginPath();
|
|
63
|
-
ctx.moveTo(s.x, s.y);
|
|
64
|
-
ctx.lineTo(s.x - vx * (s.length / s.speed), s.y - vy * (s.length / s.speed));
|
|
65
|
-
ctx.stroke();
|
|
66
|
-
ctx.restore();
|
|
67
|
-
|
|
68
|
-
if (s.opacity <= 0 || s.x < -100 || s.y > canvas.height + 100) {
|
|
69
|
-
stars.splice(i, 1);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
requestAnimationFrame(animate);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
animate();
|
|
77
|
-
|
|
78
|
-
return function stop() {
|
|
79
|
-
running = false;
|
|
80
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
81
|
-
};
|
|
82
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
count: 80, // number of sparkles alive at once
|
|
5
|
-
minSize: 2,
|
|
6
|
-
maxSize: 6,
|
|
7
|
-
speed: 0.5,
|
|
8
|
-
twinkleSpeed: 0.04,
|
|
9
|
-
colors: ['#fff', '#ffe4e8', '#ffb3c1', '#ff85a1', '#ffd6ff', '#e7c6ff'],
|
|
10
|
-
glow: true,
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export function sparkles(canvas, userOptions = {}) {
|
|
14
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
15
|
-
const ctx = canvas.getContext('2d');
|
|
16
|
-
const stars = [];
|
|
17
|
-
let running = true;
|
|
18
|
-
|
|
19
|
-
function createStar() {
|
|
20
|
-
return {
|
|
21
|
-
x: Math.random() * canvas.width,
|
|
22
|
-
y: Math.random() * canvas.height,
|
|
23
|
-
size: opts.minSize + Math.random() * (opts.maxSize - opts.minSize),
|
|
24
|
-
alpha: Math.random(),
|
|
25
|
-
alphaDir: Math.random() > 0.5 ? 1 : -1,
|
|
26
|
-
twinkleSpeed: opts.twinkleSpeed * (0.5 + Math.random()),
|
|
27
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
28
|
-
vx: (Math.random() - 0.5) * opts.speed,
|
|
29
|
-
vy: (Math.random() - 0.5) * opts.speed,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Populate initial stars
|
|
34
|
-
for (let i = 0; i < opts.count; i++) stars.push(createStar());
|
|
35
|
-
|
|
36
|
-
function drawStar(s) {
|
|
37
|
-
ctx.save();
|
|
38
|
-
ctx.globalAlpha = Math.max(0, Math.min(1, s.alpha));
|
|
39
|
-
if (opts.glow) { ctx.shadowColor = s.color; ctx.shadowBlur = s.size * 3; }
|
|
40
|
-
ctx.fillStyle = s.color;
|
|
41
|
-
|
|
42
|
-
// Cross / sparkle shape
|
|
43
|
-
const r = s.size;
|
|
44
|
-
ctx.beginPath();
|
|
45
|
-
for (let i = 0; i < 4; i++) {
|
|
46
|
-
const a = (i * Math.PI) / 2;
|
|
47
|
-
ctx.ellipse(
|
|
48
|
-
s.x + Math.cos(a) * r * 0.35,
|
|
49
|
-
s.y + Math.sin(a) * r * 0.35,
|
|
50
|
-
r * 0.15, r * 0.7, a, 0, Math.PI * 2
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
ctx.fill();
|
|
54
|
-
|
|
55
|
-
// Tiny centre dot
|
|
56
|
-
ctx.beginPath();
|
|
57
|
-
ctx.arc(s.x, s.y, r * 0.2, 0, Math.PI * 2);
|
|
58
|
-
ctx.fill();
|
|
59
|
-
ctx.restore();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function animate() {
|
|
63
|
-
if (!running) return;
|
|
64
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
65
|
-
|
|
66
|
-
for (let i = 0; i < stars.length; i++) {
|
|
67
|
-
const s = stars[i];
|
|
68
|
-
s.x += s.vx;
|
|
69
|
-
s.y += s.vy;
|
|
70
|
-
s.alpha += s.alphaDir * s.twinkleSpeed;
|
|
71
|
-
|
|
72
|
-
if (s.alpha >= 1) { s.alpha = 1; s.alphaDir = -1; }
|
|
73
|
-
else if (s.alpha <= 0) { s.alpha = 0; s.alphaDir = 1; }
|
|
74
|
-
|
|
75
|
-
// Wrap edges
|
|
76
|
-
if (s.x < -10) s.x = canvas.width + 10;
|
|
77
|
-
if (s.x > canvas.width + 10) s.x = -10;
|
|
78
|
-
if (s.y < -10) s.y = canvas.height + 10;
|
|
79
|
-
if (s.y > canvas.height + 10) s.y = -10;
|
|
80
|
-
|
|
81
|
-
drawStar(s);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
requestAnimationFrame(animate);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
animate();
|
|
88
|
-
|
|
89
|
-
return function stop() {
|
|
90
|
-
running = false;
|
|
91
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
92
|
-
};
|
|
93
|
-
}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
import { mergeOptions } from '../core/engine.js';
|
|
2
|
-
|
|
3
|
-
const DEFAULTS = {
|
|
4
|
-
starCount: 120,
|
|
5
|
-
speed: 0.4,
|
|
6
|
-
colors: ['#ffffff', '#ffe4e8', '#ffc2d1', '#e7c6ff', '#a2d2ff'],
|
|
7
|
-
minSize: 1,
|
|
8
|
-
maxSize: 3.5,
|
|
9
|
-
twinkle: true,
|
|
10
|
-
connectDist: 100, // draw faint lines between close stars
|
|
11
|
-
connectOpacity: 0.08,
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export function starField(canvas, userOptions = {}) {
|
|
15
|
-
const opts = mergeOptions(DEFAULTS, userOptions);
|
|
16
|
-
const ctx = canvas.getContext('2d');
|
|
17
|
-
const stars = [];
|
|
18
|
-
let running = true;
|
|
19
|
-
|
|
20
|
-
function createStar(randomY = false) {
|
|
21
|
-
return {
|
|
22
|
-
x: Math.random() * canvas.width,
|
|
23
|
-
y: randomY ? Math.random() * canvas.height : Math.random() * canvas.height,
|
|
24
|
-
size: opts.minSize + Math.random() * (opts.maxSize - opts.minSize),
|
|
25
|
-
alpha: 0.3 + Math.random() * 0.7,
|
|
26
|
-
alphaDir: Math.random() > 0.5 ? 1 : -1,
|
|
27
|
-
twinkleSpeed: 0.008 + Math.random() * 0.015,
|
|
28
|
-
vx: (Math.random() - 0.5) * opts.speed,
|
|
29
|
-
vy: (Math.random() - 0.5) * opts.speed,
|
|
30
|
-
color: opts.colors[Math.floor(Math.random() * opts.colors.length)],
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (let i = 0; i < opts.starCount; i++) stars.push(createStar(true));
|
|
35
|
-
|
|
36
|
-
function animate() {
|
|
37
|
-
if (!running) return;
|
|
38
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
39
|
-
|
|
40
|
-
// Draw connections
|
|
41
|
-
if (opts.connectDist > 0) {
|
|
42
|
-
for (let i = 0; i < stars.length; i++) {
|
|
43
|
-
for (let j = i + 1; j < stars.length; j++) {
|
|
44
|
-
const dx = stars[i].x - stars[j].x;
|
|
45
|
-
const dy = stars[i].y - stars[j].y;
|
|
46
|
-
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
47
|
-
if (dist < opts.connectDist) {
|
|
48
|
-
ctx.save();
|
|
49
|
-
ctx.globalAlpha = opts.connectOpacity * (1 - dist / opts.connectDist);
|
|
50
|
-
ctx.strokeStyle = '#ffffff';
|
|
51
|
-
ctx.lineWidth = 0.5;
|
|
52
|
-
ctx.beginPath();
|
|
53
|
-
ctx.moveTo(stars[i].x, stars[i].y);
|
|
54
|
-
ctx.lineTo(stars[j].x, stars[j].y);
|
|
55
|
-
ctx.stroke();
|
|
56
|
-
ctx.restore();
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Draw stars
|
|
63
|
-
for (let i = 0; i < stars.length; i++) {
|
|
64
|
-
const s = stars[i];
|
|
65
|
-
s.x += s.vx;
|
|
66
|
-
s.y += s.vy;
|
|
67
|
-
|
|
68
|
-
if (opts.twinkle) {
|
|
69
|
-
s.alpha += s.alphaDir * s.twinkleSpeed;
|
|
70
|
-
if (s.alpha >= 1) { s.alpha = 1; s.alphaDir = -1; }
|
|
71
|
-
if (s.alpha <= 0.1) { s.alpha = 0.1; s.alphaDir = 1; }
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Wrap
|
|
75
|
-
if (s.x < -5) s.x = canvas.width + 5;
|
|
76
|
-
if (s.x > canvas.width + 5) s.x = -5;
|
|
77
|
-
if (s.y < -5) s.y = canvas.height + 5;
|
|
78
|
-
if (s.y > canvas.height + 5) s.y = -5;
|
|
79
|
-
|
|
80
|
-
ctx.save();
|
|
81
|
-
ctx.globalAlpha = s.alpha;
|
|
82
|
-
ctx.shadowColor = s.color;
|
|
83
|
-
ctx.shadowBlur = s.size * 3;
|
|
84
|
-
ctx.fillStyle = s.color;
|
|
85
|
-
ctx.beginPath();
|
|
86
|
-
ctx.arc(s.x, s.y, s.size, 0, Math.PI * 2);
|
|
87
|
-
ctx.fill();
|
|
88
|
-
ctx.restore();
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
requestAnimationFrame(animate);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
animate();
|
|
95
|
-
|
|
96
|
-
return function stop() {
|
|
97
|
-
running = false;
|
|
98
|
-
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
99
|
-
};
|
|
100
|
-
}
|