solar-background 0.1.0

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/src/main.js ADDED
@@ -0,0 +1,1076 @@
1
+ const solarBackgroundStyle = `
2
+ .solar-background-root {
3
+ position: absolute;
4
+ inset: 0;
5
+ width: 100%;
6
+ height: 100%;
7
+ overflow: hidden;
8
+ pointer-events: none;
9
+ z-index: -1;
10
+ background: radial-gradient(circle at top, #07142b 0%, #02040e 42%, #000000 100%);
11
+ font-family: Inter, system-ui, sans-serif;
12
+ }
13
+
14
+ .solar-background-root::before {
15
+ content: '';
16
+ position: absolute;
17
+ inset: 0;
18
+ background: radial-gradient(circle at 20% 20%, rgba(255, 255, 255, 0.08), transparent 22%),
19
+ radial-gradient(circle at 80% 15%, rgba(82, 180, 255, 0.06), transparent 18%),
20
+ radial-gradient(circle at 60% 85%, rgba(249, 237, 173, 0.05), transparent 16%);
21
+ pointer-events: none;
22
+ }
23
+
24
+ .solar-background-root .scene {
25
+ position: absolute;
26
+ inset: 0;
27
+ width: min(90vmin, 760px);
28
+ height: min(90vmin, 760px);
29
+ margin: auto;
30
+ z-index: 3;
31
+ transform-origin: center;
32
+ animation: scene-zoom 20s ease-in-out infinite alternate;
33
+ will-change: transform, opacity;
34
+ backface-visibility: hidden;
35
+ }
36
+
37
+ .solar-background-root .sun {
38
+ position: absolute;
39
+ inset: 50%;
40
+ transform: translate(-50%, -50%);
41
+ width: 120px;
42
+ height: 120px;
43
+ border-radius: 50%;
44
+ background:
45
+ radial-gradient(circle at 38% 32%, #fff9d4 0%, #ffe57d 16%, #ffba3f 34%, #ff8d1d 58%, #e85a0f 80%, #b83006 96%),
46
+ radial-gradient(circle at 62% 55%, rgba(255, 220, 120, 0.94) 0%, rgba(255, 150, 40, 0.78) 28%, rgba(230, 100, 24, 0.5) 62%, transparent 100%);
47
+ box-shadow:
48
+ 0 0 120px rgba(255, 175, 55, 0.96),
49
+ 0 0 240px rgba(255, 135, 20, 0.3),
50
+ inset 0 0 32px rgba(255, 250, 210, 0.92);
51
+ overflow: hidden;
52
+ animation: sun-pulse 4.2s ease-in-out infinite alternate;
53
+ z-index: 6;
54
+ }
55
+
56
+ .solar-background-root .sun::before {
57
+ content: '';
58
+ position: absolute;
59
+ inset: 10%;
60
+ border-radius: 50%;
61
+ background:
62
+ radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.75) 0%, transparent 40%),
63
+ radial-gradient(circle at 50% 55%, rgba(255, 210, 90, 0.45) 0%, transparent 38%),
64
+ radial-gradient(circle at 65% 60%, rgba(255, 160, 45, 0.28) 0%, transparent 45%);
65
+ background-size: 160% 160%;
66
+ filter: blur(3px);
67
+ mix-blend-mode: screen;
68
+ animation: sun-surface 4.6s ease-in-out infinite alternate;
69
+ }
70
+
71
+ .solar-background-root .sun::after {
72
+ content: '';
73
+ position: absolute;
74
+ inset: -22%;
75
+ border-radius: 50%;
76
+ background: conic-gradient(from 0deg, transparent 0deg 10deg, rgba(255, 224, 140, 0.18) 10deg 16deg, transparent 16deg 24deg, rgba(255, 180, 75, 0.13) 24deg 32deg, transparent 32deg 360deg);
77
+ opacity: 0.8;
78
+ filter: blur(14px);
79
+ animation: sun-flares 6.4s linear infinite;
80
+ }
81
+
82
+ .solar-background-root .orbit {
83
+ position: absolute;
84
+ inset: 50%;
85
+ transform: translate(-50%, -50%);
86
+ border: 1px solid rgba(255, 255, 255, 0.12);
87
+ border-radius: 50%;
88
+ z-index: 4;
89
+ }
90
+
91
+ .solar-background-root .orbit-mercury {
92
+ width: 130px;
93
+ height: 130px;
94
+ animation: orbit 4s linear infinite;
95
+ }
96
+
97
+ .solar-background-root .orbit-venus {
98
+ width: 180px;
99
+ height: 180px;
100
+ animation: orbit 7s linear infinite reverse;
101
+ }
102
+
103
+ .solar-background-root .orbit-earth {
104
+ width: 240px;
105
+ height: 240px;
106
+ animation: orbit 10s linear infinite;
107
+ }
108
+
109
+ .solar-background-root .orbit-mars {
110
+ width: 300px;
111
+ height: 300px;
112
+ animation: orbit 16s linear infinite;
113
+ }
114
+
115
+ .solar-background-root .orbit-jupiter {
116
+ width: 380px;
117
+ height: 380px;
118
+ animation: orbit 24s linear infinite;
119
+ }
120
+
121
+ .solar-background-root .orbit-saturn {
122
+ width: 460px;
123
+ height: 460px;
124
+ animation: orbit 32s linear infinite;
125
+ }
126
+
127
+ .solar-background-root .orbit-uranus {
128
+ width: 540px;
129
+ height: 540px;
130
+ animation: orbit 46s linear infinite reverse;
131
+ }
132
+
133
+ .solar-background-root .orbit-neptune {
134
+ width: 620px;
135
+ height: 620px;
136
+ animation: orbit 56s linear infinite;
137
+ }
138
+
139
+ .solar-background-root .orbit-pluto {
140
+ width: 700px;
141
+ height: 700px;
142
+ animation: orbit 68s linear infinite;
143
+ }
144
+
145
+ @keyframes orbit {
146
+ to {
147
+ transform: translate(-50%, -50%) rotate(360deg);
148
+ }
149
+ }
150
+
151
+ .solar-background-root .planet,
152
+ .solar-background-root .moon {
153
+ position: absolute;
154
+ top: 50%;
155
+ right: 0;
156
+ transform: translate(50%, -50%);
157
+ border-radius: 50%;
158
+ background-size: cover;
159
+ background-position: center;
160
+ box-shadow: 0 0 12px rgba(255, 255, 255, 0.08);
161
+ z-index: 5;
162
+ }
163
+
164
+ .solar-background-root .mercury,
165
+ .solar-background-root .venus,
166
+ .solar-background-root .earth,
167
+ .solar-background-root .mars,
168
+ .solar-background-root .jupiter,
169
+ .solar-background-root .saturn,
170
+ .solar-background-root .uranus,
171
+ .solar-background-root .neptune,
172
+ .solar-background-root .pluto {
173
+ width: 16px;
174
+ height: 16px;
175
+ }
176
+
177
+ .solar-background-root .moon {
178
+ width: 8px;
179
+ height: 8px;
180
+ background-color: #ccc;
181
+ }
182
+
183
+ .solar-background-root .mercury {
184
+ width: 14px;
185
+ height: 14px;
186
+ background-image: url('/images/mercury.png');
187
+ }
188
+
189
+ .solar-background-root .venus {
190
+ width: 16px;
191
+ height: 16px;
192
+ background-image: url('/images/venus.png');
193
+ }
194
+
195
+ .solar-background-root .earth {
196
+ width: 22px;
197
+ height: 22px;
198
+ background-image: url('/images/earth.png');
199
+ }
200
+
201
+ .solar-background-root .mars {
202
+ width: 18px;
203
+ height: 18px;
204
+ background-image: url('/images/mars.png');
205
+ }
206
+
207
+ .solar-background-root .jupiter {
208
+ width: 28px;
209
+ height: 28px;
210
+ background-image: url('/images/jupiter.png');
211
+ }
212
+
213
+ .solar-background-root .saturn {
214
+ width: 26px;
215
+ height: 26px;
216
+ background-image: url('/images/saturn.png');
217
+ }
218
+
219
+ .solar-background-root .uranus {
220
+ width: 22px;
221
+ height: 22px;
222
+ background-image: url('/images/uranus.png');
223
+ }
224
+
225
+ .solar-background-root .neptune {
226
+ width: 20px;
227
+ height: 20px;
228
+ background-image: url('/images/neptune.png');
229
+ }
230
+
231
+ .solar-background-root .pluto {
232
+ width: 14px;
233
+ height: 14px;
234
+ background-image: url('/images/pluto.png');
235
+ }
236
+
237
+ .solar-background-root .earth .moon-orbit {
238
+ position: absolute;
239
+ inset: 50%;
240
+ width: 48px;
241
+ height: 48px;
242
+ transform: translate(-50%, -50%);
243
+ border: 1px dashed rgba(255, 255, 255, 0.18);
244
+ border-radius: 50%;
245
+ animation: orbit 3s linear infinite;
246
+ }
247
+
248
+ .solar-background-root .earth .moon {
249
+ right: -6px;
250
+ top: 50%;
251
+ transform: translate(50%, -50%);
252
+ }
253
+
254
+ .solar-background-root .star {
255
+ position: absolute;
256
+ background: rgba(255, 255, 255, 0.85);
257
+ border-radius: 50%;
258
+ pointer-events: none;
259
+ }
260
+
261
+ .solar-background-root .zodiac-layer {
262
+ position: absolute;
263
+ inset: 0;
264
+ pointer-events: none;
265
+ z-index: 1;
266
+ }
267
+
268
+ .solar-background-root .zodiac-sign {
269
+ position: absolute;
270
+ width: var(--solar-card-width, min(34vmin, 360px));
271
+ height: var(--solar-card-height, min(34vmin, 360px));
272
+ padding: var(--solar-card-padding, 2rem);
273
+ opacity: 0;
274
+ pointer-events: none;
275
+ animation: constellation-appear 3.4s ease-in-out forwards;
276
+ transform-origin: center;
277
+ border-radius: var(--solar-card-radius, 24px);
278
+ background: var(--solar-card-bg, transparent);
279
+ border: 1px solid var(--solar-card-border, rgba(255, 255, 255, 0.12));
280
+ box-shadow: var(--solar-card-boxshadow, rgba(0, 0, 0, 0.35) 0px -50px 36px -28px inset);
281
+ will-change: opacity, transform;
282
+ }
283
+
284
+ .solar-background-root .left-sign {
285
+ left: 10%;
286
+ }
287
+
288
+ .solar-background-root .right-sign {
289
+ right: 2%;
290
+ }
291
+
292
+ .solar-background-root .pattern-star {
293
+ position: absolute;
294
+ width: 4px;
295
+ height: 4px;
296
+ border-radius: 50%;
297
+ background: radial-gradient(circle, #ffffff 0%, rgba(255,255,255,0.1) 100%);
298
+ box-shadow: 0 0 16px rgba(255, 255, 255, 0.6);
299
+ }
300
+
301
+ .solar-background-root .pattern-line {
302
+ position: absolute;
303
+ height: 2px;
304
+ background: rgba(255, 255, 255, 0.45);
305
+ box-shadow: 0 0 12px rgba(255, 255, 255, 0.18);
306
+ transform-origin: left center;
307
+ }
308
+
309
+ .solar-background-root .pattern-title {
310
+ position: absolute;
311
+ left: 1rem;
312
+ top: 1rem;
313
+ font-size: 1rem;
314
+ text-transform: uppercase;
315
+ letter-spacing: 0.18em;
316
+ color: rgba(255, 255, 255, 0.92);
317
+ font-weight: 700;
318
+ text-shadow: 0 0 18px rgba(255, 255, 255, 0.15);
319
+ }
320
+
321
+ .solar-background-root .pattern-subtitle {
322
+ position: absolute;
323
+ left: 1rem;
324
+ bottom: var(--pattern-subtitle-bottom, 1rem);
325
+ font-size: var(--pattern-subtitle-size, 0.92rem);
326
+ color: var(--pattern-subtitle-color, rgba(255, 255, 255, 0.76));
327
+ }
328
+
329
+ .solar-background-root .pattern-glyph {
330
+ position: absolute;
331
+ right: 1rem;
332
+ top: 3rem;
333
+ font-size: 2.2rem;
334
+ line-height: 1;
335
+ }
336
+
337
+ .solar-background-root .pattern-pair {
338
+ position: absolute;
339
+ right: 1rem;
340
+ bottom: var(--pattern-pair-bottom, 4rem);
341
+ font-size: var(--pattern-pair-size, 1.1rem);
342
+ color: var(--pattern-pair-color, rgba(255, 255, 255, 0.9));
343
+ letter-spacing: 0.08em;
344
+ }
345
+
346
+ @keyframes constellation-appear {
347
+ 0% {
348
+ opacity: 0;
349
+ transform: translateY(15px) scale(0.96);
350
+ }
351
+ 15% {
352
+ opacity: 1;
353
+ transform: translateY(0) scale(1);
354
+ }
355
+ 85% {
356
+ opacity: 1;
357
+ }
358
+ 100% {
359
+ opacity: 0;
360
+ transform: translateY(-10px) scale(0.96);
361
+ }
362
+ }
363
+
364
+ @keyframes sun-pulse {
365
+ 0% {
366
+ transform: translate(-50%, -50%) scale(1);
367
+ box-shadow:
368
+ 0 0 110px rgba(255, 175, 55, 0.96),
369
+ 0 0 230px rgba(255, 135, 20, 0.3),
370
+ inset 0 0 30px rgba(255, 250, 210, 0.92);
371
+ }
372
+ 50% {
373
+ transform: translate(-50%, -50%) scale(1.02);
374
+ box-shadow:
375
+ 0 0 120px rgba(255, 190, 65, 0.96),
376
+ 0 0 250px rgba(255, 140, 25, 0.32),
377
+ inset 0 0 34px rgba(255, 255, 220, 0.94);
378
+ }
379
+ 100% {
380
+ transform: translate(-50%, -50%) scale(1);
381
+ box-shadow:
382
+ 0 0 110px rgba(255, 175, 55, 0.96),
383
+ 0 0 230px rgba(255, 135, 20, 0.3),
384
+ inset 0 0 30px rgba(255, 250, 210, 0.92);
385
+ }
386
+ }
387
+
388
+ @keyframes sun-surface {
389
+ 0% {
390
+ background-position: 0% 0%;
391
+ opacity: 1;
392
+ }
393
+ 50% {
394
+ background-position: 40% 45%;
395
+ opacity: 0.92;
396
+ }
397
+ 100% {
398
+ background-position: 0% 15%;
399
+ opacity: 1;
400
+ }
401
+ }
402
+
403
+ @keyframes sun-flares {
404
+ from {
405
+ transform: rotate(0deg);
406
+ opacity: 0.82;
407
+ }
408
+ to {
409
+ transform: rotate(360deg);
410
+ opacity: 0.68;
411
+ }
412
+ }
413
+
414
+ @keyframes scene-zoom {
415
+ 0% {
416
+ transform: scale(1) translateZ(0);
417
+ }
418
+ 100% {
419
+ transform: scale(1.08) translateZ(0);
420
+ }
421
+ }
422
+ `
423
+
424
+ const zodiacAnimalConstellations = [
425
+ {
426
+ zodiac: 'Sagittarius',
427
+ animal: 'Rat',
428
+ traits: ['Deeply curious', 'Highly sociable', 'Quick-witted', 'Freedom-loving'],
429
+ zodiacStars: [
430
+ { id: 'S1', x: 40, y: 30, name: 'Kaus Media' },
431
+ { id: 'S2', x: 45, y: 45, name: 'Kaus Australis' },
432
+ { id: 'S3', x: 55, y: 50, name: 'Ascella' },
433
+ { id: 'S4', x: 60, y: 35, name: 'Nunki' },
434
+ { id: 'S5', x: 50, y: 25, name: 'Kaus Borealis' },
435
+ { id: 'S6', x: 30, y: 25, name: 'Alnasl' },
436
+ ],
437
+ zodiacLines: [
438
+ ['S1', 'S2'],
439
+ ['S2', 'S3'],
440
+ ['S3', 'S4'],
441
+ ['S4', 'S5'],
442
+ ['S5', 'S1'],
443
+ ['S1', 'S6'],
444
+ ['S2', 'S5'],
445
+ ],
446
+ animalStars: [
447
+ { id: 'R1', x: 20, y: 70, name: 'Snout' },
448
+ { id: 'R2', x: 35, y: 60, name: 'Head' },
449
+ { id: 'R3', x: 30, y: 45, name: 'Ear' },
450
+ { id: 'R4', x: 55, y: 65, name: 'Body' },
451
+ { id: 'R5', x: 75, y: 75, name: 'Tail Base' },
452
+ { id: 'R6', x: 90, y: 60, name: 'Tail Tip' },
453
+ ],
454
+ animalLines: [
455
+ ['R1', 'R2'],
456
+ ['R2', 'R3'],
457
+ ['R3', 'R2'],
458
+ ['R2', 'R4'],
459
+ ['R4', 'R5'],
460
+ ['R5', 'R6'],
461
+ ],
462
+ },
463
+ {
464
+ zodiac: 'Capricorn',
465
+ animal: 'Ox',
466
+ traits: ['Hardworking', 'Methodical', 'Disciplined', 'Stable'],
467
+ zodiacStars: [
468
+ { id: 'C1', x: 20, y: 30, name: 'Algedi' },
469
+ { id: 'C2', x: 25, y: 35, name: 'Dabih' },
470
+ { id: 'C3', x: 45, y: 60, name: 'Rucha' },
471
+ { id: 'C4', x: 70, y: 50, name: 'Nashira' },
472
+ { id: 'C5', x: 75, y: 45, name: 'Deneb Algedi' },
473
+ ],
474
+ zodiacLines: [
475
+ ['C1', 'C2'],
476
+ ['C2', 'C3'],
477
+ ['C3', 'C4'],
478
+ ['C4', 'C5'],
479
+ ['C5', 'C1'],
480
+ ],
481
+ animalStars: [
482
+ { id: 'O1', x: 25, y: 35, name: 'Left Horn' },
483
+ { id: 'O2', x: 40, y: 45, name: 'Head' },
484
+ { id: 'O3', x: 55, y: 35, name: 'Right Horn' },
485
+ { id: 'O4', x: 40, y: 65, name: 'Front Legs' },
486
+ { id: 'O5', x: 70, y: 60, name: 'Back' },
487
+ { id: 'O6', x: 75, y: 75, name: 'Hind Legs' },
488
+ ],
489
+ animalLines: [
490
+ ['O1', 'O2'],
491
+ ['O3', 'O2'],
492
+ ['O2', 'O4'],
493
+ ['O2', 'O5'],
494
+ ['O5', 'O6'],
495
+ ],
496
+ },
497
+ {
498
+ zodiac: 'Aquarius',
499
+ animal: 'Tiger',
500
+ traits: ['Fiercely independent', 'Natural leader', 'Unpredictable'],
501
+ zodiacStars: [
502
+ { id: 'AQ1', x: 30, y: 20, name: 'Sadalmelik' },
503
+ { id: 'AQ2', x: 45, y: 30, name: 'Sadalsuud' },
504
+ { id: 'AQ3', x: 40, y: 50, name: 'Ancha' },
505
+ { id: 'AQ4', x: 60, y: 65, name: 'Skat' },
506
+ ],
507
+ zodiacLines: [
508
+ ['AQ1', 'AQ2'],
509
+ ['AQ2', 'AQ3'],
510
+ ['AQ3', 'AQ4'],
511
+ ],
512
+ animalStars: [
513
+ { id: 'T1', x: 20, y: 40, name: 'Jaw' },
514
+ { id: 'T2', x: 35, y: 30, name: 'Crown' },
515
+ { id: 'T3', x: 50, y: 45, name: 'Shoulder' },
516
+ { id: 'T4', x: 45, y: 70, name: 'Forepaw' },
517
+ { id: 'T5', x: 70, y: 50, name: 'Spine' },
518
+ { id: 'T6', x: 85, y: 35, name: 'Tail' },
519
+ ],
520
+ animalLines: [
521
+ ['T1', 'T2'],
522
+ ['T2', 'T3'],
523
+ ['T3', 'T4'],
524
+ ['T3', 'T5'],
525
+ ['T5', 'T6'],
526
+ ],
527
+ },
528
+ {
529
+ zodiac: 'Pisces',
530
+ animal: 'Rabbit',
531
+ traits: ['Gentle', 'Highly sensitive', 'Artistic', 'Peace-loving'],
532
+ zodiacStars: [
533
+ { id: 'P1', x: 20, y: 20, name: 'Alpherg' },
534
+ { id: 'P2', x: 40, y: 40, name: 'Baten Kaitos' },
535
+ { id: 'P3', x: 60, y: 60, name: 'Alrescha' },
536
+ { id: 'P4', x: 75, y: 45, name: 'Fumalsamakah' },
537
+ ],
538
+ zodiacLines: [
539
+ ['P1', 'P2'],
540
+ ['P2', 'P3'],
541
+ ['P3', 'P4'],
542
+ ],
543
+ animalStars: [
544
+ { id: 'RB1', x: 30, y: 25, name: 'Ear Tip 1' },
545
+ { id: 'RB2', x: 35, y: 25, name: 'Ear Tip 2' },
546
+ { id: 'RB3', x: 33, y: 40, name: 'Head' },
547
+ { id: 'RB4', x: 20, y: 45, name: 'Nose' },
548
+ { id: 'RB5', x: 55, y: 50, name: 'Spine' },
549
+ { id: 'RB6', x: 70, y: 60, name: 'Tail' },
550
+ ],
551
+ animalLines: [
552
+ ['RB1', 'RB3'],
553
+ ['RB2', 'RB3'],
554
+ ['RB4', 'RB3'],
555
+ ['RB3', 'RB5'],
556
+ ['RB5', 'RB6'],
557
+ ],
558
+ },
559
+ {
560
+ zodiac: 'Aries',
561
+ animal: 'Dragon',
562
+ traits: ['Bold', 'Fiercely confident', 'Passionate', 'Dynamic'],
563
+ zodiacStars: [
564
+ { id: 'A1', x: 30, y: 30, name: 'Hamal' },
565
+ { id: 'A2', x: 55, y: 40, name: 'Sheratan' },
566
+ { id: 'A3', x: 70, y: 55, name: 'Mesarthim' },
567
+ ],
568
+ zodiacLines: [
569
+ ['A1', 'A2'],
570
+ ['A2', 'A3'],
571
+ ],
572
+ animalStars: [
573
+ { id: 'D1', x: 20, y: 30, name: 'Dragon Horn' },
574
+ { id: 'D2', x: 30, y: 45, name: 'Head' },
575
+ { id: 'D3', x: 45, y: 40, name: 'Neck Crest' },
576
+ { id: 'D4', x: 55, y: 60, name: 'Body Coil' },
577
+ { id: 'D5', x: 75, y: 55, name: 'Lower Tail' },
578
+ { id: 'D6', x: 85, y: 70, name: 'Tail Flare' },
579
+ ],
580
+ animalLines: [
581
+ ['D1', 'D2'],
582
+ ['D2', 'D3'],
583
+ ['D3', 'D4'],
584
+ ['D4', 'D5'],
585
+ ['D5', 'D6'],
586
+ ],
587
+ },
588
+ {
589
+ zodiac: 'Virgo',
590
+ animal: 'Snake',
591
+ traits: ['Deeply analytical', 'Wise', 'Perfectionistic', 'Private'],
592
+ zodiacStars: [
593
+ { id: 'V1', x: 30, y: 25, name: 'Zavijava' },
594
+ { id: 'V2', x: 40, y: 40, name: 'Porrima' },
595
+ { id: 'V3', x: 55, y: 45, name: 'Spica' },
596
+ { id: 'V4', x: 70, y: 35, name: 'Heze' },
597
+ { id: 'V5', x: 65, y: 20, name: 'Vindemiatrix' },
598
+ ],
599
+ zodiacLines: [
600
+ ['V1', 'V2'],
601
+ ['V2', 'V3'],
602
+ ['V3', 'V4'],
603
+ ['V4', 'V5'],
604
+ ['V2', 'V5'],
605
+ ],
606
+ animalStars: [
607
+ { id: 'SN1', x: 30, y: 30, name: 'Head' },
608
+ { id: 'SN2', x: 45, y: 35, name: 'Upper Coil' },
609
+ { id: 'SN3', x: 40, y: 55, name: 'Middle Body' },
610
+ { id: 'SN4', x: 60, y: 60, name: 'Lower Coil' },
611
+ { id: 'SN5', x: 75, y: 45, name: 'Tail Tip' },
612
+ ],
613
+ animalLines: [
614
+ ['SN1', 'SN2'],
615
+ ['SN2', 'SN3'],
616
+ ['SN3', 'SN4'],
617
+ ['SN4', 'SN5'],
618
+ ],
619
+ },
620
+ {
621
+ zodiac: 'Gemini',
622
+ animal: 'Horse',
623
+ traits: ['Energetic', 'Highly adaptable', 'Talkative', 'Restless'],
624
+ zodiacStars: [
625
+ { id: 'G1', x: 30, y: 25, name: 'Castor' },
626
+ { id: 'G2', x: 35, y: 30, name: 'Pollux' },
627
+ { id: 'G3', x: 55, y: 50, name: 'Mebsuta' },
628
+ { id: 'G4', x: 60, y: 55, name: 'Alhena' },
629
+ ],
630
+ zodiacLines: [
631
+ ['G1', 'G3'],
632
+ ['G2', 'G4'],
633
+ ['G1', 'G2'],
634
+ ['G3', 'G4'],
635
+ ],
636
+ animalStars: [
637
+ { id: 'H1', x: 25, y: 30, name: 'Mane' },
638
+ { id: 'H2', x: 40, y: 35, name: 'Chest' },
639
+ { id: 'H3', x: 35, y: 65, name: 'Front Hoof' },
640
+ { id: 'H4', x: 65, y: 40, name: 'Flank' },
641
+ { id: 'H5', x: 75, y: 70, name: 'Rear Hoof' },
642
+ ],
643
+ animalLines: [
644
+ ['H1', 'H2'],
645
+ ['H2', 'H3'],
646
+ ['H2', 'H4'],
647
+ ['H4', 'H5'],
648
+ ],
649
+ },
650
+ {
651
+ zodiac: 'Cancer',
652
+ animal: 'Goat',
653
+ traits: ['Nurturing', 'Family-oriented', 'Creative', 'Emotional'],
654
+ zodiacStars: [
655
+ { id: 'CN1', x: 50, y: 20, name: 'Tegmine' },
656
+ { id: 'CN2', x: 50, y: 45, name: 'Asellus Borealis' },
657
+ { id: 'CN3', x: 35, y: 70, name: 'Acubens' },
658
+ { id: 'CN4', x: 65, y: 70, name: 'Altarf' },
659
+ ],
660
+ zodiacLines: [
661
+ ['CN1', 'CN2'],
662
+ ['CN2', 'CN3'],
663
+ ['CN2', 'CN4'],
664
+ ],
665
+ animalStars: [
666
+ { id: 'GT1', x: 35, y: 25, name: 'Left Horn' },
667
+ { id: 'GT2', x: 45, y: 35, name: 'Head' },
668
+ { id: 'GT3', x: 40, y: 60, name: 'Front Leg' },
669
+ { id: 'GT4', x: 65, y: 45, name: 'Torso' },
670
+ { id: 'GT5', x: 70, y: 65, name: 'Back Leg' },
671
+ ],
672
+ animalLines: [
673
+ ['GT1', 'GT2'],
674
+ ['GT2', 'GT3'],
675
+ ['GT2', 'GT4'],
676
+ ['GT4', 'GT5'],
677
+ ],
678
+ },
679
+ {
680
+ zodiac: 'Leo',
681
+ animal: 'Monkey',
682
+ traits: ['Energetic', 'Charismatic', 'Confident', 'Center of attention'],
683
+ zodiacStars: [
684
+ { id: 'L1', x: 35, y: 30, name: 'Algieba' },
685
+ { id: 'L2', x: 30, y: 45, name: 'Regulus' },
686
+ { id: 'L3', x: 55, y: 45, name: 'Chertan' },
687
+ { id: 'L4', x: 70, y: 35, name: 'Denebola' },
688
+ ],
689
+ zodiacLines: [
690
+ ['L1', 'L2'],
691
+ ['L2', 'L3'],
692
+ ['L3', 'L4'],
693
+ ['L4', 'L1'],
694
+ ],
695
+ animalStars: [
696
+ { id: 'M1', x: 30, y: 35, name: 'Crown Head' },
697
+ { id: 'M2', x: 45, y: 45, name: 'Shoulders' },
698
+ { id: 'M3', x: 35, y: 65, name: 'Reaching Arm' },
699
+ { id: 'M4', x: 65, y: 50, name: 'Hips' },
700
+ { id: 'M5', x: 80, y: 30, name: 'Curled Tail' },
701
+ ],
702
+ animalLines: [
703
+ ['M1', 'M2'],
704
+ ['M2', 'M3'],
705
+ ['M2', 'M4'],
706
+ ['M4', 'M5'],
707
+ ],
708
+ },
709
+ {
710
+ zodiac: 'Taurus',
711
+ animal: 'Rooster',
712
+ traits: ['Highly practical', 'Grounded', 'Fiercely loyal', 'Detail-oriented'],
713
+ zodiacStars: [
714
+ { id: 'TA1', x: 25, y: 25, name: 'El???' },
715
+ { id: 'TA2', x: 45, y: 40, name: 'Aldebaran' },
716
+ { id: 'TA3', x: 65, y: 55, name: 'Ain' },
717
+ { id: 'TA4', x: 35, y: 60, name: 'Alcyone (Pleiades)' },
718
+ ],
719
+ zodiacLines: [
720
+ ['TA1', 'TA2'],
721
+ ['TA2', 'TA3'],
722
+ ['TA2', 'TA4'],
723
+ ],
724
+ animalStars: [
725
+ { id: 'RS1', x: 25, y: 35, name: 'Beak' },
726
+ { id: 'RS2', x: 35, y: 25, name: 'Comb' },
727
+ { id: 'RS3', x: 45, y: 45, name: 'Breast' },
728
+ { id: 'RS4', x: 65, y: 35, name: 'Feather Plume' },
729
+ { id: 'RS5', x: 50, y: 65, name: 'Spur/Leg' },
730
+ ],
731
+ animalLines: [
732
+ ['RS1', 'RS3'],
733
+ ['RS2', 'RS3'],
734
+ ['RS3', 'RS4'],
735
+ ['RS3', 'RS5'],
736
+ ],
737
+ },
738
+ {
739
+ zodiac: 'Libra',
740
+ animal: 'Dog',
741
+ traits: ['Driven by justice', 'Fair play', 'Extreme loyalty'],
742
+ zodiacStars: [
743
+ { id: 'LB1', x: 45, y: 25, name: 'Zubeneschamali' },
744
+ { id: 'LB2', x: 35, y: 45, name: 'Zubenelgenubi' },
745
+ { id: 'LB3', x: 60, y: 50, name: 'Zubenelhakrabi' },
746
+ ],
747
+ zodiacLines: [
748
+ ['LB1', 'LB2'],
749
+ ['LB1', 'LB3'],
750
+ ['LB2', 'LB3'],
751
+ ],
752
+ animalStars: [
753
+ { id: 'DG1', x: 25, y: 40, name: 'Muzzle' },
754
+ { id: 'DG2', x: 40, y: 35, name: 'Perked Ear' },
755
+ { id: 'DG3', x: 45, y: 55, name: 'Front Paw' },
756
+ { id: 'DG4', x: 65, y: 50, name: 'Rump' },
757
+ { id: 'DG5', x: 80, y: 40, name: 'Alert Tail' },
758
+ ],
759
+ animalLines: [
760
+ ['DG1', 'DG2'],
761
+ ['DG2', 'DG3'],
762
+ ['DG2', 'DG4'],
763
+ ['DG4', 'DG5'],
764
+ ],
765
+ },
766
+ {
767
+ zodiac: 'Scorpius',
768
+ animal: 'Pig',
769
+ traits: ['Intense', 'Deeply passionate', 'Luxurious', 'Emotional inner world'],
770
+ zodiacStars: [
771
+ { id: 'SC1', x: 25, y: 30, name: 'Dschubba' },
772
+ { id: 'SC2', x: 40, y: 35, name: 'Antares' },
773
+ { id: 'SC3', x: 55, y: 55, name: 'Shaula' },
774
+ { id: 'SC4', x: 70, y: 70, name: 'Lesath' },
775
+ ],
776
+ zodiacLines: [
777
+ ['SC1', 'SC2'],
778
+ ['SC2', 'SC3'],
779
+ ['SC3', 'SC4'],
780
+ ],
781
+ animalStars: [
782
+ { id: 'PG1', x: 25, y: 50, name: 'Snout' },
783
+ { id: 'PG2', x: 40, y: 40, name: 'Head/Ear' },
784
+ { id: 'PG3', x: 60, y: 45, name: 'Round Flank' },
785
+ { id: 'PG4', x: 45, y: 65, name: 'Plump Leg' },
786
+ { id: 'PG5', x: 75, y: 40, name: 'Curly Tail' },
787
+ ],
788
+ animalLines: [
789
+ ['PG1', 'PG2'],
790
+ ['PG2', 'PG3'],
791
+ ['PG2', 'PG4'],
792
+ ['PG3', 'PG5'],
793
+ ],
794
+ },
795
+ ]
796
+
797
+ const zodiacGlyphMap = {
798
+ Aries: '♈',
799
+ Taurus: '♉',
800
+ Gemini: '♊',
801
+ Cancer: '♋',
802
+ Leo: '♌',
803
+ Virgo: '♍',
804
+ Libra: '♎',
805
+ Scorpio: '♏',
806
+ Sagittarius: '♐',
807
+ Capricorn: '♑',
808
+ Aquarius: '♒',
809
+ Pisces: '♓',
810
+ }
811
+
812
+ const animalGlyphMap = {
813
+ Rat: '🐀',
814
+ Ox: '🐂',
815
+ Tiger: '🐅',
816
+ Rabbit: '🐇',
817
+ Dragon: '🐉',
818
+ Snake: '🐍',
819
+ Horse: '🐎',
820
+ Goat: '🐐',
821
+ Monkey: '🐒',
822
+ Rooster: '🐓',
823
+ Dog: '🐕',
824
+ Pig: '🐖',
825
+ }
826
+
827
+ const instanceMap = new WeakMap()
828
+
829
+ function injectStyle() {
830
+ if (document.getElementById('solar-background-style')) {
831
+ return
832
+ }
833
+
834
+ const styleElement = document.createElement('style')
835
+ styleElement.id = 'solar-background-style'
836
+ styleElement.textContent = solarBackgroundStyle
837
+ document.head.appendChild(styleElement)
838
+ }
839
+
840
+ function createSceneMarkup() {
841
+ return `
842
+ <div class="scene">
843
+ <div class="sun"></div>
844
+ <div class="orbit orbit-mercury"><div class="planet mercury"></div></div>
845
+ <div class="orbit orbit-venus"><div class="planet venus"></div></div>
846
+ <div class="orbit orbit-earth">
847
+ <div class="planet earth">
848
+ <div class="moon-orbit"><div class="moon"></div></div>
849
+ </div>
850
+ </div>
851
+ <div class="orbit orbit-mars"><div class="planet mars"></div></div>
852
+ <div class="orbit orbit-jupiter"><div class="planet jupiter"></div></div>
853
+ <div class="orbit orbit-saturn"><div class="planet saturn"></div></div>
854
+ <div class="orbit orbit-uranus"><div class="planet uranus"></div></div>
855
+ <div class="orbit orbit-neptune"><div class="planet neptune"></div></div>
856
+ <div class="orbit orbit-pluto"><div class="planet pluto"></div></div>
857
+ </div>
858
+ <div class="zodiac-layer"></div>
859
+ `
860
+ }
861
+
862
+ function createStars(root, starCount = 12260) {
863
+ for (let i = 0; i < starCount; i++) {
864
+ const star = document.createElement('span')
865
+ star.className = 'star'
866
+ const size = Math.random() * 1 + 0.8
867
+ star.style.width = `${size}px`
868
+ star.style.height = `${size}px`
869
+ star.style.top = `${Math.random() * 100}%`
870
+ star.style.left = `${Math.random() * 100}%`
871
+ star.style.opacity = `${Math.random() * 0.6 + 0.2}`
872
+ star.style.transform = 'translate(-50%, -50%)'
873
+ root.appendChild(star)
874
+ }
875
+ }
876
+
877
+ function createPatternCard(root, data, type, side, cycleDuration) {
878
+ const zodiacLayer = root.querySelector('.zodiac-layer')
879
+ if (!zodiacLayer) return
880
+
881
+ const patternStars = type === 'zodiac' ? data.zodiacStars : data.animalStars
882
+ const patternLines = type === 'zodiac' ? data.zodiacLines : data.animalLines
883
+
884
+ const card = document.createElement('div')
885
+ card.className = `zodiac-sign ${type}-sign ${side}-sign`
886
+ card.style.top = `${Math.random() * 34 + 10}%`
887
+
888
+ const title = document.createElement('div')
889
+ title.className = 'pattern-title'
890
+ title.textContent = type === 'zodiac' ? `${data.zodiac} Constellation` : `${data.animal} Pattern`
891
+ card.appendChild(title)
892
+
893
+ const subtitle = document.createElement('div')
894
+ subtitle.className = 'pattern-subtitle'
895
+ subtitle.textContent = type === 'zodiac' ? data.traits.join(' • ') : `Animal: ${data.animal}`
896
+ card.appendChild(subtitle)
897
+
898
+ const glyph = document.createElement('div')
899
+ glyph.className = 'pattern-glyph'
900
+ glyph.textContent = type === 'zodiac' ? zodiacGlyphMap[data.zodiac] : animalGlyphMap[data.animal] || data.animal
901
+ card.appendChild(glyph)
902
+
903
+ const pair = document.createElement('div')
904
+ pair.className = 'pattern-pair'
905
+ pair.textContent = type === 'zodiac' ? data.animal : data.zodiac
906
+ card.appendChild(pair)
907
+
908
+ zodiacLayer.appendChild(card)
909
+
910
+ const rect = card.getBoundingClientRect()
911
+ const w = rect.width
912
+ const h = rect.height
913
+ const starMap = new Map(patternStars.map((star) => [star.id, star]))
914
+
915
+ patternStars.forEach((star) => {
916
+ const mark = document.createElement('span')
917
+ mark.className = 'pattern-star'
918
+ mark.style.left = `${star.x}%`
919
+ mark.style.top = `${star.y}%`
920
+ card.appendChild(mark)
921
+ })
922
+
923
+ patternLines.forEach(([a, b]) => {
924
+ const from = starMap.get(a)
925
+ const to = starMap.get(b)
926
+ if (!from || !to) return
927
+
928
+ const x1 = (from.x / 100) * w
929
+ const y1 = (from.y / 100) * h
930
+ const x2 = (to.x / 100) * w
931
+ const y2 = (to.y / 100) * h
932
+ const dx = x2 - x1
933
+ const dy = y2 - y1
934
+ const line = document.createElement('span')
935
+ line.className = 'pattern-line'
936
+ line.style.width = `${Math.sqrt(dx * dx + dy * dy)}px`
937
+ line.style.left = `${x1}px`
938
+ line.style.top = `${y1}px`
939
+ line.style.transform = `rotate(${Math.atan2(dy, dx)}rad)`
940
+ card.appendChild(line)
941
+ })
942
+
943
+ setTimeout(() => {
944
+ if (zodiacLayer.contains(card)) zodiacLayer.removeChild(card)
945
+ }, cycleDuration - 300)
946
+ }
947
+
948
+ function shuffle(array) {
949
+ for (let i = array.length - 1; i > 0; i--) {
950
+ const j = Math.floor(Math.random() * (i + 1))
951
+ ;[array[i], array[j]] = [array[j], array[i]]
952
+ }
953
+ return array
954
+ }
955
+
956
+ function showNextZodiacAnimalPair(root, cycleDuration = 4200, animalDelay = 1400) {
957
+ const meta = instanceMap.get(root) || {}
958
+ let order = meta.order
959
+ let idx = typeof meta.index === 'number' ? meta.index : 0
960
+
961
+ if (!order || !order.length) {
962
+ order = shuffle(Array.from({ length: zodiacAnimalConstellations.length }, (_, i) => i))
963
+ idx = 0
964
+ }
965
+
966
+ const data = zodiacAnimalConstellations[order[idx]]
967
+ createPatternCard(root, data, 'zodiac', 'left', cycleDuration)
968
+ setTimeout(() => createPatternCard(root, data, 'animal', 'right', cycleDuration), animalDelay)
969
+
970
+ idx++
971
+ if (idx >= order.length) {
972
+ order = shuffle(order.slice())
973
+ idx = 0
974
+ }
975
+
976
+ instanceMap.set(root, { ...meta, order, index: idx, interval: meta.interval })
977
+ }
978
+
979
+ function createSolarBackground(target = document.body, options = {}) {
980
+ injectStyle()
981
+
982
+ const container = typeof target === 'string' ? document.querySelector(target) : target
983
+ if (!container) {
984
+ throw new Error('SolarBackground: mount target not found')
985
+ }
986
+
987
+ if (container !== document.body) {
988
+ const computed = getComputedStyle(container)
989
+ if (computed.position === 'static') {
990
+ container.style.position = 'relative'
991
+ }
992
+ }
993
+
994
+ const wrapper = document.createElement('div')
995
+ wrapper.className = 'solar-background-root'
996
+ wrapper.style.position = options.wrapperPosition || 'absolute'
997
+ wrapper.style.inset = '0'
998
+ wrapper.style.width = '100%'
999
+ wrapper.style.height = '100%'
1000
+ wrapper.style.zIndex = options.wrapperZIndex ?? '-1'
1001
+ wrapper.style.pointerEvents = 'none'
1002
+
1003
+ wrapper.innerHTML = createSceneMarkup()
1004
+ container.appendChild(wrapper)
1005
+
1006
+ createStars(wrapper, options.starCount ?? 260)
1007
+
1008
+ const cycleDuration = options.cycleDuration ?? 4200
1009
+ const animalDelay = options.animalDelay ?? 1400
1010
+ // initialize ordered sequence so each sign shows before repeating
1011
+ const initialOrder = options.order || shuffle(Array.from({ length: zodiacAnimalConstellations.length }, (_, i) => i))
1012
+ instanceMap.set(wrapper, { order: initialOrder, index: 0 })
1013
+ showNextZodiacAnimalPair(wrapper, cycleDuration, animalDelay)
1014
+ const interval = setInterval(() => showNextZodiacAnimalPair(wrapper, cycleDuration, animalDelay), cycleDuration)
1015
+ const meta = instanceMap.get(wrapper) || {}
1016
+ meta.interval = interval
1017
+ instanceMap.set(wrapper, meta)
1018
+ return wrapper
1019
+ }
1020
+
1021
+ function destroySolarBackground(root) {
1022
+ const data = instanceMap.get(root)
1023
+ if (data) {
1024
+ clearInterval(data.interval)
1025
+ }
1026
+ if (root && root.parentNode) {
1027
+ root.parentNode.removeChild(root)
1028
+ }
1029
+ instanceMap.delete(root)
1030
+ }
1031
+
1032
+ function initializeBackgroundElement(element) {
1033
+ injectStyle()
1034
+ element.classList.add('solar-background-root')
1035
+ element.style.display = 'block'
1036
+ element.style.position = 'absolute'
1037
+ element.style.inset = '0'
1038
+ element.style.width = '100%'
1039
+ element.style.height = '100%'
1040
+ element.style.pointerEvents = 'none'
1041
+ element.style.zIndex = '-1'
1042
+ element.innerHTML = createSceneMarkup()
1043
+ createStars(element, 1260)
1044
+ const initialOrder = shuffle(Array.from({ length: zodiacAnimalConstellations.length }, (_, i) => i))
1045
+ instanceMap.set(element, { order: initialOrder, index: 0 })
1046
+ showNextZodiacAnimalPair(element)
1047
+ const interval = setInterval(() => showNextZodiacAnimalPair(element), 4200)
1048
+ const meta = instanceMap.get(element) || {}
1049
+ meta.interval = interval
1050
+ instanceMap.set(element, meta)
1051
+ }
1052
+
1053
+ class SolarBackgroundElement extends HTMLElement {
1054
+ connectedCallback() {
1055
+ if (this.__solarBackgroundInitialized) {
1056
+ return
1057
+ }
1058
+
1059
+ initializeBackgroundElement(this)
1060
+ this.__solarBackgroundInitialized = true
1061
+ }
1062
+
1063
+ disconnectedCallback() {
1064
+ const data = instanceMap.get(this)
1065
+ if (data) {
1066
+ clearInterval(data.interval)
1067
+ instanceMap.delete(this)
1068
+ }
1069
+ }
1070
+ }
1071
+
1072
+ if (!customElements.get('solar-background')) {
1073
+ customElements.define('solar-background', SolarBackgroundElement)
1074
+ }
1075
+
1076
+ export { createSolarBackground, destroySolarBackground }