diff --git a/.user.ini b/.user.ini
deleted file mode 100644
index 69b3887..0000000
--- a/.user.ini
+++ /dev/null
@@ -1 +0,0 @@
-memory_limit = 512M
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/gfs.php b/api/gfs.php
deleted file mode 100644
index 64c57b1..0000000
--- a/api/gfs.php
+++ /dev/null
@@ -1,91 +0,0 @@
- 'Failed to download GFS file', 'http_code' => $http_code]);
- exit;
- }
-}
-
-// --- Convert GRIB to XYZ using gdal_translate ---
-// We'll use band 1 for this example. You can use gdalinfo to see available bands.
-$gdal_command = 'gdal_translate -b 1 -of XYZ ' . escapeshellarg($grib_file) . ' ' . escapeshellarg($xyz_file);
-$gdal_output = shell_exec($gdal_command);
-
-if (!file_exists($xyz_file)) {
- echo json_encode(['error' => 'Failed to convert GRIB to XYZ', 'gdal_output' => $gdal_output]);
- unlink($grib_file);
- exit;
-}
-
-// --- Read the XYZ file and create GeoJSON features ---
-$features = [];
-$handle = fopen($xyz_file, 'r');
-$line_count = 0;
-$sample_rate = 100; // Process 1 in every 100 lines
-
-if ($handle) {
- while (($line = fgets($handle)) !== false) {
- $line_count++;
- if ($line_count % $sample_rate !== 0) {
- continue;
- }
-
- $parts = preg_split('/\s+/', trim($line));
- if (count($parts) === 3) {
- $lon = floatval($parts[0]);
- $lat = floatval($parts[1]);
- $value = floatval($parts[2]);
-
- // Skip points that are exactly zero, often represent no data
- if ($value === 0.0) {
- continue;
- }
-
- $features[] = [
- 'type' => 'Feature',
- 'properties' => ['value' => $value],
- 'geometry' => [
- 'type' => 'Point',
- 'coordinates' => [$lon, $lat]
- ]
- ];
- }
- }
- fclose($handle);
-}
-
-// --- Clean up temporary files ---
-unlink($grib_file);
-unlink($xyz_file);
-
-// --- Output the GeoJSON ---
-echo json_encode([
- 'type' => 'FeatureCollection',
- 'features' => $features
-]);
-
-?>
\ No newline at end of file
diff --git a/api/hurricanes.php b/api/hurricanes.php
deleted file mode 100644
index 7186da6..0000000
--- a/api/hurricanes.php
+++ /dev/null
@@ -1,118 +0,0 @@
- 'Failed to fetch NHC data.']);
- exit;
-}
-
-// Save the data to the temporary file
-file_put_contents($tmp_kmz_file, $kmz_data);
-
-if (!class_exists('ZipArchive')) {
- echo json_encode(['error' => 'ZipArchive class does not exist.']);
- exit;
-}
-
-// Use ZipArchive to open the KMZ file
-$zip = new ZipArchive;
-if ($zip->open($tmp_kmz_file) === TRUE) {
- // NHC KMZ files typically contain a single KML file, often named doc.kml or similar.
- // We will look for the first .kml file in the archive.
- $kml_content = false;
- for ($i = 0; $i < $zip->numFiles; $i++) {
- $filename = $zip->getNameIndex($i);
- if (strtolower(substr($filename, -4)) === '.kml') {
- $kml_content = $zip->getFromIndex($i);
- break;
- }
- }
- $zip->close();
-
- if ($kml_content === false) {
- echo json_encode(['error' => 'KML file not found in the KMZ archive.']);
- exit;
- }
-
- // Parse the KML content
- $xml = simplexml_load_string($kml_content, "SimpleXMLElement", LIBXML_NOCDATA);
- if ($xml === false) {
- echo json_encode(['error' => 'Failed to parse KML data.']);
- exit;
- }
-
- // Register the KML namespace
- $xml->registerXPathNamespace('kml', 'http://www.opengis.net/kml/2.2');
-
- $features = [];
-
- // Find all Placemarks in the KML
- foreach ($xml->xpath('//kml:Placemark') as $placemark) {
- $placemark->registerXPathNamespace('kml', 'http://www.opengis.net/kml/2.2');
- $name = (string)$placemark->name;
-
- // Look for Polygon
- $polygon = $placemark->xpath('.//kml:Polygon');
- if ($polygon && isset($polygon[0]->outerBoundaryIs->LinearRing->coordinates)) {
- $coordinates_str = (string)$polygon[0]->outerBoundaryIs->LinearRing->coordinates;
- $coordinates = parse_coordinates($coordinates_str);
- if (!empty($coordinates)) {
- $features[] = [
- 'name' => $name,
- 'type' => 'Polygon',
- 'coordinates' => $coordinates
- ];
- }
- }
-
- // Look for LineString
- $linestring = $placemark->xpath('.//kml:LineString');
- if ($linestring && isset($linestring[0]->coordinates)) {
- $coordinates_str = (string)$linestring[0]->coordinates;
- $coordinates = parse_coordinates($coordinates_str);
- if (!empty($coordinates)) {
- $features[] = [
- 'name' => $name,
- 'type' => 'LineString',
- 'coordinates' => $coordinates
- ];
- }
- }
- }
-
- echo json_encode($features);
-
-} else {
- echo json_encode(['error' => 'Failed to open KMZ file.']);
-}
-
-// Clean up the temporary file
-unlink($tmp_kmz_file);
-
-function parse_coordinates($coordinates_str) {
- $coords = [];
- $pairs = explode(' ', trim($coordinates_str));
- foreach ($pairs as $pair) {
- $parts = explode(',', $pair);
- if (count($parts) >= 2) {
- $lon = floatval($parts[0]);
- $lat = floatval($parts[1]);
- // Ensure coordinates are valid
- if (is_finite($lat) && is_finite($lon)) {
- $coords[] = $lon;
- $coords[] = $lat;
- }
- }
- }
- return $coords;
-}
-?>
\ No newline at end of file
diff --git a/api/spc.php b/api/spc.php
deleted file mode 100644
index 37434e5..0000000
--- a/api/spc.php
+++ /dev/null
@@ -1,66 +0,0 @@
- 'Failed to fetch SPC data.']);
- exit;
-}
-
-// Parse the KML content
-$xml = simplexml_load_string($kml_content, "SimpleXMLElement", LIBXML_NOCDATA);
-if ($xml === false) {
- echo json_encode(['error' => 'Failed to parse KML data.']);
- exit;
-}
-
-// Register the KML namespace
-$xml->registerXPathNamespace('kml', 'http://www.opengis.net/kml/2.2');
-
-$features = [];
-
-// Find all Placemarks in the KML
-foreach ($xml->xpath('//kml:Placemark') as $placemark) {
- $placemark->registerXPathNamespace('kml', 'http://www.opengis.net/kml/2.2');
- $name = (string)$placemark->name;
-
- // Look for Polygon
- $polygon = $placemark->xpath('.//kml:Polygon');
- if ($polygon && isset($polygon[0]->outerBoundaryIs->LinearRing->coordinates)) {
- $coordinates_str = (string)$polygon[0]->outerBoundaryIs->LinearRing->coordinates;
- $coordinates = parse_coordinates($coordinates_str);
- if (!empty($coordinates)) {
- $features[] = [
- 'name' => $name,
- 'type' => 'Polygon',
- 'coordinates' => $coordinates
- ];
- }
- }
-}
-
-echo json_encode($features);
-
-function parse_coordinates($coordinates_str) {
- $coords = [];
- $pairs = explode(' ', trim($coordinates_str));
- foreach ($pairs as $pair) {
- $parts = explode(',', $pair);
- if (count($parts) >= 2) {
- $lon = floatval($parts[0]);
- $lat = floatval($parts[1]);
- // Ensure coordinates are valid
- if (is_finite($lat) && is_finite($lon)) {
- $coords[] = $lon;
- $coords[] = $lat;
- }
- }
- }
- return $coords;
-}
-?>
\ No newline at end of file
diff --git a/api/wildfires.php b/api/wildfires.php
index 2997d3d..b59c433 100644
--- a/api/wildfires.php
+++ b/api/wildfires.php
@@ -17,6 +17,25 @@ if ($response === false) {
exit;
}
-// Directly pass through the GeoJSON response
-echo $response;
+$data = json_decode($response, true);
+
+if (json_last_error() !== JSON_ERROR_NONE) {
+ echo json_encode(['error' => 'Could not parse wildfire data.']);
+ exit;
+}
+
+$features = $data['features'] ?? [];
+
+$wildfires = [];
+foreach ($features as $feature) {
+ $properties = $feature['properties'];
+ $wildfires[] = [
+ 'name' => $properties['poly_IncidentName'],
+ 'acres' => $properties['poly_Acres_AutoCalc'],
+ 'started' => $properties['attr_InitialResponseDateTime'],
+ 'percent_contained' => $properties['attr_PercentContained'],
+ ];
+}
+
+echo json_encode($wildfires);
?>
\ No newline at end of file
diff --git a/assets/css/custom.css b/assets/css/custom.css
index 1cccb0a..b7e55af 100644
--- a/assets/css/custom.css
+++ b/assets/css/custom.css
@@ -1,26 +1,44 @@
+
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background-color: #F8F9FA;
color: #212529;
- display: flex;
- flex-direction: column;
- min-height: 100vh;
- margin: 0;
-}
-
-main {
- flex-grow: 1;
- display: flex;
- flex-direction: column;
}
.navbar {
padding: 1rem 0;
- flex-shrink: 0;
}
-.hero, .hero-overlay {
- display: none; /* Hidden to make map primary */
+.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 {
@@ -40,14 +58,6 @@ section {
padding: 4rem 0;
}
-#map-widget {
- flex-grow: 1;
- padding: 0;
- display: flex;
- flex-direction: column;
- min-height: 80vh; /* Ensure section has height */
-}
-
h2 {
font-size: 2.5rem;
font-weight: 700;
@@ -70,7 +80,6 @@ h2 {
background-color: #003366;
color: white;
padding: 3rem 0;
- flex-shrink: 0;
}
.footer a {
@@ -92,20 +101,3 @@ h2 {
#wildfire-data .card {
background-color: #F8F9FA;
}
-
-html, body {
- height: 100%;
- width: 100%;
- margin: 0;
- padding: 0;
- overflow: hidden; /* Prevent scrollbars */
-}
-
-#cesiumContainer {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- border: none; /* Remove the debug border */
-}
\ No newline at end of file
diff --git a/assets/js/main.js b/assets/js/main.js
index afa6f63..a53341e 100644
--- a/assets/js/main.js
+++ b/assets/js/main.js
@@ -1,2 +1,104 @@
-// Initialize the Cesium Viewer in the 'cesiumContainer' DOM element.
-const viewer = new Cesium.Viewer('cesiumContainer');
\ No newline at end of file
+
+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);
+ });
+ }
+
+ // Fetch and display wildfire data
+ const wildfireDataContainer = document.getElementById('wildfire-data');
+ if (wildfireDataContainer) {
+ fetch('api/wildfires.php')
+ .then(response => response.json())
+ .then(data => {
+ if (data && data.length > 0) {
+ let html = '';
+ data.forEach(fire => {
+ html += `
+
+
+
+
${fire.name}
+
${fire.acres ? Math.round(fire.acres) + ' acres' : 'Size not available'}
+
${fire.percent_contained !== null ? fire.percent_contained + '% contained' : 'Containment not available'}
+
+
+
+ `;
+ });
+ wildfireDataContainer.innerHTML = html;
+ } else {
+ wildfireDataContainer.innerHTML = 'No active wildfires reported at the moment.
';
+ }
+ })
+ .catch(error => {
+ wildfireDataContainer.innerHTML = 'Could not load wildfire data. Please try again later.
';
+ console.error('Error fetching wildfire data:', error);
+ });
+ }
+});
diff --git a/assets/pasted-20251014-012612-96ac69da.png b/assets/pasted-20251014-012612-96ac69da.png
deleted file mode 100644
index e041336..0000000
Binary files a/assets/pasted-20251014-012612-96ac69da.png and /dev/null differ
diff --git a/index.php b/index.php
index 9852a1e..69b02b3 100644
--- a/index.php
+++ b/index.php
@@ -1,15 +1,162 @@
+
- Worldsphere.ai - 3D Weather Map
-
+ Worldsphere.ai - AI-Powered Weather Prediction
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
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...
+
+
+
+
+ Active Wildfires
+
+
Loading real-time wildfire 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
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file