data endpoint for entity 90008 (aka. a website)
1<script lang="ts">
2 import { genDollcode } from '$lib/dollcode';
3
4 interface Star {
5 domain: string;
6 x: number;
7 y: number;
8 r: number;
9 }
10
11 interface StarsData {
12 width: number;
13 height: number;
14 stars: Star[];
15 meta?: {
16 timestamp: string;
17 angleY: number;
18 angleX: number;
19 seed?: number;
20 };
21 }
22
23 interface Props {
24 stars: StarsData | null;
25 isUIHidden: boolean;
26 }
27
28 let { stars, isUIHidden }: Props = $props();
29
30 let containerWidth = $state(0);
31 let containerHeight = $state(0);
32
33 let tauShift = $derived.by(() => {
34 if (stars?.meta?.seed === undefined) return 'UNKNOWN';
35 const main = Math.abs(stars.meta.seed % 360);
36 const sub = Math.abs((stars.meta.seed % 10000) / 10000);
37 return (main + sub).toFixed(4);
38 });
39
40 let lambdaLock = $derived.by(() => {
41 if (stars?.meta?.seed === undefined) return 'UNKNOWN';
42 return ((stars.meta.seed * 1.618) % 100).toFixed(4);
43 });
44 let manifoldId = $derived.by(() => {
45 if (stars?.meta?.seed === undefined) return 'UNKNOWN';
46 const hex = stars.meta.seed.toString(16).toUpperCase();
47 const chunks = hex.match(/.{1,5}/g)?.join('-') ?? hex;
48 return chunks;
49 });
50
51 let scale = $derived.by(() => {
52 if (!stars || containerWidth === 0 || containerHeight === 0) return 0;
53
54 const imgRatio = stars.width / stars.height;
55 const containerRatio = containerWidth / containerHeight;
56
57 if (containerRatio > imgRatio) {
58 return containerWidth / stars.width;
59 } else {
60 return containerHeight / stars.height;
61 }
62 });
63
64 let offsetX = $derived.by(() => {
65 if (!stars || scale === 0) return 0;
66 return (containerWidth - stars.width * scale) / 2;
67 });
68
69 let offsetY = $derived.by(() => {
70 if (!stars || scale === 0) return 0;
71 return (containerHeight - stars.height * scale) / 2;
72 });
73</script>
74
75<svelte:window bind:innerWidth={containerWidth} bind:innerHeight={containerHeight} />
76
77{#if stars && scale > 0}
78 <div class="fixed inset-0 pointer-events-none {isUIHidden ? 'z-[2000]' : 'z-0'} overflow-hidden">
79 {#if stars.meta}
80 <div class="absolute font-mono top-4 left-4 origin-top-left meta-text">
81 <div>//DATE/{stars.meta.timestamp}</div>
82 <div> /ASCENSION/{(stars.meta.angleY * (180 / Math.PI)).toFixed(4)}°</div>
83 <div> /DECLINATION/{(stars.meta.angleX * (180 / Math.PI)).toFixed(4)}°/</div>
84 </div>
85 <div
86 class="absolute font-mono top-4 left-1/2 -translate-x-1/2 origin-top meta-text text-center"
87 >
88 {genDollcode(
89 new Date(stars.meta.timestamp).getTime() +
90 stars.meta.angleY +
91 stars.meta.angleX +
92 (stars.meta.seed ?? 0)
93 )}
94 </div>
95 <div class="absolute top-4 right-4 origin-top-right meta-text text-right">
96 <div>//TAU SHIFT/{tauShift}°</div>
97 <div> /LAMBDA LOCK/{lambdaLock}Gpc</div>
98 <div> /MANIFOLD/{manifoldId}/</div>
99 </div>
100 {/if}
101 {#each stars.stars as star}
102 {@const screenX = star.x * scale + offsetX}
103 {@const screenY = star.y * scale + offsetY}
104 {@const radius = star.r * scale}
105
106 <!-- only render if potentially visible -->
107 {#if screenX > -50 && screenX < containerWidth + 50 && screenY > -50 && screenY < containerHeight + 50}
108 <a
109 href="https://{star.domain}"
110 target="_blank"
111 rel="noopener noreferrer"
112 class="absolute pointer-events-auto group"
113 style="
114 left: {screenX - radius}px;
115 top: {screenY - radius}px;
116 width: {radius * 2}px;
117 height: {radius * 2}px;
118 "
119 title={star.domain}
120 >
121 <span class="sr-only">{star.domain}</span>
122 <!-- Tooltip -->
123 <div
124 class="
125 absolute bottom-full left-1/2 -translate-x-1/2 mb-2 px-2 py-1
126 bg-black/80 text-white text-sm opacity-0 group-hover:opacity-100
127 transition-opacity whitespace-nowrap pointer-events-none
128 border border-white/20
129 "
130 >
131 {star.domain}
132 </div>
133 </a>
134 {/if}
135 {/each}
136 </div>
137{/if}
138
139<style lang="postcss">
140 .meta-text {
141 @apply scale-50 text-white/70 drop-shadow-[0_2px_2px_rgba(0,0,0,1.0)] select-none z-10 pointer-events-none flex flex-col gap-0.5;
142 }
143</style>