nemotron-3-ultra-free · api
api
- config
- nemotron-3-ultra-free--zen-free--dev
- batch
- 2026-07-19--unified
- transport
- opencode-zen-free-tier
- protocol
- api · plan
- served model
- nemotron-3-ultra-free
- captured
- Jul 18, 2026, 11:54 AM · N=2
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
deepseek-v4-flash · go0.64grok-4.3 @medium · api0.63mimo-v2.5-free · api0.63minimax-m2.5 · kiro0.63claude-opus-4-6 @high · kiro0.61farthest
minimax-m2.1 · kiro0.38minimax-m2.5 · go0.41claude-opus-4-8 @xhigh · kiro0.42claude-fable-5 @xhigh · CC0.42grok-4.5 · go0.44within 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 tempambiguousno-remaining-candidate
- 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=1280, height=800">
<title>Weather Card</title>
<style>
:root {
--bg: #0d1117;
--card-bg: rgba(22, 27, 34, 0.9);
--card-border: rgba(48, 54, 61, 0.6);
--text-primary: #e6edf3;
--text-secondary: #8b949e;
--text-muted: #6e7681;
--accent: #58a6ff;
--accent-warm: #f78166;
--accent-cool: #39c5cf;
--accent-sun: #d2a106;
--shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
--shadow-inner: inset 0 1px 0 rgba(255, 255, 255, 0.05);
--radius: 16px;
--radius-sm: 8px;
--transition: 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
@media (prefers-color-scheme: light) {
:root {
--bg: #f6f8fa;
--card-bg: rgba(255, 255, 255, 0.95);
--card-border: rgba(209, 213, 218, 0.6);
--text-primary: #1f2328;
--text-secondary: #57606a;
--text-muted: #8b949e;
--accent: #0969da;
--accent-warm: #cf222e;
--accent-cool: #0598bc;
--accent-sun: #9a6700;
--shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
--shadow-inner: inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
@font-face {
font-family: 'Inter';
src: local('Inter'), local('system-ui');
font-display: swap;
}
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
background: var(--bg);
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
color: var(--text-primary);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse 80% 50% at 50% -20%, rgba(88, 166, 255, 0.15), transparent),
radial-gradient(ellipse 60% 40% at 100% 100%, rgba(57, 197, 207, 0.1), transparent);
pointer-events: none;
z-index: -1;
}
.weather-card {
width: 100%;
max-width: 520px;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: var(--radius);
box-shadow: var(--shadow), var(--shadow-inner);
overflow: hidden;
backdrop-filter: blur(20px);
animation: slideUp 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.card-header {
padding: 28px 28px 16px;
border-bottom: 1px solid var(--card-border);
background: linear-gradient(180deg, rgba(88, 166, 255, 0.08), transparent);
}
.location-row {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 8px;
}
.location-icon {
width: 20px;
height: 20px;
color: var(--accent);
flex-shrink: 0;
}
.location-name {
font-size: 20px;
font-weight: 600;
letter-spacing: -0.02em;
color: var(--text-primary);
}
.date-row {
display: flex;
align-items: center;
gap: 10px;
color: var(--text-secondary);
font-size: 14px;
}
.date-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
}
.card-main {
padding: 24px 28px;
display: grid;
grid-template-columns: 1fr auto;
gap: 24px;
align-items: start;
}
.current-weather {
min-width: 0;
}
.condition-badge {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 6px 12px;
background: rgba(88, 166, 255, 0.12);
border: 1px solid rgba(88, 166, 255, 0.25);
border-radius: 100px;
font-size: 13px;
font-weight: 500;
color: var(--accent);
margin-bottom: 16px;
animation: fadeIn 0.4s ease 0.1s both;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.condition-icon {
width: 18px;
height: 18px;
flex-shrink: 0;
}
.temp-display {
display: flex;
align-items: flex-start;
gap: 4px;
margin-bottom: 6px;
}
.temp-max {
font-size: 64px;
font-weight: 700;
line-height: 1;
letter-spacing: -0.03em;
color: var(--text-primary);
font-variant-numeric: tabular-nums;
}
.temp-unit {
font-size: 28px;
font-weight: 500;
color: var(--text-secondary);
margin-top: 8px;
}
.temp-min-row {
display: flex;
align-items: center;
gap: 16px;
color: var(--text-secondary);
font-size: 15px;
}
.temp-min-item {
display: flex;
align-items: center;
gap: 6px;
}
.temp-min-label {
color: var(--text-muted);
font-size: 13px;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.temp-min-value {
font-weight: 600;
color: var(--text-primary);
font-variant-numeric: tabular-nums;
}
.weather-visual {
width: 120px;
height: 120px;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
animation: float 3s ease-in-out infinite;
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-6px); }
}
.hourly-section {
margin-top: 8px;
padding-top: 24px;
border-top: 1px solid var(--card-border);
}
.hourly-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.hourly-title {
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--text-muted);
}
.hourly-chart {
height: 140px;
position: relative;
}
.chart-canvas {
width: 100%;
height: 100%;
display: block;
}
.chart-labels {
position: absolute;
bottom: -20px;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
font-size: 11px;
color: var(--text-muted);
pointer-events: none;
}
.hourly-tooltip {
position: absolute;
background: var(--card-bg);
border: 1px solid var(--card-border);
border-radius: var(--radius-sm);
padding: 8px 12px;
font-size: 12px;
pointer-events: none;
opacity: 0;
transform: translate(-50%, -100%) scale(0.9);
transition: opacity 0.15s ease, transform 0.15s ease;
z-index: 10;
box-shadow: var(--shadow);
white-space: nowrap;
}
.hourly-tooltip.visible {
opacity: 1;
transform: translate(-50%, -100%) scale(1);
}
.tooltip-time {
color: var(--text-secondary);
margin-bottom: 2px;
}
.tooltip-temp {
font-weight: 600;
color: var(--text-primary);
font-variant-numeric: tabular-nums;
}
.error-state {
padding: 48px 28px;
text-align: center;
color: var(--text-secondary);
}
.error-icon {
width: 48px;
height: 48px;
margin: 0 auto 16px;
color: var(--accent-warm);
opacity: 0.7;
}
.error-title {
font-size: 18px;
font-weight: 600;
color: var(--text-primary);
margin-bottom: 8px;
}
.error-message {
font-size: 14px;
line-height: 1.6;
}
.loading-state {
padding: 48px 28px;
text-align: center;
color: var(--text-secondary);
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 16px;
border: 3px solid var(--card-border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.loading-text {
font-size: 14px;
}
.chart-point {
position: absolute;
width: 10px;
height: 10px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--card-bg);
box-shadow: 0 0 0 2px var(--accent);
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.15s ease, transform 0.15s ease;
z-index: 5;
pointer-events: none;
}
.chart-point:hover,
.chart-point.active {
opacity: 1;
transform: translate(-50%, -50%) scale(1.3);
}
.chart-line {
fill: none;
stroke: var(--accent);
stroke-width: 2.5;
stroke-linecap: round;
stroke-linejoin: round;
filter: drop-shadow(0 2px 8px rgba(88, 166, 255, 0.3));
}
.chart-area {
fill: url(#temp-gradient);
}
@media (max-width: 560px) {
.card-main {
grid-template-columns: 1fr;
gap: 16px;
}
.weather-visual {
width: 100px;
height: 100px;
margin: 0 auto;
}
.temp-max {
font-size: 56px;
}
}
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
</style>
</head>
<body>
<article class="weather-card" id="card">
<div class="loading-state" id="loading">
<div class="spinner" aria-hidden="true"></div>
<div class="loading-text">Loading weather data…</div>
</div>
</article>
<script>
// Weather code to condition mapping
const WEATHER_CODES = {
0: { label: 'Clear sky', icon: 'sun', gradient: ['#f7d745', '#f5a623'] },
1: { label: 'Mainly clear', icon: 'sun-cloud', gradient: ['#f7d745', '#a8c0d0'] },
2: { label: 'Partly cloudy', icon: 'sun-cloud', gradient: ['#e8c85e', '#9db4c8'] },
3: { label: 'Overcast', icon: 'cloud', gradient: ['#8b9ba8', '#6d7d8a'] },
45: { label: 'Fog', icon: 'cloud-fog', gradient: ['#9aa5b1', '#7a8590'] },
48: { label: 'Depositing rime fog', icon: 'cloud-fog', gradient: ['#8b9ba8', '#6d7d8a'] },
51: { label: 'Light drizzle', icon: 'cloud-drizzle', gradient: ['#6b8cae', '#4a6b8a'] },
53: { label: 'Moderate drizzle', icon: 'cloud-drizzle', gradient: ['#5a7bb8', '#3d5a80'] },
55: { label: 'Dense drizzle', icon: 'cloud-drizzle', gradient: ['#4a6fa5', '#2d4f70'] },
56: { label: 'Light freezing drizzle', icon: 'cloud-drizzle', gradient: ['#7db9de', '#5aa3cc'] },
57: { label: 'Dense freezing drizzle', icon: 'cloud-drizzle', gradient: ['#6ab0d8', '#489ac4'] },
61: { label: 'Slight rain', icon: 'cloud-rain', gradient: ['#5a8fd8', '#3d6ab8'] },
63: { label: 'Moderate rain', icon: 'cloud-rain', gradient: ['#4a7fc8', '#2d5aa0'] },
65: { label: 'Heavy rain', icon: 'cloud-rain', gradient: ['#3a6fb8', '#1d4a90'] },
66: { label: 'Light freezing rain', icon: 'cloud-rain', gradient: ['#6ab8e8', '#48a0d0'] },
67: { label: 'Heavy freezing rain', icon: 'cloud-rain', gradient: ['#5aa8e0', '#3890c8'] },
71: { label: 'Slight snow fall', icon: 'cloud-snow', gradient: ['#c8d8e8', '#a8c0d8'] },
73: { label: 'Moderate snow fall', icon: 'cloud-snow', gradient: ['#b8cce0', '#98b0d0'] },
75: { label: 'Heavy snow fall', icon: 'cloud-snow', gradient: ['#a8c0d8', '#88a8c0'] },
77: { label: 'Snow grains', icon: 'cloud-snow', gradient: ['#b8cce0', '#98b0d0'] },
80: { label: 'Slight rain showers', icon: 'cloud-rain', gradient: ['#5a8fd8', '#3d6ab8'] },
81: { label: 'Moderate rain showers', icon: 'cloud-rain', gradient: ['#4a7fc8', '#2d5aa0'] },
82: { label: 'Violent rain showers', icon: 'cloud-rain', gradient: ['#3a6fb8', '#1d4a90'] },
85: { label: 'Slight snow showers', icon: 'cloud-snow', gradient: ['#b8cce0', '#98b0d0'] },
86: { label: 'Heavy snow showers', icon: 'cloud-snow', gradient: ['#a8c0d8', '#88a8c0'] },
95: { label: 'Thunderstorm', icon: 'cloud-lightning', gradient: ['#d4a84a', '#c4983a'] },
96: { label: 'Thunderstorm with slight hail', icon: 'cloud-lightning', gradient: ['#d4984a', '#c4883a'] },
99: { label: 'Thunderstorm with heavy hail', icon: 'cloud-lightning', gradient: ['#d4884a', '#c4783a'] }
};
// SVG Icons
const ICONS = {
location: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>`,
calendar: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" ry="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>`,
sun: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>`,
'sun-cloud': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v2"/><path d="M12 20v2"/><path d="M4.93 4.93l1.41 1.41"/><path d="M17.66 17.66l1.41 1.41"/><path d="M2 12h2"/><path d="M20 12h2"/><path d="M6.34 17.66l-1.41 1.41"/><path d="M19.07 4.93l-1.41 1.41"/><path d="M16 13a4 4 0 0 0-8 0"/><path d="M16 13a6 6 0 0 1-12 0h8a2 2 0 0 1 0 4"/></svg>`,
cloud: `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>`,
'cloud-fog': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/><line x1="3" y1="14" x2="21" y2="14"/><line x1="3" y1="18" x2="21" y2="18"/><line x1="3" y1="22" x2="21" y2="22"/></svg>`,
'cloud-drizzle': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/><line x1="8" y1="19" x2="8" y2="21"/><line x1="8" y1="22" x2="8" y2="24"/><line x1="12" y1="19" x2="12" y2="21"/><line x1="12" y1="22" x2="12" y2="24"/><line x1="16" y1="19" x2="16" y2="21"/><line x1="16" y1="22" x2="16" y2="24"/></svg>`,
'cloud-rain': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/><line x1="8" y1="19" x2="8" y2="22"/><line x1="12" y1="19" x2="12" y2="22"/><line x1="16" y1="19" x2="16" y2="22"/></svg>`,
'cloud-snow': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/><line x1="8" y1="19" x2="8" y2="21"/><line x1="8" y1="22" x2="8" y2="24"/><line x1="12" y1="19" x2="12" y2="21"/><line x1="12" y1="22" x2="12" y2="24"/><line x1="16" y1="19" x2="16" y2="21"/><line x1="16" y1="22" x2="16" y2="24"/></svg>`,
'cloud-lightning': `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/><polyline points="13 11 9 17 11 17 7 23"/></svg>`
};
// Parse URL parameters
function getParams() {
const url = new URL(window.location.href);
return {
lat: parseFloat(url.searchParams.get('lat')) || 52.52,
lon: parseFloat(url.searchParams.get('lon')) || 13.405,
name: url.searchParams.get('name') || 'Berlin',
date: url.searchParams.get('date') || new Date().toISOString().split('T')[0]
};
}
// Format date for display
function formatDate(dateStr) {
const date = new Date(dateStr + 'T00:00:00Z');
return date.toLocaleDateString('en-US', {
weekday: 'long',
year: 'numeric',
month: 'long',
day: 'numeric',
timeZone: 'UTC'
});
}
// Determine API endpoint
function getApiEndpoint(dateStr) {
const today = new Date().toISOString().split('T')[0];
return dateStr <= today ? '/api/om/archive' : '/api/om/forecast';
}
// Fetch weather data
async function fetchWeather(params) {
const endpoint = getApiEndpoint(params.date);
const url = new URL(endpoint, window.location.origin);
url.searchParams.set('latitude', params.lat.toString());
url.searchParams.set('longitude', params.lon.toString());
url.searchParams.set('daily', 'temperature_2m_max,temperature_2m_min,weather_code');
url.searchParams.set('hourly', 'temperature_2m');
url.searchParams.set('timezone', 'UTC');
url.searchParams.set('temperature_unit', 'celsius');
url.searchParams.set('start_date', params.date);
url.searchParams.set('end_date', params.date);
const response = await fetch(url);
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return response.json();
}
// Render weather card
function renderCard(data, params) {
const daily = data.daily;
const hourly = data.hourly;
if (!daily || !daily.temperature_2m_max || !daily.temperature_2m_max.length) {
throw new Error('No weather data available for this date');
}
const maxTemp = daily.temperature_2m_max[0];
const minTemp = daily.temperature_2m_min[0];
const weatherCode = daily.weather_code[0];
const condition = WEATHER_CODES[weatherCode] || { label: 'Unknown', icon: 'cloud', gradient: ['#8b9ba8', '#6d7d8a'] };
// Filter hourly data for the requested date
const hourlyTemps = [];
const hourlyTimes = [];
if (hourly && hourly.time && hourly.temperature_2m) {
hourly.time.forEach((time, i) => {
if (time.startsWith(params.date)) {
hourlyTimes.push(time);
hourlyTemps.push(hourly.temperature_2m[i]);
}
});
}
const card = document.getElementById('card');
card.innerHTML = `
<header class="card-header">
<div class="location-row">
<span class="location-icon" aria-hidden="true">${ICONS.location}</span>
<h1 class="location-name">${escapeHtml(params.name)}</h1>
</div>
<div class="date-row">
<span class="date-icon" aria-hidden="true">${ICONS.calendar}</span>
<time datetime="${params.date}">${formatDate(params.date)}</time>
</div>
</header>
<main class="card-main">
<div class="current-weather">
<div class="condition-badge">
<span class="condition-icon" aria-hidden="true">${ICONS[condition.icon]}</span>
<span>${condition.label}</span>
</div>
<div class="temp-display">
<span class="temp-max">${Math.round(maxTemp)}</span>
<span class="temp-unit">°C</span>
</div>
<div class="temp-min-row">
<div class="temp-min-item">
<span class="temp-min-label">Min</span>
<span class="temp-min-value">${Math.round(minTemp)}°C</span>
</div>
</div>
</div>
<div class="weather-visual" aria-hidden="true">
${ICONS[condition.icon]}
</div>
</main>
<section class="hourly-section" aria-labelledby="hourly-title">
<div class="hourly-header">
<h2 id="hourly-title" class="hourly-title">Hourly Temperatures</h2>
</div>
<div class="hourly-chart" id="hourly-chart" role="img" aria-label="Hourly temperature chart for ${formatDate(params.date)}">
${hourlyTemps.length ? renderChart(hourlyTemps, hourlyTimes, condition.gradient) : '<p style="color:var(--text-muted);text-align:center;padding:20px;">No hourly data available</p>'}
</div>
</section>
`;
// Add gradient definition for chart
if (hourlyTemps.length) {
const svg = card.querySelector('svg');
if (svg) {
const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
defs.innerHTML = `
<linearGradient id="temp-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="${condition.gradient[0]}" stop-opacity="0.3"/>
<stop offset="100%" stop-color="${condition.gradient[1]}" stop-opacity="0.02"/>
</linearGradient>
`;
svg.insertBefore(defs, svg.firstChild);
}
initChartInteraction(hourlyTemps, hourlyTimes);
}
// Apply weather-themed accent colors
applyWeatherTheme(condition.gradient);
}
function renderChart(temps, times, gradient) {
const minTemp = Math.min(...temps);
const maxTemp = Math.max(...temps);
const range = maxTemp - minTemp || 1;
const padding = 20;
const chartWidth = 464; // 520 - 28*2 - padding*2
const chartHeight = 140;
const points = temps.map((temp, i) => {
const x = padding + (i / (temps.length - 1 || 1)) * (chartWidth - 2 * padding);
const y = padding + (1 - (temp - minTemp) / range) * (chartHeight - 2 * padding);
return { x, y, temp, time: times[i] };
});
// Generate smooth curve path
let pathData = '';
points.forEach((p, i) => {
if (i === 0) {
pathData += `M ${p.x} ${p.y}`;
} else {
const prev = points[i - 1];
const cpX = (prev.x + p.x) / 2;
pathData += ` C ${cpX} ${prev.y} ${cpX} ${p.y} ${p.x} ${p.y}`;
}
});
// Area path
let areaPath = pathData;
const lastPoint = points[points.length - 1];
const firstPoint = points[0];
areaPath += ` L ${lastPoint.x} ${chartHeight - padding} L ${firstPoint.x} ${chartHeight - padding} Z`;
// Format time labels (every 3 hours)
const labels = times.filter((_, i) => i % 3 === 0).map(t => {
const hour = parseInt(t.split('T')[1]);
return `${hour.toString().padStart(2, '0')}:00`;
});
return `
<svg class="chart-canvas" viewBox="0 0 ${chartWidth + 2 * padding} ${chartHeight}" preserveAspectRatio="none">
<defs>
<linearGradient id="temp-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="${gradient[0]}" stop-opacity="0.3"/>
<stop offset="100%" stop-color="${gradient[1]}" stop-opacity="0.02"/>
</linearGradient>
</defs>
<path class="chart-area" d="${areaPath}"/>
<path class="chart-line" d="${pathData}"/>
${points.map((p, i) => `
<circle class="chart-point" cx="${p.x}" cy="${p.y}" r="4" data-index="${i}" data-temp="${p.temp}" data-time="${p.time}"/>
`).join('')}
</svg>
<div class="chart-labels">
${labels.map(l => `<span>${l}</span>`).join('')}
</div>
<div class="hourly-tooltip" id="hourly-tooltip" role="tooltip"></div>
`;
}
function initChartInteraction(temps, times) {
const chart = document.getElementById('hourly-chart');
const tooltip = document.getElementById('hourly-tooltip');
const points = chart.querySelectorAll('.chart-point');
let activeIndex = -1;
function showTooltip(index, clientX, clientY) {
const point = points[index];
const temp = point.dataset.temp;
const time = point.dataset.time;
const hour = time.split('T')[1].substring(0, 5);
tooltip.innerHTML = `
<div class="tooltip-time">${hour}</div>
<div class="tooltip-temp">${Math.round(parseFloat(temp))}°C</div>
`;
const rect = chart.getBoundingClientRect();
tooltip.style.left = `${clientX - rect.left}px`;
tooltip.style.top = `${clientY - rect.top - 10}px`;
tooltip.classList.add('visible');
points.forEach((p, i) => p.classList.toggle('active', i === index));
}
function hideTooltip() {
tooltip.classList.remove('visible');
points.forEach(p => p.classList.remove('active'));
}
chart.addEventListener('mousemove', (e) => {
const rect = chart.getBoundingClientRect();
const x = e.clientX - rect.left;
// Find closest point
let closest = 0;
let minDist = Infinity;
points.forEach((p, i) => {
const cx = parseFloat(p.getAttribute('cx'));
const dist = Math.abs(cx - x);
if (dist < minDist) {
minDist = dist;
closest = i;
}
});
if (minDist < 30) {
showTooltip(closest, e.clientX, e.clientY);
} else {
hideTooltip();
}
});
chart.addEventListener('mouseleave', hideTooltip);
// Touch support
chart.addEventListener('touchstart', (e) => {
e.preventDefault();
const touch = e.touches[0];
const rect = chart.getBoundingClientRect();
const x = touch.clientX - rect.left;
let closest = 0;
let minDist = Infinity;
points.forEach((p, i) => {
const cx = parseFloat(p.getAttribute('cx'));
const dist = Math.abs(cx - x);
if (dist < minDist) {
minDist = dist;
closest = i;
}
});
if (minDist < 40) {
showTooltip(closest, touch.clientX, touch.clientY);
}
}, { passive: false });
document.addEventListener('touchstart', (e) => {
if (!chart.contains(e.target)) hideTooltip();
});
}
function applyWeatherTheme(gradient) {
const root = document.documentElement;
root.style.setProperty('--accent', gradient[0]);
root.style.setProperty('--accent-warm', gradient[1]);
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
function showError(message) {
const card = document.getElementById('card');
card.innerHTML = `
<div class="error-state">
<div class="error-icon" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="10"/>
<line x1="12" y1="8" x2="12" y2="12"/>
<line x1="12" y1="16" x2="12.01" y2="16"/>
</svg>
</div>
<h2 class="error-title">Unable to Load Weather</h2>
<p class="error-message">${escapeHtml(message)}</p>
</div>
`;
}
// Initialize
async function init() {
const params = getParams();
try {
const data = await fetchWeather(params);
renderCard(data, params);
} catch (error) {
console.error('Weather fetch error:', error);
showError(error.message || 'Failed to fetch weather data. Please try again later.');
}
}
init();
</script>
</body>
</html>L1 — cheap deterministic descriptors
| bytes total | 28,044 | html / css / js | 449 / 9,362 / 18,233 |
|---|---|---|---|
| dom nodes | 12 | dom depth | 5 |
| css rules | 64 | js present | yes |
| brightness | 245.4 | contrast | 12.3 |
| colorfulness | 6.2 | whitespace | 99.1% |
This slot's telemetry
| prompt tokens | 334 | completion tokens | 9,830 |
|---|---|---|---|
| total tokens | 10,164 | wall | 162.8 s |
| cost | — | request id | — |
config.json574 B
{
"N": 2,
"auth": {
"credential_ref": "WCB_ZEN_KEY",
"method": "api-key"
},
"billing": "plan",
"config_id": "nemotron-3-ultra-free--zen-free--dev",
"effort": null,
"family": "nemotron",
"m": {
"min": 2,
"q": 2
},
"model_id": "nemotron-3-ultra-free",
"protocol": "api",
"served_model": "nemotron-3-ultra-free",
"telemetry": {
"completion_tokens": 34941,
"cost_usd": null,
"prompt_tokens": 1320,
"total_tokens": 36261,
"wall_ms": 403886
},
"transport": "opencode-zen-free-tier",
"vendor_sanction_ref": null
}send-log2.5 KB
{
"N": 2,
"batch_id": "2026-07-18--dev-zen-free",
"config_id": "nemotron-3-ultra-free--zen-free--dev",
"positions": [
{
"attempts": [
{
"attempt_index": 0,
"backoff_ms": null,
"charged": true,
"ended_at": "2026-07-18T01:08:11.062116+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T01:05:28.210565+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-18T01:10:17.116918+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T01:08:14.224245+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-18T01:10:53.210402+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T01:10:20.653332+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-18T01:12:22.454672+00:00",
"http_status": 200,
"outcome": "valid",
"reached_model": true,
"reason": "ok",
"request_id": null,
"started_at": "2026-07-18T01:10:56.862351+00:00"
}
],
"block_index": 1,
"model_reaching_attempt_index": 0,
"slot_index": 1,
"terminal_state": "valid",
"variant": "P-q"
}
],
"retry_policy": {
"max_unreachable_retries": 5,
"rate_limit_backoff": {
"max_attempts": 4,
"max_total_ms": 60000
}
}
}