Active Tropical Cyclones

This commit is contained in:
Flatlogic Bot 2025-10-13 16:57:50 +00:00
parent 28a6b3ca28
commit db94e7c618
10 changed files with 520 additions and 143 deletions

43
api/cyclone.php Normal file
View File

@ -0,0 +1,43 @@
<?php
header('Content-Type: application/json');
header('User-Agent: worldsphere.ai, contact@worldsphere.ai');
// URL for the SPC RSS feed
$url = 'http://www.spc.noaa.gov/products/spcrss.xml';
// Fetch the RSS feed content
$rss = @file_get_contents($url);
if ($rss === false) {
echo json_encode(['error' => '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);
?>

46
api/pexels.php Normal file
View File

@ -0,0 +1,46 @@
<?php
header('Content-Type: application/json');
require_once __DIR__.'/../includes/pexels.php';
// --- Configuration ---
$query = isset($_GET['query']) ? $_GET['query'] : 'hurricane';
$orientation = isset($_GET['orientation']) ? $_GET['orientation'] : 'landscape';
$cache_dir = __DIR__ . '/../assets/images/pexels/';
// --- End Configuration ---
// Ensure cache directory exists
if (!is_dir($cache_dir)) {
mkdir($cache_dir, 0775, true);
}
$url = 'https://api.pexels.com/v1/search?query=' . urlencode($query) . '&orientation=' . urlencode($orientation) . '&per_page=1&page=1';
$data = pexels_get($url);
if (!$data || empty($data['photos'])) {
http_response_code(500);
echo json_encode(['error' => '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,
]);

95
assets/css/custom.css Normal file
View File

@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

72
assets/js/main.js Normal file
View File

@ -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 = '<div class="alert alert-danger">Please fill out all fields.</div>';
return;
}
fetch('contact.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
status.innerHTML = `<div class="alert alert-success">${data.message}</div>`;
form.reset();
} else {
status.innerHTML = `<div class="alert alert-danger">${data.message}</div>`;
}
})
.catch(error => {
status.innerHTML = '<div class="alert alert-danger">An error occurred. Please try again.</div>';
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 += `
<div class="col-md-6 mb-4">
<div class="card h-100">
<div class="card-body d-flex flex-column">
<h5 class="card-title">${alert.headline}</h5>
<p class="card-text">${alert.description.substring(0, 150)}...</p>
<a href="${alert.link}" target="_blank" rel="noopener noreferrer" class="btn btn-primary btn-sm mt-auto">Read More</a>
</div>
</div>
</div>
`;
});
cycloneDataContainer.innerHTML = html;
} else {
cycloneDataContainer.innerHTML = '<div class="col-12"><p>No active severe weather alerts from the SPC at the moment.</p></div>';
}
})
.catch(error => {
cycloneDataContainer.innerHTML = '<p>Could not load cyclone data. Please try again later.</p>';
console.error('Error fetching cyclone data:', error);
});
}
});

34
contact.php Normal file
View File

