diff --git a/api/cyclone.php b/api/cyclone.php new file mode 100644 index 0000000..6eaa9a5 --- /dev/null +++ b/api/cyclone.php @@ -0,0 +1,43 @@ + 'Failed to fetch SPC data.']); + exit; +} + +// Parse the XML +$xml = @simplexml_load_string($rss); + +if ($xml === false) { + echo json_encode(['error' => 'Failed to parse SPC XML.']); + exit; +} + +$alerts = []; +if (isset($xml->channel->item)) { + foreach ($xml->channel->item as $item) { + // The title often contains the most succinct information + $title = (string)$item->title; + + // The description can be long, let's create a summary or just use the title + $description = (string)$item->description; + + $alerts[] = [ + 'headline' => $title, + 'description' => strip_tags($description), // Basic sanitization + 'link' => (string)$item->link + ]; + } +} + +// Return the alerts as JSON +echo json_encode($alerts); +?> \ No newline at end of file diff --git a/api/pexels.php b/api/pexels.php new file mode 100644 index 0000000..031aa0f --- /dev/null +++ b/api/pexels.php @@ -0,0 +1,46 @@ + 'Failed to fetch image from Pexels.']); + exit; +} + +$photo = $data['photos'][0]; +$src = $photo['src']['large2x'] ?? ($photo['src']['large'] ?? $photo['src']['original']); +$filename = $photo['id'] . '.jpg'; +$target_path = $cache_dir . $filename; + +// Download if it doesn't exist +if (!file_exists($target_path)) { + if (!download_to($src, $target_path)) { + http_response_code(500); + echo json_encode(['error' => 'Failed to download and save image.']); + exit; + } +} + +// Return minimal info and local relative path +echo json_encode([ + 'id' => $photo['id'], + 'local_path' => 'assets/images/pexels/' . $filename, + 'photographer' => $photo['photographer'] ?? null, + 'photographer_url' => $photo['photographer_url'] ?? null, + 'alt' => $photo['alt'] ?? 'Image related to ' . $query, +]); diff --git a/assets/css/custom.css b/assets/css/custom.css new file mode 100644 index 0000000..12a2da8 --- /dev/null +++ b/assets/css/custom.css @@ -0,0 +1,95 @@ + +body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; + background-color: #F8F9FA; + color: #212529; +} + +.navbar { + padding: 1rem 0; +} + +.hero { + position: relative; + padding: 8rem 0; + background-size: cover; + background-position: center; + color: white; +} + +.hero-overlay { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 25, 51, 0.7); + z-index: 1; +} + +.hero .container { + position: relative; + z-index: 2; +} + +.hero h1 { + font-size: 3.5rem; + font-weight: 700; +} + +.hero p { + font-size: 1.25rem; +} + +.btn-primary { + background-color: #00CC99; + border-color: #00CC99; + padding: 0.75rem 1.5rem; + border-radius: 0.5rem; + font-weight: 600; +} + +.btn-primary:hover { + background-color: #00b386; + border-color: #00b386; +} + +section { + padding: 4rem 0; +} + +h2 { + font-size: 2.5rem; + font-weight: 700; + margin-bottom: 2rem; +} + +.card { + border: none; + border-radius: 0.5rem; + box-shadow: 0 4px 8px rgba(0,0,0,0.1); +} + +.contact-form { + background-color: #FFFFFF; + padding: 3rem; + border-radius: 0.5rem; +} + +.footer { + background-color: #003366; + color: white; + padding: 3rem 0; +} + +.footer a { + color: #00CC99; +} + +#cyclone-widget { + background-color: #FFFFFF; +} + +#cyclone-data .card { + background-color: #F8F9FA; +} diff --git a/assets/images/pexels/76969.jpg b/assets/images/pexels/76969.jpg new file mode 100644 index 0000000..ab2119f Binary files /dev/null and b/assets/images/pexels/76969.jpg differ diff --git a/assets/js/main.js b/assets/js/main.js new file mode 100644 index 0000000..05cd30e --- /dev/null +++ b/assets/js/main.js @@ -0,0 +1,72 @@ + +document.addEventListener('DOMContentLoaded', function () { + const contactForm = document.getElementById('contactForm'); + if (contactForm) { + contactForm.addEventListener('submit', function (e) { + e.preventDefault(); + const form = e.target; + const formData = new FormData(form); + const status = document.getElementById('form-status'); + + // Basic client-side validation + const name = formData.get('name'); + const email = formData.get('email'); + const message = formData.get('message'); + + if (!name || !email || !message) { + status.innerHTML = '
Please fill out all fields.
'; + return; + } + + fetch('contact.php', { + method: 'POST', + body: formData + }) + .then(response => response.json()) + .then(data => { + if (data.success) { + status.innerHTML = `
${data.message}
`; + form.reset(); + } else { + status.innerHTML = `
${data.message}
`; + } + }) + .catch(error => { + status.innerHTML = '
An error occurred. Please try again.
'; + console.error('Error:', error); + }); + }); + } + + // Fetch and display cyclone data + const cycloneDataContainer = document.getElementById('cyclone-data'); + if (cycloneDataContainer) { + fetch('api/cyclone.php') + .then(response => response.json()) + .then(data => { + if (data && data.length > 0) { + let html = ''; + data.forEach(alert => { + html += ` +
+
+
+
${alert.headline}
+

${alert.description.substring(0, 150)}...

