diff --git a/public/app.js b/public/app.js index 11b5ea0..55ad155 100644 --- a/public/app.js +++ b/public/app.js @@ -651,6 +651,162 @@ const r = 0.76 + 0.24 * Math.cos(6 * (i / count) * Math.PI * 2); verts.push({ x: Math.cos(theta) * r, y: Math.sin(theta) * r }); } + } else if (shape === 'lightning') { + verts = [ + { x: 0.18, y: -1.0 }, + { x: -0.42, y: -0.08 }, + { x: -0.06, y: -0.08 }, + { x: -0.32, y: 1.0 }, + { x: 0.42, y: 0.08 }, + { x: 0.06, y: 0.08 } + ]; + } else if (shape === 'flame') { + const count = 64; + for (let i = 0; i < count; i++) { + const u = (i / count) * Math.PI * 2; + const px = 0.78 * Math.sin(u) * Math.pow(Math.sin(u / 2), 0.75); + const py = -Math.cos(u) * 0.95 - 0.05 * Math.cos(2 * u); + verts.push({ x: px, y: py }); + } + } else if (shape === 'skull') { + verts = [ + { x: 0, y: -0.95 }, + { x: 0.38, y: -0.90 }, + { x: 0.70, y: -0.68 }, + { x: 0.84, y: -0.32 }, + { x: 0.82, y: 0.0 }, + { x: 0.62, y: 0.18 }, + { x: 0.75, y: 0.38 }, + { x: 0.48, y: 0.52 }, + { x: 0.42, y: 0.88 }, + { x: 0.20, y: 0.94 }, + { x: 0, y: 0.95 }, + { x: -0.20, y: 0.94 }, + { x: -0.42, y: 0.88 }, + { x: -0.48, y: 0.52 }, + { x: -0.75, y: 0.38 }, + { x: -0.62, y: 0.18 }, + { x: -0.82, y: 0.0 }, + { x: -0.84, y: -0.32 }, + { x: -0.70, y: -0.68 }, + { x: -0.38, y: -0.90 } + ]; + } else if (shape === 'crown') { + verts = [ + { x: 0, y: -0.95 }, + { x: 0.24, y: -0.32 }, + { x: 0.50, y: -0.80 }, + { x: 0.66, y: -0.25 }, + { x: 0.88, y: -0.65 }, + { x: 0.82, y: 0.70 }, + { x: 0.40, y: 0.75 }, + { x: 0, y: 0.76 }, + { x: -0.40, y: 0.75 }, + { x: -0.82, y: 0.70 }, + { x: -0.88, y: -0.65 }, + { x: -0.66, y: -0.25 }, + { x: -0.50, y: -0.80 }, + { x: -0.24, y: -0.32 } + ]; + } else if (shape === 'crescent') { + const count = 36; + for (let i = 0; i <= count; i++) { + const a = Math.PI * 1.5 - (i / count) * Math.PI; + verts.push({ x: 0.92 * Math.cos(a) + 0.42, y: 0.92 * Math.sin(a) }); + } + for (let i = 1; i < count; i++) { + const phi = Math.PI * 0.5 - (i / count) * Math.PI; + verts.push({ x: -0.36 * Math.cos(phi) + 0.42, y: 0.92 * Math.sin(phi) }); + } + } else if (shape === 'infinity') { + const count = 64; + for (let i = 0; i < count; i++) { + const theta = (i / count) * Math.PI * 2; + const r = 0.32 + 0.64 * Math.pow(Math.cos(theta), 2); + verts.push({ x: Math.cos(theta) * r, y: Math.sin(theta) * r }); + } + } else if (shape === 'eye') { + const count = 32; + for (let i = 0; i <= count; i++) { + const t = i / count; + verts.push({ x: -0.95 + 1.90 * t, y: -Math.sin(t * Math.PI) * 0.62 }); + } + for (let i = count - 1; i > 0; i--) { + const t = i / count; + verts.push({ x: -0.95 + 1.90 * t, y: Math.sin(t * Math.PI) * 0.62 }); + } + } else if (shape === 'gem') { + verts = [ + { x: -0.52, y: -0.85 }, + { x: 0.52, y: -0.85 }, + { x: 0.92, y: -0.32 }, + { x: 0, y: 0.98 }, + { x: -0.92, y: -0.32 } + ]; + } else if (shape === 'pick') { + const count = 48; + for (let i = 0; i < count; i++) { + const a = (i / count) * Math.PI * 2; + const px = 0.80 * Math.cos(a) * (1.0 - 0.45 * Math.sin(a)); + const py = 0.92 * Math.sin(a); + verts.push({ x: px, y: py }); + } + } else if (shape === 'sun') { + const n = 16; + const step = Math.PI / n; + const start = -Math.PI / 2; + for (let i = 0; i < n * 2; i++) { + const r = (i % 2 === 0) ? 1.0 : 0.72; + const a = start + i * step; + verts.push({ x: Math.cos(a) * r, y: Math.sin(a) * r }); + } + } else if (shape === 'droplet') { + const count = 48; + for (let i = 0; i < count; i++) { + const u = (i / count) * Math.PI * 2; + const px = 0.82 * Math.sin(u) * Math.sin(u / 2); + const py = -Math.cos(u) * 0.90 - 0.05 * Math.cos(2 * u) + 0.05; + verts.push({ x: px, y: py }); + } + } else if (shape === 'hourglass') { + verts = [ + { x: -0.80, y: -0.92 }, + { x: 0.80, y: -0.92 }, + { x: 0.18, y: 0.0 }, + { x: 0.80, y: 0.92 }, + { x: -0.80, y: 0.92 }, + { x: -0.18, y: 0.0 } + ]; + } else if (shape === 'butterfly') { + verts = [ + { x: 0, y: -0.75 }, + { x: 0.22, y: -0.68 }, + { x: 0.62, y: -0.88 }, + { x: 0.95, y: -0.48 }, + { x: 0.72, y: -0.10 }, + { x: 0.38, y: -0.02 }, + { x: 0.78, y: 0.35 }, + { x: 0.55, y: 0.72 }, + { x: 0.20, y: 0.62 }, + { x: 0, y: 0.82 }, + { x: -0.20, y: 0.62 }, + { x: -0.55, y: 0.72 }, + { x: -0.78, y: 0.35 }, + { x: -0.38, y: -0.02 }, + { x: -0.72, y: -0.10 }, + { x: -0.95, y: -0.48 }, + { x: -0.62, y: -0.88 }, + { x: -0.22, y: -0.68 } + ]; + } else if (shape === 'hexagram') { + const n = 6; + const step = Math.PI / n; + const start = -Math.PI / 2; + for (let i = 0; i < n * 2; i++) { + const r = (i % 2 === 0) ? 1.0 : 0.577; + const a = start + i * step; + verts.push({ x: Math.cos(a) * r, y: Math.sin(a) * r }); + } } SHAPE_VERTICES_CACHE[shape] = verts; diff --git a/public/index.html b/public/index.html index bfe4f73..43cdcc2 100644 --- a/public/index.html +++ b/public/index.html @@ -371,6 +371,104 @@ Blume + + + + + + + + + + + + + + diff --git a/public/presets/metal_lightning.json b/public/presets/metal_lightning.json new file mode 100644 index 0000000..0dedd9d --- /dev/null +++ b/public/presets/metal_lightning.json @@ -0,0 +1,81 @@ +{ + "name": "Heavy Metal Lightning", + "icon": "⚑", + "shapeType": "lightning", + "showCover": true, + "coverShape": "circle", + "circleRadius": 160, + "pulseIntensity": 0.65, + "pulseDecay": 0.82, + "showBorder": true, + "borderWidth": 4, + "borderColor": "#ffcc00", + "showProgressRing": true, + "progressRingColor": "#ff2200", + "progressRingWidth": 4, + "rotationSpeed": 0.8, + "beatSpinImpulse": true, + "showSpectrum": true, + "spectrumMode": "radial_bars", + "linearAlignment": "center_mirrored", + "barCount": 96, + "spectrumMaxHeight": 150, + "barWidth": 4, + "barSpacing": 8, + "barCornerRadius": 1, + "freqSensitivity": 1.4, + "freqFocus": "bass_heavy", + "mirrorSpectrum": true, + "stereoSplit": true, + "stereoMode": "split_hemisphere", + "routePulse": "sub_bass", + "routeParticles": "treble", + "routeShake": "sub_bass", + "bpmSync": false, + "bpmValue": 140, + "bpmSyncRotation": false, + "bpmSyncGrid": false, + "enableParticles": true, + "particleType": "sparks", + "particleCount": 120, + "particleSpeed": 1.4, + "particleWarp": 2.0, + "enableGrid": true, + "colorGrid": "#ff3300", + "gridPerspective": 0.7, + "gridAudioReactive": 0.6, + "enableShake": true, + "camShakeIntensity": 0.45, + "enableGlitch": true, + "rgbSplitIntensity": 0.25, + "beatFlash": true, + "enableBassZoom": true, + "enableVhs": false, + "vhsScanlineIntensity": 0.2, + "vhsNoiseIntensity": 0.1, + "vhsCrtCurvature": false, + "enableAfterglow": true, + "afterglowDecay": 0.75, + "afterglowMode": "fire_amber", + "colorMode": "gradient_3", + "colorGrad1": "#ffcc00", + "colorGrad2": "#ff3300", + "colorGrad3": "#990000", + "colorParticle": "#ffea88", + "gradientStyle": "angular", + "enableGlow": true, + "glowIntensity": 0.9, + "glowBlur": 28, + "laserCore": true, + "backgroundMode": "transparent", + "showTextOverlay": true, + "fontFamily": "'Outfit', sans-serif", + "textPosition": "below_circle", + "titleFontSize": 40, + "artistFontSize": 24, + "textPulseWithBeat": true, + "textGlow": true, + "titleColor": "#ffffff", + "artistColor": "#ffcc00", + "timecodeColor": "#ff4422" +} diff --git a/public/presets/midnight_crescent.json b/public/presets/midnight_crescent.json new file mode 100644 index 0000000..7f8a7e5 --- /dev/null +++ b/public/presets/midnight_crescent.json @@ -0,0 +1,81 @@ +{ + "name": "Midnight Crescent", + "icon": "πŸŒ™", + "shapeType": "crescent", + "showCover": true, + "coverShape": "circle", + "circleRadius": 155, + "pulseIntensity": 0.45, + "pulseDecay": 0.85, + "showBorder": true, + "borderWidth": 4, + "borderColor": "#00f0ff", + "showProgressRing": true, + "progressRingColor": "#bd00ff", + "progressRingWidth": 4, + "rotationSpeed": 0.6, + "beatSpinImpulse": false, + "showSpectrum": true, + "spectrumMode": "smooth_wave", + "linearAlignment": "center_mirrored", + "barCount": 120, + "spectrumMaxHeight": 120, + "barWidth": 3, + "barSpacing": 6, + "barCornerRadius": 2, + "freqSensitivity": 1.2, + "freqFocus": "flat", + "mirrorSpectrum": true, + "stereoSplit": true, + "stereoMode": "split_hemisphere", + "routePulse": "sub_bass", + "routeParticles": "treble", + "routeShake": "sub_bass", + "bpmSync": false, + "bpmValue": 90, + "bpmSyncRotation": false, + "bpmSyncGrid": false, + "enableParticles": true, + "particleType": "starfield", + "particleCount": 130, + "particleSpeed": 0.8, + "particleWarp": 1.8, + "enableGrid": true, + "colorGrid": "#6b11ff", + "gridPerspective": 0.6, + "gridAudioReactive": 0.4, + "enableShake": false, + "camShakeIntensity": 0.2, + "enableGlitch": false, + "rgbSplitIntensity": 0.15, + "beatFlash": false, + "enableBassZoom": true, + "enableVhs": false, + "vhsScanlineIntensity": 0.2, + "vhsNoiseIntensity": 0.1, + "vhsCrtCurvature": false, + "enableAfterglow": true, + "afterglowDecay": 0.82, + "afterglowMode": "magenta_dream", + "colorMode": "gradient_3", + "colorGrad1": "#00f0ff", + "colorGrad2": "#a020f0", + "colorGrad3": "#ff007f", + "colorParticle": "#aae7ff", + "gradientStyle": "angular", + "enableGlow": true, + "glowIntensity": 0.85, + "glowBlur": 26, + "laserCore": true, + "backgroundMode": "transparent", + "showTextOverlay": true, + "fontFamily": "'Outfit', sans-serif", + "textPosition": "below_circle", + "titleFontSize": 38, + "artistFontSize": 22, + "textPulseWithBeat": true, + "textGlow": true, + "titleColor": "#ffffff", + "artistColor": "#00f0ff", + "timecodeColor": "#ff007f" +}