From c7397852b772a95f25140c97bc4ec43b2ab5b26d Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 26 Feb 2026 17:25:21 +0000 Subject: [PATCH] 4 --- frontend/src/pages/observation.tsx | 359 ++++++++++++++++++----------- 1 file changed, 228 insertions(+), 131 deletions(-) diff --git a/frontend/src/pages/observation.tsx b/frontend/src/pages/observation.tsx index 54c9ca8..fc26b09 100644 --- a/frontend/src/pages/observation.tsx +++ b/frontend/src/pages/observation.tsx @@ -1,10 +1,10 @@ import React, { useEffect, useRef, useState } from 'react'; import type { ReactElement } from 'react'; import Head from 'next/head'; -import { - mdiClose, - mdiTelescope, - mdiMagnifyPlusOutline, +import { + mdiClose, + mdiTelescope, + mdiMagnifyPlusOutline, mdiMagnifyMinusOutline, mdiOrbitVariant, mdiFlare, @@ -13,42 +13,58 @@ import { mdiRecord, mdiStop, mdiDownload, - mdiAutoFix + mdiAutoFix, + mdiAccountGroup, + mdiStarCircle, + mdiChatProcessingOutline } from '@mdi/js'; import BaseIcon from '../components/BaseIcon'; import { useAppDispatch } from '../stores/hooks'; import { fetch as fetchSkyObjects } from '../stores/sky_objects/sky_objectsSlice'; import LayoutAuthenticated from '../layouts/Authenticated'; +const CELEBRITIES = [ + { id: 'beyonce', name: 'Beyoncé', category: 'Singer', reaction: 'This view is absolutely flawless! Like a diamond in the sky.' }, + { id: 'jackson', name: 'Michael Jackson', category: 'Singer', reaction: 'Hee-hee! Looking at the stars is a thriller!' }, + { id: 'mercury', name: 'Freddie Mercury', category: 'Singer', reaction: 'I see a little silhouetto of a galaxy! Magnificent!' }, + { id: 'swift', name: 'Taylor Swift', category: 'Singer', reaction: 'I can see the sparks fly in that nebula. Enchanting!' }, + { id: 'dicaprio', name: 'Leonardo DiCaprio', category: 'Actor', reaction: 'I\'m the king of the world... or at least this telescope!' }, + { id: 'streep', name: 'Meryl Streep', category: 'Actress', reaction: 'The performance of these celestial bodies is award-worthy.' }, + { id: 'hanks', name: 'Tom Hanks', category: 'Actor', reaction: 'Houston, we have an incredible view here!' }, + { id: 'davinci', name: 'Leonardo da Vinci', category: 'Painter', reaction: 'The proportions of this universe are divine. A true masterpiece.' }, + { id: 'vangogh', name: 'Vincent van Gogh', category: 'Painter', reaction: 'The starry night... it\'s even more vibrant than I painted it!' }, + { id: 'kahlo', name: 'Frida Kahlo', category: 'Painter', reaction: 'Feet, what do I need them for if I have wings to fly to these stars?' }, +]; + const PRESET_TARGETS = [ - { - id: 'mars', - name: 'Mars', - type: 'Planet', + { + id: 'mars', + name: 'Mars', + type: 'Planet', img: 'https://images-assets.nasa.gov/image/PIA04591/PIA04591~medium.jpg', dist: '225M km', temp: '210K' }, - { - id: 'jupiter', - name: 'Jupiter', - type: 'Planet', + { + id: 'jupiter', + name: 'Jupiter', + type: 'Planet', img: 'https://images-assets.nasa.gov/image/PIA04866/PIA04866~medium.jpg', dist: '778M km', temp: '110K' }, - { - id: 'orion', - name: 'Orion Nebula', - type: 'Nebula', + { + id: 'orion', + name: 'Orion Nebula', + type: 'Nebula', img: 'https://images-assets.nasa.gov/image/PIA08653/PIA08653~medium.jpg', dist: '1,344 ly', temp: '10,000K' }, - { - id: 'andromeda', - name: 'Andromeda', - type: 'Galaxy', + { + id: 'andromeda', + name: 'Andromeda', + type: 'Galaxy', img: 'https://images-assets.nasa.gov/image/PIA15416/PIA15416~medium.jpg', dist: '2.5M ly', temp: '2.7K' @@ -57,7 +73,7 @@ const PRESET_TARGETS = [ id: 'pillars', name: 'Pillars of Creation', type: 'Nebula', - img: 'https://images-assets.nasa.gov/image/as11-40-5874/as11-40-5874~medium.jpg', + img: 'https://images-assets.nasa.gov/image/as11-40-5874/as11-40-5874~medium.jpg', dist: '6,500 ly', temp: '15K' } @@ -67,7 +83,7 @@ const ObservationPage = () => { const videoRef = useRef(null); const [isCameraActive, setIsCameraActive] = useState(false); const [mode, setMode] = useState<'normal' | 'ir' | 'deep'>('normal'); - const [zoom, setZoom] = useState(1); + const [zoom, setZoom] = useState(1); const [selectedTarget, setSelectedTarget] = useState(null); const [isFocusing, setIsFocusing] = useState(false); const [isSharpnessMax, setIsSharpnessMax] = useState(false); @@ -77,6 +93,13 @@ const ObservationPage = () => { focal: 131, }); + // Simulation States + const [audienceCount, setAudienceCount] = useState(0); + const [isSimActive, setIsSimActive] = useState(false); + const [activeCelebrities, setActiveCelebrities] = useState([]); + const [chatMessages, setChatMessages] = useState([]); + const [showSimPanel, setShowSimPanel] = useState(false); + // Recording states const [isRecording, setIsRecording] = useState(false); const [mediaRecorder, setMediaRecorder] = useState(null); @@ -91,13 +114,13 @@ const ObservationPage = () => { const startCamera = async () => { try { - const stream = await navigator.mediaDevices.getUserMedia({ - video: { + const stream = await navigator.mediaDevices.getUserMedia({ + video: { facingMode: 'environment', width: { ideal: 1920 }, height: { ideal: 1080 } }, - audio: true // Integrate audio for synchronized recording + audio: true }); if (videoRef.current) { videoRef.current.srcObject = stream; @@ -122,6 +145,52 @@ const ObservationPage = () => { return () => stopCamera(); }, []); + // Audience Simulation Logic + useEffect(() => { + let interval: any; + if (isSimActive) { + interval = setInterval(() => { + setAudienceCount(prev => { + const target = 1000000; + if (prev < target) { + return Math.min(prev + Math.floor(Math.random() * 5000) + 1000, target); + } + return target; + }); + + // Generate Chat Messages + if (activeCelebrities.length > 0 && Math.random() > 0.7) { + const randomCelebId = activeCelebrities[Math.floor(Math.random() * activeCelebrities.length)]; + const celeb = CELEBRITIES.find(c => c.id === randomCelebId); + if (celeb) { + const newMessage = { + id: Date.now(), + name: celeb.name, + category: celeb.category, + text: celeb.reaction, + time: new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) + }; + setChatMessages(prev => [newMessage, ...prev].slice(0, 10)); + } + } + }, 2000); + } else { + setAudienceCount(0); + setChatMessages([]); + } + return () => clearInterval(interval); + }, [isSimActive, activeCelebrities]); + + const toggleCelebrity = (id: string) => { + setActiveCelebrities(prev => + prev.includes(id) ? prev.filter(c => c !== id) : [...prev, id] + ); + }; + + const selectAllCelebrities = () => { + setActiveCelebrities(CELEBRITIES.map(c => c.id)); + }; + const handleZoom = (direction: 'in' | 'out') => { setZoom(prev => { if (direction === 'in') { @@ -179,30 +248,17 @@ const ObservationPage = () => { // Recording Logic const startRecording = () => { if (!videoRef.current || !videoRef.current.srcObject) return; - const stream = videoRef.current.srcObject as MediaStream; - - // Check for supported types with audio const options = { mimeType: 'video/webm;codecs=vp8,opus' }; - if (!MediaRecorder.isTypeSupported(options.mimeType)) { - options.mimeType = 'video/webm'; - } - + if (!MediaRecorder.isTypeSupported(options.mimeType)) options.mimeType = 'video/webm'; const recorder = new MediaRecorder(stream, options); - const chunks: Blob[] = []; - recorder.ondataavailable = (event) => { - if (event.data.size > 0) { - chunks.push(event.data); - } - }; - + recorder.ondataavailable = (event) => { if (event.data.size > 0) chunks.push(event.data); }; recorder.onstop = () => { const blob = new Blob(chunks, { type: 'video/webm' }); const url = URL.createObjectURL(blob); setVideoUrl(url); }; - recorder.start(); setIsRecording(true); setMediaRecorder(recorder); @@ -221,7 +277,7 @@ const ObservationPage = () => { const a = document.createElement('a'); a.style.display = 'none'; a.href = videoUrl; - a.download = `JWST-AV-REC-${new Date().getTime()}.webm`; + a.download = `JWST-CELEB-REC-${new Date().getTime()}.webm`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(videoUrl); @@ -242,7 +298,7 @@ const ObservationPage = () => { return (
- JWST | Deep Space Observation + JWST | Global Observation Live {/* Main Viewport */} @@ -277,7 +333,7 @@ const ObservationPage = () => { }} /> - {/* Deep Space High-Res Layer */} + {/* Deep Space Layer */} {selectedTarget && (
{ /> )} - {/* Loading Overlay when Focusing */} + {/* Audience Visual Simulation Overlay */} + {isSimActive && audienceCount > 1000 && ( +
+ {/* Heatmap/Crowd Particles Effect */} +
+ {[...Array(20)].map((_, i) => ( +
+ ))} +
+ )} + + {/* Loading Overlay */} {isFocusing && (
@@ -301,61 +379,55 @@ const ObservationPage = () => { )}
- {/* JWST Hexagonal Overlay */} - {isCameraActive && ( -
- - - - - - - - -
- )} - {/* UI Controls & Telemetry */} {isCameraActive && (
{/* Top Bar */}
-
-
Mission Control: NASA-ESA-CSA
+
+
Global Observation Stream
-
-
- {isRecording ? 'A/V REC ACTIVE' : (isFocusing ? 'Acquiring Target' : 'Observation Stable')} +
+
+ {isRecording ? 'A/V REC ACTIVE' : (isFocusing ? 'Acquiring Target' : 'LIVE TRANSMISSION')}
-
+ + {isSimActive && ( +
+ + {audienceCount.toLocaleString()} WATCHING +
+ )} + +
BUS TEMP - {(selectedTarget && isDeepZoom ? 6.5 : telemetry.temp).toFixed(1)}K + {(selectedTarget && isDeepZoom ? 6.5 : telemetry.temp).toFixed(1)}K
MAGNIFICATION - {formatZoom(zoom)} -
-
- FOCAL POINT - {telemetry.focal.toFixed(1)}mm -
-
- L2 DISTANCE - 1,502,401.2 km + {formatZoom(zoom)}
+ {/* Advanced Sim Control */} + + {/* Recording System */}
{!isRecording ? ( @@ -363,7 +435,6 @@ const ObservationPage = () => { @@ -372,7 +443,6 @@ const ObservationPage = () => { @@ -381,17 +451,10 @@ const ObservationPage = () => { -
+ {/* Advanced Simulation Panel */} + {showSimPanel && ( +
+
+

Audience Simulation

+ +
+ +
+
+ Live Audience (1M max) + +
+ +
+
+ Personalities (Famous Artists) + +
+
+ {CELEBRITIES.map(celeb => ( + + ))} +
+
+
+
+ )} + + {/* Simulation Chat / Interaction Overlay */} + {isSimActive && chatMessages.length > 0 && ( +
+ {chatMessages.map(msg => ( +
+
+ {msg.name} + {msg.category} +
+

"{msg.text}"

+
+ ))} +
+ )} + {/* Zoom Controls */}
-
Magnify
-
+
{
- {/* Targeting HUD */} - {isDeepZoom && ( -
-
-
-
-
-
-
- -
-
-
- )} - {/* Bottom Area: Controls */} -
+
{/* Target Selector */}
-
Select Astronomical Target
{PRESET_TARGETS.map(target => (
); }; @@ -512,4 +609,4 @@ ObservationPage.getLayout = function getLayout(page: ReactElement) { return {page}; }; -export default ObservationPage; \ No newline at end of file +export default ObservationPage;