Files
fraxle f22833ee63 2.8
Animated sunscope with day cycle
2026-06-06 14:49:56 +01:00

113 lines
6.9 KiB
JavaScript

// ------------------------------------------------------------------------
// lens-overlay.js - Returns an SVG string for the event overlay inside
// the big ScopeReticle.
//
// Rendered INSIDE the lens clip path, BELOW the glass shine/shade layers.
// cx, cy = lens centre coords; lensR = lens radius.
//
// To add a new overlay for an event: add another 'if (...)' block below
// that matches by event.emoji or event.id and returns an SVG fragment
// string. Return null when no overlay applies.
// ------------------------------------------------------------------------
export function getLensOverlaySVG(event, cx, cy, lensR) {
if (!event) return null;
const id = event.id;
if (event.emoji === '☄️') {
return [
'<g opacity="0.55" clip-path="url(#scope-lens-clip)">',
'<line x1="' + (cx-60) + '" y1="' + (cy-50) + '" x2="' + (cx-20) + '" y2="' + (cy-20) + '" stroke="#ffe8a0" stroke-width="1.5" stroke-linecap="round" opacity="0.9"/>',
'<line x1="' + (cx-40) + '" y1="' + (cy-70) + '" x2="' + (cx+5) + '" y2="' + (cy-30) + '" stroke="#fff0c0" stroke-width="1" stroke-linecap="round" opacity="0.7"/>',
'<line x1="' + (cx+30) + '" y1="' + (cy-60) + '" x2="' + (cx+65) + '" y2="' + (cy-25) + '" stroke="#ffe8a0" stroke-width="1.8" stroke-linecap="round" opacity="0.8"/>',
'<line x1="' + (cx-10) + '" y1="' + (cy-40) + '" x2="' + (cx+30) + '" y2="' + (cy-5) + '" stroke="#fff0c0" stroke-width="0.9" stroke-linecap="round" opacity="0.65"/>',
'<line x1="' + (cx-70) + '" y1="' + (cy-20) + '" x2="' + (cx-35) + '" y2="' + (cy+10) + '" stroke="#ffe8a0" stroke-width="1.2" stroke-linecap="round" opacity="0.6"/>',
'</g>',
].join('');
}
if (id.includes('solar-eclipse')) {
const cx_ = cx, cy_ = cy - 20;
return '<g clip-path="url(#scope-lens-clip)">'
+ '<radialGradient id="corona-glow" cx="' + cx_ + '" cy="' + cy_ + '" r="38" gradientUnits="userSpaceOnUse">'
+ '<stop offset="0%" stop-color="rgba(255,220,100,0)" />'
+ '<stop offset="55%" stop-color="rgba(255,220,100,0.55)" />'
+ '<stop offset="100%" stop-color="rgba(255,180,40,0)" /></radialGradient>'
+ '<circle cx="' + cx_ + '" cy="' + cy_ + '" r="38" fill="url(#corona-glow)" opacity="0.8" />'
+ '<circle cx="' + cx_ + '" cy="' + cy_ + '" r="18" fill="rgba(5,2,15,0.88)" /></g>';
}
if (id.includes('lunar-eclipse')) {
const cx_ = cx, cy_ = cy - 30;
return '<g clip-path="url(#scope-lens-clip)">'
+ '<radialGradient id="blood-moon-glow" cx="' + cx_ + '" cy="' + cy_ + '" r="30" gradientUnits="userSpaceOnUse">'
+ '<stop offset="0%" stop-color="rgba(180,30,10,0.7)" />'
+ '<stop offset="100%" stop-color="rgba(120,10,5,0)" /></radialGradient>'
+ '<circle cx="' + cx_ + '" cy="' + cy_ + '" r="30" fill="url(#blood-moon-glow)" />'
+ '<circle cx="' + cx_ + '" cy="' + cy_ + '" r="16" fill="rgba(160,25,10,0.75)" />'
+ '<circle cx="' + cx_ + '" cy="' + cy_ + '" r="16" fill="none" stroke="rgba(220,60,20,0.5)" stroke-width="1.5" /></g>';
}
if (event.emoji === '🪐' && event.id.includes('conjunction')) {
return '<g clip-path="url(#scope-lens-clip)" opacity="0.65">'
+ '<circle cx="' + (cx+20) + '" cy="' + (cy-35) + '" r="10" fill="rgba(210,185,130,0.7)" />'
+ '<ellipse cx="' + (cx+20) + '" cy="' + (cy-35) + '" rx="18" ry="4.5" fill="none" stroke="rgba(200,170,100,0.65)" stroke-width="2.5" /></g>';
}
if (event.emoji === '🔴') {
return '<g clip-path="url(#scope-lens-clip)" opacity="0.6">'
+ '<circle cx="' + (cx+30) + '" cy="' + (cy-30) + '" r="7" fill="rgba(200,80,40,0.75)" />'
+ '<circle cx="' + (cx-20) + '" cy="' + (cy-45) + '" r="5" fill="rgba(220,160,80,0.7)" /></g>';
}
if (id === 'stargazing') {
const pts = [[cx-50,cy-55,1.8],[cx+40,cy-65,1.4],[cx-20,cy-70,1.0],[cx+65,cy-40,1.6],[cx-60,cy-30,1.2],[cx+50,cy-55,1.0],[cx-35,cy-45,1.4],[cx+20,cy-50,1.8],[cx-75,cy-50,1.0]];
const dots = pts.map(function(s){return '<circle cx="'+s[0]+'" cy="'+s[1]+'" r="'+s[2]+'" fill="rgba(255,255,255,0.9)" />';}).join('');
return '<g clip-path="url(#scope-lens-clip)" opacity="0.7">' + dots + '</g>';
}
if (id === 'perfect-sunset') {
return '<g clip-path="url(#scope-lens-clip)" opacity="0.5">'
+ '<radialGradient id="sunset-lens-glow" cx="' + cx + '" cy="' + (cy+20) + '" r="' + lensR + '" gradientUnits="userSpaceOnUse">'
+ '<stop offset="0%" stop-color="rgba(255,120,20,0.7)" />'
+ '<stop offset="50%" stop-color="rgba(255,60,10,0.25)" />'
+ '<stop offset="100%" stop-color="rgba(200,20,0,0)" /></radialGradient>'
+ '<circle cx="' + cx + '" cy="' + cy + '" r="' + lensR + '" fill="url(#sunset-lens-glow)" /></g>';
}
if (id === 'heat-spike') {
return '<g clip-path="url(#scope-lens-clip)" opacity="0.35">'
+ '<path d="M ' + (cx-lensR+10) + ' ' + (cy+30) + ' Q ' + (cx-20) + ' ' + (cy+15) + ' ' + (cx+20) + ' ' + (cy+30) + ' Q ' + (cx+60) + ' ' + (cy+45) + ' ' + (cx+lensR-10) + ' ' + (cy+30) + '" fill="none" stroke="rgba(255,120,20,0.6)" stroke-width="2" />'
+ '<path d="M ' + (cx-lensR+10) + ' ' + (cy+45) + ' Q ' + (cx-10) + ' ' + (cy+30) + ' ' + (cx+30) + ' ' + (cy+45) + ' Q ' + (cx+65) + ' ' + (cy+60) + ' ' + (cx+lensR-10) + ' ' + (cy+45) + '" fill="none" stroke="rgba(255,100,10,0.5)" stroke-width="2" /></g>';
}
if (id === 'wet') {
// Rain is now drawn continuously on the scope FX canvas; no static overlay.
return null;
}
if (id === 'wind') {
const wl = [-30,5,40].map(function(y){
return '<path d="M ' + (cx-lensR+12) + ' ' + (cy+y) + ' q 40 -14 80 0 q 30 10 ' + (lensR-10) + ' -2" fill="none" stroke="rgba(170,200,230,0.55)" stroke-width="1.5" stroke-linecap="round" />';
}).join('');
return '<g clip-path="url(#scope-lens-clip)" opacity="0.45">' + wl + '</g>';
}
if (id === 'storm') {
// Driving rain + lightning flashes are drawn on the FX canvas; keep just
// the static forked bolt as the event signifier.
const bolt = '<path d="M ' + (cx+6) + ' ' + (cy-lensR+18) + ' L ' + (cx-14) + ' ' + (cy+8) + ' L ' + (cx-2) + ' ' + (cy+8) + ' L ' + (cx-18) + ' ' + (cy+lensR-14) + ' L ' + (cx+18) + ' ' + (cy-2) + ' L ' + (cx+4) + ' ' + (cy-2) + ' Z" fill="rgba(255,224,120,0.7)" stroke="rgba(255,200,60,0.8)" stroke-width="1" stroke-linejoin="round" />';
return '<g clip-path="url(#scope-lens-clip)" opacity="0.5">' + bolt + '</g>';
}
if (id === 'frost') {
const fc = [[-50,40],[0,55],[50,40],[-30,65],[30,65]].map(function(p){
var dx=p[0], dy=p[1];
return '<g transform="translate(' + (cx+dx) + ',' + (cy+dy) + ')"><line x1="-6" y1="0" x2="6" y2="0" stroke="rgba(180,220,255,0.8)" stroke-width="1" /><line x1="0" y1="-6" x2="0" y2="6" stroke="rgba(180,220,255,0.8)" stroke-width="1" /><line x1="-4" y1="-4" x2="4" y2="4" stroke="rgba(180,220,255,0.7)" stroke-width="0.8" /><line x1="4" y1="-4" x2="-4" y2="4" stroke="rgba(180,220,255,0.7)" stroke-width="0.8" /></g>';
}).join('');
return '<g clip-path="url(#scope-lens-clip)" opacity="0.5">' + fc + '</g>';
}
return null;
}