+ Read More +
+
+
+ `; + }); + cycloneDataContainer.innerHTML = html; + } else { + cycloneDataContainer.innerHTML = '

No active severe weather alerts from the SPC at the moment.

'; + } + }) + .catch(error => { + cycloneDataContainer.innerHTML = '

Could not load cyclone data. Please try again later.

'; + console.error('Error fetching cyclone data:', error); + }); + } +}); diff --git a/contact.php b/contact.php new file mode 100644 index 0000000..7d6e8d0 --- /dev/null +++ b/contact.php @@ -0,0 +1,34 @@ + false, 'message' => 'Please fill out all fields.']); + exit; +} + +if (!filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)) { + echo json_encode(['success' => false, 'message' => 'Invalid email format.']); + exit; +} + +require_once __DIR__ . '/mail/MailService.php'; + +$name = htmlspecialchars($_POST['name']); +$email = htmlspecialchars($_POST['email']); +$message = htmlspecialchars($_POST['message']); + +// The recipient email address should be configured in .env as MAIL_TO +// If MAIL_TO is not set, it will fall back to MAIL_FROM +$to = null; +$subject = 'New Contact Form Submission from Worldsphere.ai'; + +$res = MailService::sendContactMessage($name, $email, $message, $to, $subject); + +if (!empty($res['success'])) { + echo json_encode(['success' => true, 'message' => 'Thank you for your message! We will get back to you shortly.']); +} else { + // In a real app, you would log the detailed error. + // error_log("Mailgun error: " . $res['error']); + echo json_encode(['success' => false, 'message' => 'Sorry, there was an error sending your message. Please try again later.']); +} diff --git a/includes/pexels.php b/includes/pexels.php new file mode 100644 index 0000000..229413e --- /dev/null +++ b/includes/pexels.php @@ -0,0 +1,34 @@ + 0 ? $k : 'Vc99rnmOhHhJAbgGQoKLZtsaIVfkeownoQNbTj78VemUjKh08ZYRbf18'; +} +function pexels_get($url) { + $ch = curl_init(); + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_HTTPHEADER => [ 'Authorization: '. pexels_key() ], + CURLOPT_TIMEOUT => 15, + ]); + $resp = curl_exec($ch); + $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + if ($code >= 200 && $code < 300 && $resp) return json_decode($resp, true); + return null; +} +function download_to($srcUrl, $destPath) { + if (!is_dir(dirname($destPath))) { + mkdir(dirname($destPath), 0775, true); + } + $ch = curl_init($srcUrl); + $fp = fopen($destPath, 'wb'); + curl_setopt($ch, CURLOPT_FILE, $fp); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_TIMEOUT, 60); // 60 seconds timeout for download + $result = curl_exec($ch); + curl_close($ch); + fclose($fp); + return $result !== false; +} diff --git a/index.php b/index.php index 7205f3d..09db81c 100644 --- a/index.php +++ b/index.php @@ -1,150 +1,155 @@ - + - - - New Style - - - - - - - - - - - - - - - - - - - + + + Worldsphere.ai - AI-Powered Weather Prediction + + + + + + + + + + + + + -
-
-

Analyzing your requirements and generating your website…

-
- Loading… -
-

AI is collecting your requirements and applying the first changes.

-

This page will update automatically as the plan is implemented.

-

Runtime: PHP — UTC

-
-
- + + + +
+
+
+
+

First Beta Version now available! Download now

+

Revolutionizing Climate Resilience with AI-Powered Weather Prediction

+

Where Cutting-Edge Technology Meets Climate Action. At Worldsphere.ai, we’re harnessing the power of artificial intelligence to transform how we predict, prepare for, and respond to extreme weather events.

+ Join the Climate Tech Revolution +
+
+
+ +
+

Active Tropical Cyclones

+
+

Loading real-time cyclone data...

+
+
+ +
+

Technology & Innovation

+

Our innovative platform combines state-of-the-art AI models, big data analytics, and immersive visualization techniques to provide unparalleled insights into weather risks and climate patterns.

+
+
+
+
AI-Powered Hurricane Prediction
+

Our flagship technology utilizes advanced diffusion models to revolutionize hurricane forecasting.

+
+
+
+
+
Satellite-to-Wind Technology
+

Generate realistic 2D wind fields from infrared satellite imagery and automatically remove land masses.

+
+
+
+
+
Model Interpretability
+

We bridge traditional meteorological frameworks and AI-generated insights by mapping atmospheric patterns to model activations.

+
+
+
+
+ +
+
+
+
+

Our Mission

+

Empowering Global Resilience in the Face of Climate Change.

+

We recognize the urgency of the climate crisis. At Worldsphere.ai, we’re committed to developing solutions that address both current and future climate challenges, from severe droughts to devastating floods. Our ultimate goal is to create a world where every individual, community, and organization has access to accurate, timely, and actionable weather intelligence.

+
+
+
Our Core Objectives
+
    +
  • Advance the field of Al-powered weather prediction
  • +
  • Improve early warning systems for extreme weather events
  • +
  • Support businesses and communities in climate risk management
  • +
  • Foster collaboration between technology and climate science
  • +
+
+
+
+
+ +
+
+
+
+
+

Contact Us

+

Sign up for our beta testing program and experience the future of weather risk management.

+
+
+ +
+
+ +
+
+ +
+ +
+
+
+
+
+
+
+
+ + + + + - + \ No newline at end of file diff --git a/privacy.php b/privacy.php new file mode 100644 index 0000000..0be1e14 --- /dev/null +++ b/privacy.php @@ -0,0 +1,35 @@ + + + + + + + Privacy Policy - Worldsphere.ai + + + + + + + + +
+

Privacy Policy

+

This is a placeholder for the Privacy Policy page.

+

Information on how user data is collected, used, and protected will be detailed here.

+ Return to Home +
+ + + + + + diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 0000000..6f138b9 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,13 @@ + + + + https:///index.php + 2025-10-13 + 1.00 + + + https:///privacy.php + 2025-10-13 + 0.80 + +