Updates to the particle system
This commit is contained in:
@@ -31,6 +31,8 @@
|
|||||||
glowIntensity: 0.6,
|
glowIntensity: 0.6,
|
||||||
logoSpin: false,
|
logoSpin: false,
|
||||||
logoSpinSpeed: 5,
|
logoSpinSpeed: 5,
|
||||||
|
particleImage: "",
|
||||||
|
particleSize: 1.0,
|
||||||
titlePosition: "top",
|
titlePosition: "top",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -71,6 +73,8 @@
|
|||||||
let glowIntensity = saved.glowIntensity;
|
let glowIntensity = saved.glowIntensity;
|
||||||
let logoSpin = saved.logoSpin;
|
let logoSpin = saved.logoSpin;
|
||||||
let logoSpinSpeed = saved.logoSpinSpeed;
|
let logoSpinSpeed = saved.logoSpinSpeed;
|
||||||
|
let particleImage = saved.particleImage;
|
||||||
|
let particleSize = saved.particleSize;
|
||||||
let titlePosition = saved.titlePosition;
|
let titlePosition = saved.titlePosition;
|
||||||
let visualizerComponent;
|
let visualizerComponent;
|
||||||
let toggleHidden = false;
|
let toggleHidden = false;
|
||||||
@@ -126,6 +130,8 @@
|
|||||||
glowIntensity,
|
glowIntensity,
|
||||||
logoSpin,
|
logoSpin,
|
||||||
logoSpinSpeed,
|
logoSpinSpeed,
|
||||||
|
particleImage,
|
||||||
|
particleSize,
|
||||||
titlePosition,
|
titlePosition,
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
@@ -183,6 +189,8 @@
|
|||||||
glowIntensity = defaults.glowIntensity;
|
glowIntensity = defaults.glowIntensity;
|
||||||
logoSpin = defaults.logoSpin;
|
logoSpin = defaults.logoSpin;
|
||||||
logoSpinSpeed = defaults.logoSpinSpeed;
|
logoSpinSpeed = defaults.logoSpinSpeed;
|
||||||
|
particleImage = defaults.particleImage;
|
||||||
|
particleSize = defaults.particleSize;
|
||||||
titlePosition = defaults.titlePosition;
|
titlePosition = defaults.titlePosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,6 +319,8 @@
|
|||||||
{glowIntensity}
|
{glowIntensity}
|
||||||
{logoSpin}
|
{logoSpin}
|
||||||
{logoSpinSpeed}
|
{logoSpinSpeed}
|
||||||
|
{particleImage}
|
||||||
|
{particleSize}
|
||||||
bind:isListening
|
bind:isListening
|
||||||
bind:fileCurrentTime
|
bind:fileCurrentTime
|
||||||
bind:fileDuration
|
bind:fileDuration
|
||||||
@@ -381,6 +391,8 @@
|
|||||||
bind:glowIntensity
|
bind:glowIntensity
|
||||||
bind:logoSpin
|
bind:logoSpin
|
||||||
bind:logoSpinSpeed
|
bind:logoSpinSpeed
|
||||||
|
bind:particleImage
|
||||||
|
bind:particleSize
|
||||||
bind:titlePosition
|
bind:titlePosition
|
||||||
{isListening}
|
{isListening}
|
||||||
{colorPresets}
|
{colorPresets}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
export let glowIntensity = 0.6;
|
export let glowIntensity = 0.6;
|
||||||
export let logoSpin = false;
|
export let logoSpin = false;
|
||||||
export let logoSpinSpeed = 5;
|
export let logoSpinSpeed = 5;
|
||||||
|
export let particleImage = "";
|
||||||
|
export let particleSize = 1.0;
|
||||||
|
|
||||||
const DEFAULT_SIZE = 250;
|
const DEFAULT_SIZE = 250;
|
||||||
const LINE_LIFT = 8;
|
const LINE_LIFT = 8;
|
||||||
@@ -55,6 +57,16 @@
|
|||||||
let visualizerWrapper;
|
let visualizerWrapper;
|
||||||
let blobPhase = 0;
|
let blobPhase = 0;
|
||||||
|
|
||||||
|
// Particle image cache
|
||||||
|
let pImg = null;
|
||||||
|
$: if (particleImage) {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = particleImage;
|
||||||
|
pImg = img;
|
||||||
|
} else {
|
||||||
|
pImg = null;
|
||||||
|
}
|
||||||
|
|
||||||
// Particle system
|
// Particle system
|
||||||
let particles = [];
|
let particles = [];
|
||||||
|
|
||||||
@@ -100,7 +112,7 @@
|
|||||||
vy: -(1.5 + Math.random() * 4 * loudness),
|
vy: -(1.5 + Math.random() * 4 * loudness),
|
||||||
life: 1.0,
|
life: 1.0,
|
||||||
decay: 0.008 + Math.random() * 0.02,
|
decay: 0.008 + Math.random() * 0.02,
|
||||||
radius: 2 + Math.random() * 5,
|
radius: (2 + Math.random() * 5) * particleSize,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -124,7 +136,7 @@
|
|||||||
vy: -(0.8 + Math.random() * 3 * loudness),
|
vy: -(0.8 + Math.random() * 3 * loudness),
|
||||||
life: 1.0,
|
life: 1.0,
|
||||||
decay: 0.006 + Math.random() * 0.012,
|
decay: 0.006 + Math.random() * 0.012,
|
||||||
radius: 2 + Math.random() * 4,
|
radius: (2 + Math.random() * 4) * particleSize,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -147,7 +159,7 @@
|
|||||||
vy: Math.sin(tangent) * speed + Math.sin(angle) * speed * 0.3,
|
vy: Math.sin(tangent) * speed + Math.sin(angle) * speed * 0.3,
|
||||||
life: 1.0,
|
life: 1.0,
|
||||||
decay: 0.006 + Math.random() * 0.015,
|
decay: 0.006 + Math.random() * 0.015,
|
||||||
radius: 2 + Math.random() * 6,
|
radius: (2 + Math.random() * 6) * particleSize,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -164,7 +176,7 @@
|
|||||||
vy: Math.sin(angle) * speed,
|
vy: Math.sin(angle) * speed,
|
||||||
life: 1.0,
|
life: 1.0,
|
||||||
decay: 0.005 + Math.random() * 0.015,
|
decay: 0.005 + Math.random() * 0.015,
|
||||||
radius: 3 + Math.random() * 7,
|
radius: (3 + Math.random() * 7) * particleSize,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -193,17 +205,26 @@
|
|||||||
particles.pop();
|
particles.pop();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (pImg && pImg.complete) {
|
||||||
|
const sz = p.radius * p.life * 3;
|
||||||
|
ctx.globalAlpha = p.life;
|
||||||
|
ctx.drawImage(pImg, p.x - sz / 2, p.y - sz / 2, sz, sz);
|
||||||
|
ctx.globalAlpha = 1;
|
||||||
|
} else {
|
||||||
const alpha = Math.floor(p.life * 200)
|
const alpha = Math.floor(p.life * 200)
|
||||||
.toString(16)
|
.toString(16)
|
||||||
.padStart(2, "0");
|
.padStart(2, "0");
|
||||||
const color =
|
const color =
|
||||||
useSecondary && Math.random() > 0.5 ? colors.secondary : colors.primary;
|
useSecondary && Math.random() > 0.5
|
||||||
|
? colors.secondary
|
||||||
|
: colors.primary;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(p.x, p.y, p.radius * p.life, 0, Math.PI * 2);
|
ctx.arc(p.x, p.y, p.radius * p.life, 0, Math.PI * 2);
|
||||||
ctx.fillStyle = color + alpha;
|
ctx.fillStyle = color + alpha;
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function precalculateAngles() {
|
function precalculateAngles() {
|
||||||
const totalBars = barCount;
|
const totalBars = barCount;
|
||||||
|
|||||||
@@ -56,6 +56,8 @@
|
|||||||
export let glowIntensity = 0.6;
|
export let glowIntensity = 0.6;
|
||||||
export let logoSpin = false;
|
export let logoSpin = false;
|
||||||
export let logoSpinSpeed = 5;
|
export let logoSpinSpeed = 5;
|
||||||
|
export let particleImage = "";
|
||||||
|
export let particleSize = 1.0;
|
||||||
export let titlePosition = "top";
|
export let titlePosition = "top";
|
||||||
|
|
||||||
const dispatch = createEventDispatcher();
|
const dispatch = createEventDispatcher();
|
||||||
@@ -89,6 +91,13 @@
|
|||||||
if (file) readFileAsDataUrl(file, (url) => (logoUrl = url));
|
if (file) readFileAsDataUrl(file, (url) => (logoUrl = url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let particleImgInput;
|
||||||
|
|
||||||
|
function handleParticleImgUpload(e) {
|
||||||
|
const file = e.target.files[0];
|
||||||
|
if (file) readFileAsDataUrl(file, (url) => (particleImage = url));
|
||||||
|
}
|
||||||
|
|
||||||
function handleBgUpload(e) {
|
function handleBgUpload(e) {
|
||||||
const file = e.target.files[0];
|
const file = e.target.files[0];
|
||||||
if (file) readFileAsDataUrl(file, (url) => (bgImage = url));
|
if (file) readFileAsDataUrl(file, (url) => (bgImage = url));
|
||||||
@@ -553,6 +562,42 @@
|
|||||||
bind:value={particleDensity}
|
bind:value={particleDensity}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="slider-row">
|
||||||
|
<label for="slider-psize"
|
||||||
|
>Size <span class="slider-val">{particleSize.toFixed(1)}</span></label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="slider-psize"
|
||||||
|
type="range"
|
||||||
|
min="0.3"
|
||||||
|
max="5.0"
|
||||||
|
step="0.1"
|
||||||
|
bind:value={particleSize}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="inline-row" style="margin-top: 0.5rem; gap: 0.4rem">
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
accept="image/*"
|
||||||
|
on:change={handleParticleImgUpload}
|
||||||
|
bind:this={particleImgInput}
|
||||||
|
id="particle-img-upload"
|
||||||
|
style="display: none"
|
||||||
|
/>
|
||||||
|
<label for="particle-img-upload" class="upload-btn"
|
||||||
|
>Particle Image</label
|
||||||
|
>
|
||||||
|
{#if particleImage}
|
||||||
|
<img
|
||||||
|
src={particleImage}
|
||||||
|
alt="particle"
|
||||||
|
style="width: 22px; height: 22px; object-fit: cover; border-radius: 4px"
|
||||||
|
/>
|
||||||
|
<button class="clear-btn" on:click={() => (particleImage = "")}
|
||||||
|
>Clear</button
|
||||||
|
>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
<div class="slider-row">
|
<div class="slider-row">
|
||||||
<label for="slider-shake"
|
<label for="slider-shake"
|
||||||
|
|||||||
Reference in New Issue
Block a user