gemini-3.5-flash @ medium · api
apimedium
- config
- gemini-3.5-flash-eff-medium--api--official--dev
- batch
- 2026-07-19--unified
- transport
- google-gemini-developer-api-openai-compat
- protocol
- api · metered
- served model
- gemini-3.5-flash
- captured
- Jul 18, 2026, 11:54 AM · N=4
variant
live
slot 0 · P-q · sandboxed iframe

The screenshot is the exact frozen pixels the similarity channels measured. Run live re-executes the raw output in a sandboxed iframe; its rendering depends on your browser and fonts and is not guaranteed to match the measured pixels.
similarity neighbors
nearest
mimo-v2.5-pro · opencode0.63claude-sonnet-5 @low · CC0.61glm-5 · kiro0.61glm-5.2-eff-enabled--api--official--dev0.61gpt-5.6-luna @max · codex-oauth0.61farthest
gpt-5.6-sol @ultra · codex-oauth0.44claude-sonnet-5 @max · CC0.44minimax-m2.1 · kiro0.47gpt-5.6-luna @none · codex-oauth0.47gpt-5.6-luna @high · kiro0.47within session 2026-07-19--unified
similarity measures convergence within this session — not quality.
Fidelity — does the card show the right data?
- namematch
- conditionmatch
- datematch
- max tempmatchshown: 25.3
- min tempmatchshown: 16
- hourlyambiguouscoverage · 0 match · 0 mismatch · 24 not shown
- request sidematch0 violation(s)
extractor fidelity-extractor-v1+Berlin-2026-07-15
Source — raw model output, one byte unchanged
download card.html<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather Dashboard</title>
<style>
/* System Font Stack & Reset */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: radial-gradient(circle at 50% 50%, #1a1e36 0%, #0d101d 100%);
color: #f8fafc;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}
/* Container fixed to 1280x800 for the ultimate desktop viewport presentation */
.app-container {
width: 1280px;
height: 800px;
background: rgba(15, 23, 42, 0.45);
backdrop-filter: blur(24px);
-webkit-backdrop-filter: blur(24px);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 32px;
box-shadow: 0 24px 64px rgba(0, 0, 0, 0.4);
display: flex;
overflow: hidden;
position: relative;
}
/* Background glow effects */
.app-container::before {
content: '';
position: absolute;
top: -150px;
left: -150px;
width: 400px;
height: 400px;
background: radial-gradient(circle, rgba(99, 102, 241, 0.15) 0%, rgba(99, 102, 241, 0) 70%);
pointer-events: none;
z-index: 0;
}
/* Left Hero Panel (38% width) */
.hero-panel {
width: 38%;
border-right: 1px solid rgba(255, 255, 255, 0.08);
padding: 48px;
display: flex;
flex-direction: column;
justify-content: space-between;
position: relative;
z-index: 1;
}
.location-info {
display: flex;
flex-direction: column;
gap: 8px;
}
.location-title {
font-size: 2.5rem;
font-weight: 800;
letter-spacing: -0.03em;
background: linear-gradient(135deg, #ffffff 0%, #cbd5e1 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
line-height: 1.1;
}
.coordinates-badge {
display: inline-flex;
align-items: center;
gap: 6px;
background: rgba(255, 255, 255, 0.06);
padding: 6px 12px;
border-radius: 100px;
font-size: 0.8rem;
color: #94a3b8;
width: fit-content;
font-family: monospace;
border: 1px solid rgba(255, 255, 255, 0.04);
}
.weather-hero-visual {
display: flex;
flex-direction: column;
align-items: center;
margin: 32px 0;
}
.hero-icon-container {
width: 180px;
height: 180px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.hero-icon-container svg {
width: 100%;
height: 100%;
filter: drop-shadow(0 10px 20px rgba(0,0,0,0.25));
}
.current-temp-block {
text-align: center;
margin-top: 16px;
}
.current-temp {
font-size: 5.5rem;
font-weight: 300;
letter-spacing: -0.04em;
line-height: 1;
position: relative;
display: inline-block;
}
.current-temp::after {
content: '°';
position: absolute;
top: 0;
right: -24px;
font-size: 3.5rem;
font-weight: 300;
color: #a5b4fc;
}
.condition-text {
font-size: 1.4rem;
font-weight: 500;
color: #e2e8f0;
margin-top: 8px;
}
.date-badge {
font-size: 1rem;
font-weight: 500;
color: #818cf8;
text-transform: uppercase;
letter-spacing: 0.05em;
}
/* Right Metrics & Forecast Panel (62% width) */
.dashboard-panel {
width: 62%;
padding: 48px;
display: flex;
flex-direction: column;
justify-content: space-between;
z-index: 1;
}
.panel-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.section-title {
font-size: 1.1rem;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.1em;
color: #94a3b8;
}
/* Highlight Cards Grid */
.highlights-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
margin-bottom: 32px;
}
.metric-card {
background: rgba(255, 255, 255, 0.03);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 18px;
padding: 24px;
display: flex;
align-items: center;
gap: 20px;
transition: background 0.3s ease;
}
.metric-card:hover {
background: rgba(255, 255, 255, 0.05);
}
.metric-icon-wrapper {
width: 52px;
height: 52px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
}
.icon-max {
background: rgba(239, 68, 68, 0.15);
color: #f87171;
}
.icon-min {
background: rgba(59, 130, 246, 0.15);
color: #60a5fa;
}
.metric-details {
display: flex;
flex-direction: column;
}
.metric-label {
font-size: 0.85rem;
color: #94a3b8;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 4px;
}
.metric-value {
font-size: 1.8rem;
font-weight: 700;
}
/* Chart Area */
.chart-container {
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: 20px;
padding: 24px;
flex-grow: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
margin-bottom: 32px;
position: relative;
}
.chart-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.chart-canvas-wrapper {
position: relative;
width: 100%;
height: 180px;
}
/* Hourly Forecast Track */
.hourly-track {
display: flex;
gap: 12px;
overflow-x: auto;
padding-bottom: 8px;
}
/* Style thin elegant scrollbar */
.hourly-track::-webkit-scrollbar {
height: 6px;
}
.hourly-track::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.02);
border-radius: 10px;
}
.hourly-track::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.hourly-item {
flex: 0 0 calc(100% / 8 - 11px);
background: rgba(255, 255, 255, 0.02);
border: 1px solid rgba(255, 255, 255, 0.04);
border-radius: 14px;
padding: 12px;
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
transition: all 0.3s ease;
}
.hourly-item:hover {
background: rgba(255, 255, 255, 0.05);
transform: translateY(-2px);
}
.hourly-time {
font-size: 0.75rem;
color: #94a3b8;
font-weight: 600;
}
.hourly-icon {
width: 32px;
height: 32px;
}
.hourly-temp {
font-size: 0.95rem;
font-weight: 700;
}
/* Error Overlay State */
.error-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(15, 23, 42, 0.95);
z-index: 10;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 16px;
border-radius: 32px;
opacity: 0;
pointer-events: none;
transition: opacity 0.3s ease;
}
.error-overlay.active {
opacity: 1;
pointer-events: auto;
}
.error-icon {
color: #f87171;
width: 64px;
height: 64px;
}
.error-title {
font-size: 1.5rem;
font-weight: 700;
}
.error-msg {
color: #94a3b8;
font-size: 1rem;
max-width: 400px;
text-align: center;
line-height: 1.5;
}
/* Loading overlay */
.loading-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: #0d101d;
z-index: 11;
display: flex;
justify-content: center;
align-items: center;
border-radius: 32px;
transition: opacity 0.4s ease;
}
.loading-spinner {
width: 50px;
height: 50px;
border: 3px solid rgba(255, 255, 255, 0.1);
border-top-color: #818cf8;
border-radius: 50%;
animation: spin 1s infinite linear;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* Beautiful CSS keyframes for Weather Icons */
@keyframes float {
0% { transform: translateY(0px); }
50% { transform: translateY(-8px); }
100% { transform: translateY(0px); }
}
@keyframes spin-slow {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes pulse-glow {
0% { opacity: 0.6; }
50% { opacity: 0.9; }
100% { opacity: 0.6; }
}
.animated-float {
animation: float 4s ease-in-out infinite;
}
.animated-spin {
animation: spin-slow 20s linear infinite;
transform-origin: center;
}
.animated-glow {
animation: pulse-glow 3s ease-in-out infinite;
}
</style>
</head>
<body>
<div class="app-container">
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="loading-spinner"></div>
</div>
<!-- Error State Overlay -->
<div class="error-overlay" id="errorOverlay">
<svg class="error-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
</svg>
<div class="error-title">Failed to Load Weather</div>
<div class="error-msg" id="errorMsg">Please verify your parameters and check your network connection.</div>
</div>
<!-- Left Hero Column -->
<section class="hero-panel">
<div class="location-info">
<span class="date-badge" id="dateBadge">Date display</span>
<h1 class="location-title" id="locationTitle">City Location</h1>
<div class="coordinates-badge">
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M15 10.5a3 3 0 11-6 0 3 3 0 016 0z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 10.5c0 7.142-7.5 11.25-7.5 11.25S4.5 17.642 4.5 10.5a7.5 7.5 0 1115 0z" />
</svg>
<span id="coordsDisplay">0.000°N, 0.000°E</span>
</div>
</div>
<div class="weather-hero-visual">
<div class="hero-icon-container" id="heroIconContainer">
<!-- Dynamically populated main icon SVG -->
</div>
<div class="current-temp-block">
<div class="current-temp" id="currentTempDisplay">--</div>
<div class="condition-text" id="conditionText">Determining sky condition...</div>
</div>
</div>
<div style="opacity: 0.5; font-size: 0.8rem; letter-spacing: 0.05em; text-transform: uppercase;">
Daily Forecast Summary
</div>
</section>
<!-- Right Detailed Dashboard Column -->
<section class="dashboard-panel">
<!-- Top: Dynamic Extreme Indicators -->
<div>
<div class="panel-header">
<h2 class="section-title">Today's Extremes</h2>
</div>
<div class="highlights-grid">
<div class="metric-card">
<div class="metric-icon-wrapper icon-max">
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5L12 3m0 0l7.5 7.5M12 3v18" />
</svg>
</div>
<div class="metric-details">
<span class="metric-label">Max Temperature</span>
<span class="metric-value" id="maxTempDisplay">--°C</span>
</div>
</div>
<div class="metric-card">
<div class="metric-icon-wrapper icon-min">
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 13.5L12 21m0 0l-7.5-7.5M12 21V3" />
</svg>
</div>
<div class="metric-details">
<span class="metric-label">Min Temperature</span>
<span class="metric-value" id="minTempDisplay">--°C</span>
</div>
</div>
</div>
</div>
<!-- Center: 24h Trend Chart Dynamic SVG Area -->
<div class="chart-container">
<div class="chart-header">
<h2 class="section-title" style="margin-bottom: 0;">24-Hour Temperature Curve</h2>
<span style="font-size: 0.8rem; color: #818cf8; font-weight: 500;" id="chartRange">--</span>
</div>
<div class="chart-canvas-wrapper" id="chartWrapper">
<!-- Will draw beautiful high-fidelity SVG path -->
</div>
</div>
<!-- Bottom: Fast scrolling interval track (sampled 24h) -->
<div>
<div class="panel-header" style="margin-bottom: 12px;">
<h2 class="section-title">Hourly Projection</h2>
</div>
<div class="hourly-track" id="hourlyTrack">
<!-- Populated dynamically via JS loop -->
</div>
</div>
</section>
</div>
<script>
// Configured parameters & defaults (UTC)
const urlParams = new URLSearchParams(window.location.search);
const lat = parseFloat(urlParams.get('lat')) || 52.52;
const lon = parseFloat(urlParams.get('lon')) || 13.405;
const locationName = urlParams.get('name') || 'Berlin';
// Fallback to today (UTC) formatted as YYYY-MM-DD
const todayUTCString = new Date().toISOString().split('T')[0];
const targetDateStr = urlParams.get('date') || todayUTCString;
// Interpret WMO Codes into user-friendly names and visual classes
function mapWeather(code) {
const wmoData = {
0: { text: "Clear Sky", iconClass: "clear" },
1: { text: "Mainly Clear", iconClass: "mostly-clear" },
2: { text: "Partly Cloudy", iconClass: "cloudy" },
3: { text: "Overcast", iconClass: "overcast" },
45: { text: "Foggy", iconClass: "fog" },
48: { text: "Depositing Rime Fog", iconClass: "fog" },
51: { text: "Light Drizzle", iconClass: "drizzle" },
53: { text: "Moderate Drizzle", iconClass: "drizzle" },
55: { text: "Dense Drizzle", iconClass: "drizzle" },
56: { text: "Light Freezing Drizzle", iconClass: "drizzle" },
57: { text: "Dense Freezing Drizzle", iconClass: "drizzle" },
61: { text: "Slight Rain", iconClass: "rain" },
63: { text: "Moderate Rain", iconClass: "rain" },
65: { text: "Heavy Rain", iconClass: "rain" },
66: { text: "Light Freezing Rain", iconClass: "rain" },
67: { text: "Heavy Freezing Rain", iconClass: "rain" },
71: { text: "Slight Snowfall", iconClass: "snow" },
73: { text: "Moderate Snowfall", iconClass: "snow" },
75: { text: "Heavy Snowfall", iconClass: "snow" },
77: { text: "Snow Grains", iconClass: "snow" },
80: { text: "Slight Rain Showers", iconClass: "rain" },
81: { text: "Moderate Rain Showers", iconClass: "rain" },
82: { text: "Violent Rain Showers", iconClass: "rain" },
85: { text: "Slight Snow Showers", iconClass: "snow" },
86: { text: "Heavy Snow Showers", iconClass: "snow" },
95: { text: "Thunderstorm", iconClass: "storm" },
96: { text: "Thunderstorm with Hail", iconClass: "storm" },
99: { text: "Heavy Thunderstorm", iconClass: "storm" }
};
return wmoData[code] || { text: "Variable Skies", iconClass: "clear" };
}
// Dynamic High Fidelity SVGs representing specific weather conditions
function generateWeatherSVG(iconClass, size = 120, animated = true) {
const animClass = animated ? 'animated-float' : '';
const spinClass = animated ? 'animated-spin' : '';
const glowClass = animated ? 'animated-glow' : '';
switch(iconClass) {
case 'clear':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<radialGradient id="sunGlow" cx="50%" cy="50%" r="50%">
<stop offset="0%" stop-color="#fbbf24" stop-opacity="1"/>
<stop offset="100%" stop-color="#d97706" stop-opacity="0.2"/>
</radialGradient>
</defs>
<circle class="${glowClass}" cx="50" cy="50" r="28" fill="url(#sunGlow)"/>
<circle class="${spinClass}" cx="50" cy="50" r="16" fill="#f59e0b" stroke="#fef08a" stroke-width="2"/>
</svg>
`;
case 'mostly-clear':
case 'cloudy':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="cloudGrad" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#ffffff"/>
<stop offset="100%" stop-color="#cbd5e1"/>
</linearGradient>
<linearGradient id="sunPart" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#fbbf24"/>
<stop offset="100%" stop-color="#f59e0b"/>
</linearGradient>
</defs>
<circle cx="62" cy="38" r="15" fill="url(#sunPart)"/>
<path d="M32 68 h36 a18 18 0 0 0 0 -36 a18 18 0 0 0 -14 -7 a22 22 0 0 0 -22 22 a18 18 0 0 0 0 21 z" fill="url(#cloudGrad)" filter="drop-shadow(0px 8px 12px rgba(15,23,42,0.25))"/>
</svg>
`;
case 'overcast':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="darkCloud" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#94a3b8"/>
<stop offset="100%" stop-color="#475569"/>
</linearGradient>
</defs>
<path d="M28 65 h40 a16 16 0 0 0 0 -32 a16 16 0 0 0 -12 -6 a20 20 0 0 0 -20 20 a16 16 0 0 0 0 18 z" fill="url(#darkCloud)" filter="drop-shadow(0px 8px 12px rgba(0,0,0,0.3))"/>
</svg>
`;
case 'fog':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="fogGrad" x1="0%" y1="0%" x2="100%">
<stop offset="0%" stop-color="#94a3b8" stop-opacity="0.2"/>
<stop offset="50%" stop-color="#e2e8f0" stop-opacity="0.8"/>
<stop offset="100%" stop-color="#94a3b8" stop-opacity="0.2"/>
</linearGradient>
</defs>
<rect x="15" y="35" width="70" height="6" rx="3" fill="url(#fogGrad)"/>
<rect x="25" y="47" width="50" height="6" rx="3" fill="url(#fogGrad)"/>
<rect x="18" y="59" width="64" height="6" rx="3" fill="url(#fogGrad)"/>
<rect x="30" y="71" width="40" height="6" rx="3" fill="url(#fogGrad)"/>
</svg>
`;
case 'rain':
case 'drizzle':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="rainCloud" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#64748b"/>
<stop offset="100%" stop-color="#334155"/>
</linearGradient>
</defs>
<path d="M30 58 h40 a16 16 0 0 0 0 -32 a16 16 0 0 0 -12 -6 a20 20 0 0 0 -20 20 a16 16 0 0 0 0 18 z" fill="url(#rainCloud)"/>
<line x1="38" y1="68" x2="34" y2="80" stroke="#60a5fa" stroke-width="3" stroke-linecap="round"/>
<line x1="50" y1="68" x2="46" y2="80" stroke="#60a5fa" stroke-width="3" stroke-linecap="round"/>
<line x1="62" y1="68" x2="58" y2="80" stroke="#60a5fa" stroke-width="3" stroke-linecap="round"/>
</svg>
`;
case 'snow':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="snowCloud" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#cbd5e1"/>
<stop offset="100%" stop-color="#94a3b8"/>
</linearGradient>
</defs>
<path d="M30 58 h40 a16 16 0 0 0 0 -32 a16 16 0 0 0 -12 -6 a20 20 0 0 0 -20 20 a16 16 0 0 0 0 18 z" fill="url(#snowCloud)"/>
<!-- Flakes -->
<circle cx="36" cy="72" r="3" fill="#f8fafc"/>
<circle cx="50" cy="76" r="3" fill="#f8fafc"/>
<circle cx="64" cy="71" r="3" fill="#f8fafc"/>
</svg>
`;
case 'storm':
return `
<svg class="${animClass}" viewBox="0 0 100 100" width="${size}" height="${size}">
<defs>
<linearGradient id="stormCloud" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#475569"/>
<stop offset="100%" stop-color="#1e293b"/>
</linearGradient>
</defs>
<path d="M30 58 h40 a16 16 0 0 0 0 -32 a16 16 0 0 0 -12 -6 a20 20 0 0 0 -20 20 a16 16 0 0 0 0 18 z" fill="url(#stormCloud)"/>
<path d="M48 62 L40 76 L49 76 L44 90 L58 72 L49 72 Z" fill="#fbbf24" stroke="#f59e0b" stroke-width="1"/>
</svg>
`;
default:
return `
<svg viewBox="0 0 100 100" width="${size}" height="${size}">
<circle cx="50" cy="50" r="20" fill="#cbd5e1"/>
</svg>
`;
}
}
// Dynamic Chart rendering within the exact coordinates
function generateInteractiveSVGChart(hourlyTemps) {
const width = 712; // Native proportional container width
const height = 150;
const paddingLeft = 32;
const paddingRight = 32;
const paddingTop = 20;
const paddingBottom = 20;
const minTemp = Math.min(...hourlyTemps);
const maxTemp = Math.max(...hourlyTemps);
const range = maxTemp - minTemp === 0 ? 1 : maxTemp - minTemp;
// Project array of 24 points to graphic mapping space
const points = hourlyTemps.map((temp, index) => {
const x = paddingLeft + (index / 23) * (width - paddingLeft - paddingRight);
// Flip SVG coordinates natively (higher temperature is higher on the screen)
const y = height - paddingBottom - ((temp - minTemp) / range) * (height - paddingTop - paddingBottom);
return [x, y];
});
// Construct Smooth Cubic Bezier Curves representing the temperatures
let pathData = `M ${points[0][0]} ${points[0][1]}`;
for (let i = 0; i < points.length - 1; i++) {
const p0 = points[i];
const p1 = points[i + 1];
const cpX1 = p0[0] + (p1[0] - p0[0]) / 2;
const cpY1 = p0[1];
const cpX2 = p0[0] + (p1[0] - p0[0]) / 2;
const cpY2 = p1[1];
pathData += ` C ${cpX1} ${cpY1}, ${cpX2} ${cpY2}, ${p1[0]} ${p1[1]}`;
}
// Smooth Area underneath temperature visual plot line
const areaPath = `
${pathData}
L ${points[points.length - 1][0]} ${height - paddingBottom}
L ${points[0][0]} ${height - paddingBottom}
Z
`;
// Build grid line parameters dynamically
const segmentsY = 3;
let gridLines = '';
for (let i = 0; i <= segmentsY; i++) {
const tempVal = minTemp + (i / segmentsY) * (maxTemp - minTemp);
const y = height - paddingBottom - (i / segmentsY) * (height - paddingTop - paddingBottom);
gridLines += `
<line x1="${paddingLeft}" y1="${y}" x2="${width - paddingRight}" y2="${y}" stroke="rgba(255,255,255,0.04)" stroke-dasharray="4 4" />
<text x="${paddingLeft - 10}" y="${y + 4}" fill="#64748b" font-size="10" font-weight="600" text-anchor="end">${tempVal.toFixed(1)}°</text>
`;
}
// X-Axis hour markers sampled dynamically
let xLabels = '';
[0, 4, 8, 12, 16, 20, 23].forEach(idx => {
const p = points[idx];
const hrString = idx < 10 ? `0${idx}:00` : `${idx}:00`;
xLabels += `
<text x="${p[0]}" y="${height - 2}" fill="#64748b" font-size="10" font-weight="600" text-anchor="middle">${hrString}</text>
`;
});
return `
<svg viewBox="0 0 ${width} ${height}" width="100%" height="100%">
<defs>
<linearGradient id="chartLineGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#818cf8"/>
<stop offset="100%" stop-color="#34d399"/>
</linearGradient>
<linearGradient id="chartAreaGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#818cf8" stop-opacity="0.25"/>
<stop offset="100%" stop-color="#818cf8" stop-opacity="0"/>
</linearGradient>
</defs>
<!-- Horizontal reference helpers -->
${gridLines}
<!-- Underlay area gradient fills -->
<path d="${areaPath}" fill="url(#chartAreaGrad)" />
<!-- Dynamic stroke outline paths -->
<path d="${pathData}" fill="none" stroke="url(#chartLineGrad)" stroke-width="3.5" stroke-linecap="round" />
<!-- Interactive coordinate indicators -->
${points.filter((_, idx) => idx % 4 === 0 || idx === 23).map((p, idx) => `
<circle cx="${p[0]}" cy="${p[1]}" r="4" fill="#1e293b" stroke="#34d399" stroke-width="2.5" />
`).join('')}
<!-- Text timeline labels -->
${xLabels}
</svg>
`;
}
// Build the dynamic UI elements using fetched Open-Meteo context data
function updateUI(data) {
// Clean UI element variables
const maxTemp = data.daily.temperature_2m_max[0];
const minTemp = data.daily.temperature_2m_min[0];
const code = data.daily.weather_code[0];
const weatherMap = mapWeather(code);
// 1. Coordinates, City Location & Main Info Text fields
document.title = `${locationName} Weather Dashboard`;
document.getElementById('locationTitle').innerText = locationName;
document.getElementById('coordsDisplay').innerText = `${lat.toFixed(3)}°N, ${lon.toFixed(3)}°E`;
// Target localized Date Output mapping
const dateOption = { weekday: 'long', year: 'numeric', month: 'short', day: 'numeric' };
const parsedTargetDate = new Date(targetDateStr + 'T00:00:00Z');
document.getElementById('dateBadge').innerText = parsedTargetDate.toLocaleDateString('en-US', dateOption);
// 2. Load and present Weather Hero visualizations
document.getElementById('heroIconContainer').innerHTML = generateWeatherSVG(weatherMap.iconClass, 160, true);
document.getElementById('conditionText').innerText = weatherMap.text;
// Main central highlight temperature indicator
// Approximate temperature representation: mid-point of day extremes
const currentEstimate = Math.round((maxTemp + minTemp) / 2);
document.getElementById('currentTempDisplay').innerText = currentEstimate;
// 3. Peak Extremes High/Low blocks
document.getElementById('maxTempDisplay').innerText = `${maxTemp.toFixed(1)}°C`;
document.getElementById('minTempDisplay').innerText = `${minTemp.toFixed(1)}°C`;
// 4. Render native vector-scalable line representation
const hourlyTemps = data.hourly.temperature_2m;
document.getElementById('chartRange').innerText = `${Math.min(...hourlyTemps).toFixed(1)}°C — ${Math.max(...hourlyTemps).toFixed(1)}°C`;
document.getElementById('chartWrapper').innerHTML = generateInteractiveSVGChart(hourlyTemps);
// 5. Grid/Row Track representing specific standard hourly intervals
const hourlyTrack = document.getElementById('hourlyTrack');
hourlyTrack.innerHTML = '';
// Sample standard timestamps dynamically
const trackIntervals = [0, 3, 6, 9, 12, 15, 18, 21];
trackIntervals.forEach(hour => {
const hourTemp = hourlyTemps[hour];
const formattedHour = hour < 10 ? `0${hour}:00` : `${hour}:00`;
// Approximate micro-weather condition logic mapping (slightly simplified variant of core sky code)
const hourlyItem = document.createElement('div');
hourlyItem.className = 'hourly-item';
hourlyItem.innerHTML = `
<div class="hourly-time">${formattedHour}</div>
<div class="hourly-icon">${generateWeatherSVG(weatherMap.iconClass, 32, false)}</div>
<div class="hourly-temp">${Math.round(hourTemp)}°</div>
`;
hourlyTrack.appendChild(hourlyItem);
});
}
// Initialize API request logic flows
async function loadWeatherData() {
const loader = document.getElementById('loadingOverlay');
const errorOverlay = document.getElementById('errorOverlay');
try {
// Evaluate historical criteria comparison using baseline requested date values
const todayUTC = new Date().toISOString().split('T')[0];
const useArchive = targetDateStr < todayUTC;
const baseEndpoint = useArchive
? '/api/om/archive'
: '/api/om/forecast';
const requestParams = new URLSearchParams({
latitude: lat,
longitude: lon,
daily: 'temperature_2m_max,temperature_2m_min,weather_code',
hourly: 'temperature_2m',
timezone: 'UTC',
temperature_unit: 'celsius',
start_date: targetDateStr,
end_date: targetDateStr
});
const fullRequestURL = `${baseEndpoint}?${requestParams.toString()}`;
const response = await fetch(fullRequestURL);
if (!response.ok) {
throw new Error(`API server connection issue (Code: ${response.status})`);
}
const data = await response.json();
// Confirm structured arrays exist within localized parsed payloads
if (!data.daily || !data.hourly) {
throw new Error("Invalid or empty data structures returned from weather system.");
}
// Apply rendering sequence mapping
updateUI(data);
// Terminate loaders
loader.style.opacity = '0';
setTimeout(() => loader.style.display = 'none', 400);
} catch (err) {
console.error(err);
document.getElementById('errorMsg').innerText = err.message || "Failed to load weather data.";
errorOverlay.classList.add('active');
loader.style.display = 'none';
}
}
// Trigger Initial Lifecycle
window.addEventListener('DOMContentLoaded', loadWeatherData);
</script>
</body>
</html>L1 — cheap deterministic descriptors
| bytes total | 31,631 | html / css / js | 4,647 / 9,219 / 17,765 |
|---|---|---|---|
| dom nodes | 59 | dom depth | 9 |
| css rules | 64 | js present | yes |
| brightness | 29.2 | contrast | 16.4 |
| colorfulness | 12.4 | whitespace | 91.7% |
This slot's telemetry
| prompt tokens | 348 | completion tokens | 10,783 |
|---|---|---|---|
| total tokens | 11,131 | wall | 44.7 s |
| cost | — | request id | — |
config.json602 B
{
"N": 4,
"auth": {
"credential_ref": "WCB_GEMINI_KEY",
"method": "api-key"
},
"billing": "metered",
"config_id": "gemini-3.5-flash-eff-medium--api--official--dev",
"effort": "medium",
"family": "gemini",
"m": {
"min": 4,
"q": 4
},
"model_id": "gemini-3.5-flash",
"protocol": "api",
"served_model": "gemini-3.5-flash",
"telemetry": {
"completion_tokens": 82073,
"cost_usd": null,
"prompt_tokens": 2748,
"total_tokens": 84821,
"wall_ms": 434200
},
"transport": "google-gemini-developer-api-openai-compat",
"vendor_sanction_ref": null
}send-log4.7 KB
{
"N": 4,
"batch_id": "2026-07-20--official-gemini",
"config_id": "gemini-3.5-flash-eff-medium--api--official--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:45:44.079657+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:44:56.708615+00:00"
}
],
"block_index": 0,
"model_reaching_attempt_index": 0,
"slot_index": 0,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:46:32.208926+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:45:47.478319+00:00"
}
],
"block_index": 0,
"model_reaching_attempt_index": 0,
"slot_index": 0,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:47:48.986254+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:46:36.334063+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:48:56.339601+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:47:52.273062+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:49:49.112838+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:48:59.817519+00:00"
}
],
"block_index": 2,
"model_reaching_attempt_index": 0,
"slot_index": 2,
"terminal_state": "valid",
"variant": "P-q"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:50:30.239640+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:49:52.222200+00:00"
}
],
"block_index": 2,
"model_reaching_attempt_index": 0,
"slot_index": 2,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:51:19.919044+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:50:33.690223+00:00"
}
],
"block_index": 3,
"model_reaching_attempt_index": 0,
"slot_index": 3,
"terminal_state": "valid",
"variant": "P-min"
},
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-19T15:52:35.018875+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-19T15:51:23.172432+00:00"
}
],
"block_index": 3,
"model_reaching_attempt_index": 0,
"slot_index": 3,
"terminal_state": "valid",
"variant": "P-q"
}
],
"retry_policy": {
"max_unreachable_retries": 5,
"rate_limit_backoff": {
"max_attempts": 4,
"max_total_ms": 60000
}
}
}