@ -0,0 +1,34 @@
<?php
header('Content-Type: application/json');
// Basic validation
if (empty($_POST['name']) || empty($_POST['email']) || empty($_POST['message'])) {
echo json_encode(['success' => 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.']);
}

34
includes/pexels.php Normal file
View File

@ -0,0 +1,34 @@
<?php
function pexels_key() {
$k = getenv('PEXELS_KEY');
return $k && strlen($k) > 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;
}

289
index.php
View File

@ -1,150 +1,155 @@
<?php <?php
declare(strict_types=1); // Fetch a hurricane image from our local API endpoint
@ini_set('display_errors', '1'); $image_api_url = "http://" . $_SERVER['HTTP_HOST'] . "/api/pexels.php?query=hurricane&orientation=landscape";
@error_reporting(E_ALL); @$image_data_json = file_get_contents($image_api_url);
@date_default_timezone_set('UTC'); $image_data = $image_data_json ? json_decode($image_data_json, true) : null;
$hero_image_url = $image_data ? $image_data['local_path'] : 'https://images.pexels.com/photos/15033937/pexels-photo-15033937.jpeg'; // Fallback
$phpVersion = PHP_VERSION; $hero_image_alt = $image_data ? $image_data['alt'] : 'Satellite view of a hurricane';
$now = date('Y-m-d H:i:s');
?> ?>
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>New Style</title> <title>Worldsphere.ai - AI-Powered Weather Prediction</title>
<?php <meta name="description" content="Worldsphere.ai is revolutionizing climate resilience with AI-powered weather prediction.">
// Read project preview data from environment <meta name="keywords" content="ai weather prediction, climate resilience, hurricane forecasting, climate tech, big data analytics, weather risk management, diffusion models, satellite imagery analysis, Built with Flatlogic Generator">
$projectDescription = $_SERVER['PROJECT_DESCRIPTION'] ?? ''; <meta property="og:title" content="Worldsphere.ai - AI-Powered Weather Prediction">
$projectImageUrl = $_SERVER['PROJECT_IMAGE_URL'] ?? ''; <meta property="og:description" content="Revolutionizing Climate Resilience with AI-Powered Weather Prediction.">
?> <meta property="og:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
<?php if ($projectDescription): ?> <meta name="twitter:card" content="summary_large_image">
<!-- Meta description --> <meta name="twitter:image" content="<?php echo htmlspecialchars($_SERVER['PROJECT_IMAGE_URL'] ?? ''); ?>">
<meta name="description" content='<?= htmlspecialchars($projectDescription) ?>' />
<!-- Open Graph meta tags --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<meta property="og:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
<!-- Twitter meta tags --> <link rel="preconnect" href="https://fonts.googleapis.com">
<meta property="twitter:description" content="<?= htmlspecialchars($projectDescription) ?>" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<?php endif; ?> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet">
<?php if ($projectImageUrl): ?>
<!-- Open Graph image -->
<meta property="og:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<!-- Twitter image -->
<meta property="twitter:image" content="<?= htmlspecialchars($projectImageUrl) ?>" />
<?php endif; ?>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;700&display=swap" rel="stylesheet">
<style>
:root {
--bg-color-start: #6a11cb;
--bg-color-end: #2575fc;
--text-color: #ffffff;
--card-bg-color: rgba(255, 255, 255, 0.01);
--card-border-color: rgba(255, 255, 255, 0.1);
}
body {
margin: 0;
font-family: 'Inter', sans-serif;
background: linear-gradient(45deg, var(--bg-color-start), var(--bg-color-end));
color: var(--text-color);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
text-align: center;
overflow: hidden;
position: relative;
}
body::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M-10 10L110 10M10 -10L10 110" stroke-width="1" stroke="rgba(255,255,255,0.05)"/></svg>');
animation: bg-pan 20s linear infinite;
z-index: -1;
}
@keyframes bg-pan {
0% { background-position: 0% 0%; }
100% { background-position: 100% 100%; }
}
main {
padding: 2rem;
}
.card {
background: var(--card-bg-color);
border: 1px solid var(--card-border-color);
border-radius: 16px;
padding: 2rem;
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.1);
}
.loader {
margin: 1.25rem auto 1.25rem;
width: 48px;
height: 48px;
border: 3px solid rgba(255, 255, 255, 0.25);
border-top-color: #fff;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
.hint {
opacity: 0.9;
}
.sr-only {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap; border: 0;
}
h1 {
font-size: 3rem;
font-weight: 700;
margin: 0 0 1rem;
letter-spacing: -1px;
}
p {
margin: 0.5rem 0;
font-size: 1.1rem;
}
code {
background: rgba(0,0,0,0.2);
padding: 2px 6px;
border-radius: 4px;
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
position: absolute;
bottom: 1rem;
font-size: 0.8rem;
opacity: 0.7;
}
</style>
</head> </head>
<body> <body>
<main>
<div class="card"> <header class="navbar navbar-expand-lg navbar-light bg-light">
<h1>Analyzing your requirements and generating your website…</h1> <div class="container">
<div class="loader" role="status" aria-live="polite" aria-label="Applying initial changes"> <a class="navbar-brand fw-bold" href="#">Worldsphere.ai</a>
<span class="sr-only">Loading…</span> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
</div> <span class="navbar-toggler-icon"></span>
<p class="hint"><?= ($_SERVER['HTTP_HOST'] ?? '') === 'appwizzy.com' ? 'AppWizzy' : 'Flatlogic' ?> AI is collecting your requirements and applying the first changes.</p> </button>
<p class="hint">This page will update automatically as the plan is implemented.</p> <div class="collapse navbar-collapse" id="navbarNav">
<p>Runtime: PHP <code><?= htmlspecialchars($phpVersion) ?></code> — UTC <code><?= htmlspecialchars($now) ?></code></p> <ul class="navbar-nav ms-auto">
</div> <li class="nav-item"><a class="nav-link" href="#solutions">Solutions</a></li>
</main> <li class="nav-item"><a class="nav-link" href="#mission">About</a></li>
<footer> <li class="nav-item"><a class="nav-link" href="#contact">Contact</a></li>
Page updated: <?= htmlspecialchars($now) ?> (UTC) </ul>
</footer> </div>
</div>
</header>
<main>
<section class="hero text-center text-white" style="background-image: url('<?php echo htmlspecialchars($hero_image_url); ?>');">
<div class="hero-overlay">
<div class="container">
<p class="mb-3">First Beta Version now available! Download now</p>
<h1 class="display-3 fw-bold">Revolutionizing Climate Resilience with AI-Powered Weather Prediction</h1>
<p class="lead mt-4">Where Cutting-Edge Technology Meets Climate Action. At Worldsphere.ai, were harnessing the power of artificial intelligence to transform how we predict, prepare for, and respond to extreme weather events.</p>
<a href="#contact" class="btn btn-primary mt-4">Join the Climate Tech Revolution</a>
</div>
</div>
</section>
<section id="cyclone-widget" class="container text-center">
<h2>Active Tropical Cyclones</h2>
<div id="cyclone-data" class="row">
<p>Loading real-time cyclone data...</p>
</div>
</section>
<section id="solutions" class="container text-center">
<h2>Technology & Innovation</h2>
<p class="lead mb-5">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.</p>
<div class="row">
<div class="col-md-4 mb-4">
<div class="card h-100 p-4">
<h5 class="fw-bold">AI-Powered Hurricane Prediction</h5>
<p>Our flagship technology utilizes advanced diffusion models to revolutionize hurricane forecasting.</p>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 p-4">
<h5 class="fw-bold">Satellite-to-Wind Technology</h5>
<p>Generate realistic 2D wind fields from infrared satellite imagery and automatically remove land masses.</p>
</div>
</div>
<div class="col-md-4 mb-4">
<div class="card h-100 p-4">
<h5 class="fw-bold">Model Interpretability</h5>
<p>We bridge traditional meteorological frameworks and AI-generated insights by mapping atmospheric patterns to model activations.</p>
</div>
</div>
</div>
</section>
<section id="mission" class="bg-white">
<div class="container">
<div class="row align-items-center">
<div class="col-md-6">
<h2>Our Mission</h2>
<p class="lead">Empowering Global Resilience in the Face of Climate Change.</p>
<p>We recognize the urgency of the climate crisis. At Worldsphere.ai, were 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.</p>
</div>
<div class="col-md-6">
<h5 class="fw-bold">Our Core Objectives</h5>
<ul>
<li>Advance the field of Al-powered weather prediction</li>
<li>Improve early warning systems for extreme weather events</li>
<li>Support businesses and communities in climate risk management</li>
<li>Foster collaboration between technology and climate science</li>
</ul>
</div>
</div>
</div>
</section>
<section id="contact">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-8">
<div class="contact-form text-center">
<h2>Contact Us</h2>
<p>Sign up for our beta testing program and experience the future of weather risk management.</p>
<form id="contactForm" novalidate>
<div class="mb-3">
<input type="text" class="form-control" id="name" name="name" placeholder="Your Name" required>
</div>
<div class="mb-3">
<input type="email" class="form-control" id="email" name="email" placeholder="Your Email" required>
</div>
<div class="mb-3">
<textarea class="form-control" id="message" name="message" rows="5" placeholder="Your Message" required></textarea>
</div>
<button type="submit" class="btn btn-primary">Send Message</button>
</form>
<div id="form-status" class="mt-4"></div>
</div>
</div>
</div>
</div>
</section>
</main>
<footer class="footer">
<div class="container text-center">
<ul class="nav justify-content-center mb-3">
<li class="nav-item"><a href="#" class="nav-link px-2 text-white">LinkedIn</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-white">Instagram</a></li>
<li class="nav-item"><a href="#" class="nav-link px-2 text-white">x.com</a></li>
<li class="nav-item"><a href="privacy.php" class="nav-link px-2 text-white">Privacy Policy</a></li>
</ul>
<p>&copy; 2025 Worldsphere.ai. All Rights Reserved.</p>
<p>Reminder: click Save in the editor to sync changes.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="assets/js/main.js?v=<?php echo time(); ?>"></script>
</body> </body>
</html> </html>

35
privacy.php Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Privacy Policy - Worldsphere.ai</title>
<meta name="description" content="Privacy Policy for Worldsphere.ai.">
<meta name="robots" content="noindex, nofollow">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="assets/css/custom.css?v=<?php echo time(); ?>">
</head>
<body>
<header class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand fw-bold" href="index.php">Worldsphere.ai</a>
</div>
</header>
<main class="container py-5">
<h1>Privacy Policy</h1>
<p>This is a placeholder for the Privacy Policy page.</p>
<p>Information on how user data is collected, used, and protected will be detailed here.</p>
<a href="index.php">Return to Home</a>
</main>
<footer class="footer">
<div class="container text-center">
<p>&copy; 2025 Worldsphere.ai. All Rights Reserved.</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>

13
sitemap.xml Normal file
View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://<?php echo $_SERVER['HTTP_HOST']; ?>/index.php</loc>
<lastmod>2025-10-13</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://<?php echo $_SERVER['HTTP_HOST']; ?>/privacy.php</loc>
<lastmod>2025-10-13</lastmod>
<priority>0.80</priority>
</url>
</urlset>