← back to Model Arena
data/artifacts/1a357c868e55/qwen3-14b.html
328 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>The Empire of Virellis</title>
<style>
:root {
--bg: #0f0f1a;
--accent: #ff4b4b;
--text: #fff;
--border: rgba(255, 255, 255, 0.1);
--label: #ccc;
--highlight: #a333ff;
--event-bg: rgba(255, 255, 255, 0.05);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
body {
background: var(--bg);
color: var(--text);
display: flex;
flex-direction: column;
height: 100vh;
overflow: hidden;
}
header {
background: var(--accent);
padding: 1rem;
text-align: center;
font-size: 1.5rem;
font-weight: bold;
}
main {
flex: 1;
display: flex;
position: relative;
overflow: hidden;
}
.map {
flex: 1;
position: relative;
background: #1a1a2e;
min-height: 100%;
}
.slider-container {
position: absolute;
bottom: 0;
left: 0;
right: 0;
display: flex;
align-items: center;
padding: 0.5rem;
pointer-events: none;
}
.slider {
flex: 1;
height: 4px;
background: var(--border);
border-radius: 2px;
cursor: pointer;
position: relative;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 4px #ff4b4b;
}
.slider::-moz-range-thumb {
width: 16px;
height: 16px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
box-shadow: 0 0 4px #ff4b4b;
}
.slider:focus {
outline: none;
}
.events {
position: absolute;
top: 10px;
left: 10px;
background: var(--event-bg);
padding: 0.5rem;
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
max-height: 150px;
overflow-y: auto;
z-index: 10;
}
.event {
margin-bottom: 0.3rem;
color: #fff;
font-size: 0.9rem;
}
.legend {
position: absolute;
bottom: 10px;
right: 10px;
background: var(--event-bg);
padding: 0.5rem;
border: 1px solid rgba(255,255,255,0.1);
border-radius: 8px;
max-width: 220px;
overflow-y: auto;
}
.legend-item {
display: flex;
align-items: center;
margin-bottom: 0.3rem;
font-size: 0.85rem;
}
.legend-item span {
margin-right: 0.5rem;
}
.city {
position: absolute;
width: 8px;
height: 8px;
border-radius: 50%;
background: #ff4b4b;
transition: transform 0.2s, opacity 0.2s;
}
.city.active {
transform: scale(1.5);
opacity: 1;
}
.border {
position: absolute;
pointer-events: none;
fill: none;
stroke: var(--border);
stroke-width: 1;
transition: stroke 0.3s, stroke-opacity 0.3s;
}
.border.active {
stroke: var(--accent);
stroke-opacity: 1;
}
.event-note {
position: absolute;
padding: 0.3rem 0.5rem;
background: #1a1a2e;
color: #fff;
border-radius: 4px;
font-size: 0.8rem;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
}
.event-note.visible {
opacity: 1;
}
@media (prefers-reduced-motion: no-preference) {
.city.active {
animation: pulse 1s ease-in-out;
}
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.2);
opacity: 0.8;
}
}
</style>
</head>
<body>
<header>The Empire of Virellis: 1251–1350</header>
<main>
<div class="map" id="map">
<div class="slider-container">
<input
type="range"
min="1251"
max="1350"
value="1251"
id="slider"
aria-label="Century Slider"
/>
</div>
<svg id="svg-map" width="100%" height="100%" viewBox="0 0 100 100">
<g id="borders">
<!-- Example polygons - these would be dynamically generated -->
<path d="M10 10 L20 20 L30 10 L10 10" class="border" data-year="1255"/>
<path d="M40 40 L50 50 L60 40 L40 40" class="border" data-year="1300"/>
</g>
<g id="cities">
<!-- Example cities - dynamically generated -->
<circle cx="20" cy="20" r="4" class="city" data-year="1260"/>
<circle cx="50" cy="50" r="4" class="city" data-year="1290"/>
</g>
</svg>
<div class="events" id="events">
<div class="event" id="event-1255">The Pact of Eldros expands Virellis to the north.</div>
<div class="event" id="event-1280">The Great Collapse: Cities of the Western March fall.</div>
<div class="event" id="event-1300">Queen Seraphina the Wise unites the southern provinces.</div>
</div>
<div class="legend" id="legend">
<div class="legend-item"><span style="background:#ff4b4b;"></span> Cities</div>
<div class="legend-item"><span style="background:#a333ff;"></span> Major Events</div>
<div class="legend-item"><span style="background:#0f0f1a;"></span> Current Map Borders</div>
</div>
</div>
</main>
<script>
const slider = document.getElementById("slider");
const map = document.getElementById("map");
const svgMap = document.getElementById("svg-map");
const eventsContainer = document.getElementById("events");
const legend = document.getElementById("legend");
const years = [1251, 1255, 1260, 1270, 1280, 1290, 1300, 1310, 1320, 1330, 1340, 1350];
slider.addEventListener("input", updateMap);
slider.addEventListener("change", updateMap);
// Initialize
updateMap();
function updateMap() {
const year = parseInt(slider.value);
const yearIdx = years.findIndex(y => y === year);
if (yearIdx === -1) return;
// Highlight cities
const cities = document.querySelectorAll(".city");
cities.forEach(city => {
const cityYear = parseInt(city.getAttribute("data-year"));
if (cityYear <= year) {
city.classList.add("active");
} else {
city.classList.remove("active");
}
});
// Border activation
const borders = document.querySelectorAll(".border");
borders.forEach(border => {
const borderYear = parseInt(border.getAttribute("data-year"));
if (borderYear <= year) {
border.classList.add("active");
} else {
border.classList.remove("active");
}
});
// Event notes
const eventNotes = document.querySelectorAll(".event-note");
eventNotes.forEach(note => {
note.classList.remove("visible");
});
// Show event notes based on year
if (year === 1255) {
const note1255 = document.getElementById("event-1255");
if (note1255) {
note1255.classList.add("visible");
}
}
if (year === 1280) {
const note1280 = document.getElementById("event-1280");
if (note1280) {
note1280.classList.add("visible");
}
}
if (year === 1300) {
const note1300 = document.getElementById("event-1300");
if (note1300) {
note1300.classList.add("visible");
}
}
}
// Keyboard accessibility
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowLeft" && slider.value > 1251) {
slider.value = parseInt(slider.value) - 10;
updateMap();
e.preventDefault();
} else if (e.key === "ArrowRight" && slider.value < 1350) {
slider.value = parseInt(slider.value) + 10;
updateMap();
e.preventDefault();
}
});
</script>
</body>
</html>