GameJam-Seite integriert
- public/gamejam.html: teilnehmerseitige AI-GameJam-Seite (TechDay Bruchsal, 27.05.) mit eigenem Schwarz-Weiß-Styling, Zurück-Link zur Landingpage - server.js: abhängigkeitsfreier Multipart-Parser plus Endpunkte POST /api/gamejam/upload und GET /api/gamejam/games - index.html: Navigations-Verweis "GameJam" in Header und Mobilmenü - .gitignore: hochgeladene Spiele und Einreichungen ausgeschlossen Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
143748dc0d
commit
b629bbc90a
4 files changed
+918
-5
No files matched your search
@@ -1,6 +1,10 @@
|
||||
# Lead-Daten — enthalten personenbezogene Daten, gehören nicht ins Repo
|
||||
leads/
|
||||
|
||||
# GameJam — Einreichungen & hochgeladene Spiele (User-Content)
|
||||
gamejam/
|
||||
public/gamejam-games/
|
||||
|
||||
# OS / Editor
|
||||
.DS_Store
|
||||
|
||||
|
||||
@@ -0,0 +1,727 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>AI GameJam — Human in the Loop · TechDay Bruchsal 2026</title>
|
||||
<link rel="icon" type="image/png" href="/assets/favicon.png">
|
||||
<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=Space+Grotesk:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff;
|
||||
--bg2: #f5f5f6;
|
||||
--panel: #f3f3f4;
|
||||
--panel2: #ededee;
|
||||
--line: #e4e4e6;
|
||||
--line2: #d2d2d6;
|
||||
--text: #0c0c0e;
|
||||
--muted: #6b6b73;
|
||||
--ac: #0c0c0e;
|
||||
}
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
html { scroll-behavior: smooth; }
|
||||
body {
|
||||
font-family: 'Space Grotesk', -apple-system, sans-serif;
|
||||
background: var(--bg); color: var(--text);
|
||||
line-height: 1.6; -webkit-font-smoothing: antialiased; overflow-x: hidden;
|
||||
}
|
||||
.mono { font-family: 'Space Mono', monospace; }
|
||||
.wrap { max-width: 1120px; margin: 0 auto; padding: 0 32px; }
|
||||
svg.ic { width: 1em; height: 1em; stroke: currentColor; stroke-width: 1.8;
|
||||
fill: none; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
|
||||
|
||||
section { padding: 100px 0; position: relative; }
|
||||
section::before {
|
||||
content: ""; position: absolute; top: 0; left: 32px; right: 32px;
|
||||
height: 1px; background: var(--line);
|
||||
}
|
||||
.seclabel {
|
||||
font-family: 'Space Mono', monospace; font-size: 12px; letter-spacing: 3px;
|
||||
text-transform: uppercase; color: var(--ac); margin-bottom: 34px;
|
||||
display: flex; align-items: center; gap: 12px;
|
||||
}
|
||||
.seclabel::before {
|
||||
content: ""; width: 8px; height: 8px; background: var(--ac);
|
||||
transform: rotate(45deg); flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* ===== TOPBAR ===== */
|
||||
.topbar {
|
||||
position: sticky; top: 0; z-index: 50;
|
||||
background: rgba(255,255,255,0.85); backdrop-filter: blur(12px);
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
.topbar .inner {
|
||||
max-width: 1120px; margin: 0 auto; padding: 13px 32px;
|
||||
display: flex; align-items: center; justify-content: space-between;
|
||||
}
|
||||
.topbar img { display: block; }
|
||||
.topbar .tc { height: 28px; }
|
||||
.topbar .left { display: flex; align-items: center; gap: 18px; }
|
||||
.topbar .back {
|
||||
display: inline-flex; align-items: center; gap: 7px;
|
||||
font-family: 'Space Mono', monospace; font-size: 11px;
|
||||
letter-spacing: 1px; text-transform: uppercase;
|
||||
color: var(--muted); text-decoration: none;
|
||||
border-left: 1px solid var(--line); padding-left: 18px;
|
||||
transition: color .15s;
|
||||
}
|
||||
.topbar .back:hover { color: var(--ac); }
|
||||
.topbar .back svg.ic { width: 13px; height: 13px; }
|
||||
.topbar .right { display: flex; align-items: center; gap: 20px; }
|
||||
.topbar .mit { height: 26px; }
|
||||
.topbar .ev {
|
||||
font-family: 'Space Mono', monospace; font-size: 11px;
|
||||
color: var(--muted); letter-spacing: 1px; text-transform: uppercase;
|
||||
}
|
||||
|
||||
/* ===== HERO ===== */
|
||||
.hero {
|
||||
min-height: calc(100vh - 53px); display: flex; flex-direction: column;
|
||||
justify-content: center; align-items: center; text-align: center;
|
||||
padding: 80px 32px; position: relative; overflow: hidden;
|
||||
}
|
||||
.hero .bg {
|
||||
position: absolute; inset: 0; z-index: 0;
|
||||
background-image:
|
||||
linear-gradient(rgba(0,0,0,0.045) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(0,0,0,0.045) 1px, transparent 1px);
|
||||
background-size: 54px 54px;
|
||||
mask-image: radial-gradient(ellipse 70% 65% at 50% 42%, #000 30%, transparent 80%);
|
||||
-webkit-mask-image: radial-gradient(ellipse 70% 65% at 50% 42%, #000 30%, transparent 80%);
|
||||
}
|
||||
.hero > * { position: relative; z-index: 1; }
|
||||
.hero .kicker {
|
||||
font-family: 'Space Mono', monospace; font-size: 13px; letter-spacing: 4px;
|
||||
text-transform: uppercase; color: var(--ac); margin-bottom: 26px;
|
||||
}
|
||||
.hero h1 {
|
||||
font-size: clamp(52px, 11vw, 142px); font-weight: 700; line-height: 0.93;
|
||||
letter-spacing: -0.04em; text-transform: uppercase; margin-bottom: 24px;
|
||||
}
|
||||
.hero h1 .ln2 { color: var(--ac); }
|
||||
.hero .hsub {
|
||||
font-size: clamp(15px, 2vw, 19px); color: var(--muted);
|
||||
max-width: 540px; margin-bottom: 56px;
|
||||
}
|
||||
.hero .hsub b { color: var(--text); font-weight: 600; }
|
||||
|
||||
/* HUD panel */
|
||||
.hud {
|
||||
position: relative; background: var(--panel);
|
||||
border: 1px solid var(--line2); padding: 36px 56px;
|
||||
min-width: min(560px, 92vw);
|
||||
}
|
||||
.hud .cn {
|
||||
position: absolute; width: 14px; height: 14px;
|
||||
border: 1.5px solid var(--ac);
|
||||
}
|
||||
.hud .cn.tl { top: -1px; left: -1px; border-right: 0; border-bottom: 0; }
|
||||
.hud .cn.br { bottom: -1px; right: -1px; border-left: 0; border-top: 0; }
|
||||
.hud .live {
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
font-family: 'Space Mono', monospace; font-size: 11px; letter-spacing: 2.5px;
|
||||
text-transform: uppercase; color: var(--ac); margin-bottom: 16px;
|
||||
}
|
||||
.hud .live .dot {
|
||||
width: 7px; height: 7px; background: var(--ac); border-radius: 50%;
|
||||
animation: pulse 1.8s ease-in-out infinite;
|
||||
}
|
||||
@keyframes pulse { 0%,100%{opacity:1;box-shadow:0 0 0 0 rgba(0,0,0,.32);}
|
||||
50%{opacity:.5;box-shadow:0 0 0 6px rgba(0,0,0,0);} }
|
||||
.hud .pn {
|
||||
font-size: clamp(26px, 4vw, 40px); font-weight: 700; line-height: 1.12;
|
||||
letter-spacing: -0.02em; text-transform: uppercase; margin-bottom: 4px;
|
||||
}
|
||||
.hud .ps { color: var(--muted); font-size: 14px; margin-bottom: 26px; }
|
||||
.hud .timer {
|
||||
font-family: 'Space Mono', monospace; font-weight: 700;
|
||||
font-size: clamp(54px, 11vw, 108px); line-height: 1;
|
||||
letter-spacing: -0.02em; color: var(--text);
|
||||
}
|
||||
.hud .tl {
|
||||
font-family: 'Space Mono', monospace; font-size: 11px; letter-spacing: 2px;
|
||||
text-transform: uppercase; color: var(--muted); margin-top: 10px;
|
||||
}
|
||||
.hmeta {
|
||||
margin-top: 44px; display: flex; gap: 14px; flex-wrap: wrap; justify-content: center;
|
||||
}
|
||||
.hmeta span {
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
font-family: 'Space Mono', monospace; font-size: 12px; color: var(--muted);
|
||||
border: 1px solid var(--line); padding: 8px 14px; text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.hmeta svg.ic { width: 14px; height: 14px; color: var(--ac); }
|
||||
|
||||
h2.big {
|
||||
font-size: clamp(30px, 5vw, 52px); font-weight: 700; line-height: 1.05;
|
||||
letter-spacing: -0.03em; text-transform: uppercase; margin-bottom: 18px;
|
||||
}
|
||||
.lead { font-size: 18px; color: var(--muted); max-width: 680px; }
|
||||
.lead b { color: var(--text); font-weight: 600; }
|
||||
|
||||
/* ===== TIMELINE ===== */
|
||||
.tl-row {
|
||||
display: grid; grid-template-columns: 96px 1fr 26px; gap: 22px;
|
||||
align-items: center; padding: 17px 20px;
|
||||
border-left: 2px solid var(--line); margin-bottom: 2px;
|
||||
transition: background .15s;
|
||||
}
|
||||
.tl-row .tt {
|
||||
font-family: 'Space Mono', monospace; font-weight: 700; font-size: 15px;
|
||||
color: var(--muted);
|
||||
}
|
||||
.tl-row .tn { font-weight: 600; font-size: 16px; text-transform: uppercase; letter-spacing: -0.01em; }
|
||||
.tl-row .ts { color: var(--muted); font-size: 13px; }
|
||||
.tl-row .tx { color: var(--ac); }
|
||||
.tl-row.done { opacity: 0.38; }
|
||||
.tl-row.active {
|
||||
background: var(--panel); border-left-color: var(--ac);
|
||||
}
|
||||
.tl-row.active .tt { color: var(--ac); }
|
||||
.tl-row.active .tn { color: var(--text); }
|
||||
|
||||
/* ===== STEPS ===== */
|
||||
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; }
|
||||
.step {
|
||||
position: relative; padding: 30px 34px 8px 0; overflow: hidden;
|
||||
}
|
||||
.step + .step { padding-left: 34px; border-left: 1px solid var(--line); }
|
||||
.step .gn {
|
||||
position: absolute; top: 6px; right: 14px; font-family: 'Space Mono', monospace;
|
||||
font-size: 110px; font-weight: 700; line-height: 1;
|
||||
color: transparent; -webkit-text-stroke: 1px var(--line2);
|
||||
pointer-events: none; z-index: 0;
|
||||
}
|
||||
.step > *:not(.gn) { position: relative; z-index: 1; }
|
||||
.step .sic { color: var(--ac); margin-bottom: 20px; }
|
||||
.step .sic svg.ic { width: 28px; height: 28px; }
|
||||
.step .sk {
|
||||
font-family: 'Space Mono', monospace; font-size: 11px; letter-spacing: 2px;
|
||||
text-transform: uppercase; color: var(--muted);
|
||||
}
|
||||
.step h3 {
|
||||
font-size: 26px; font-weight: 700; letter-spacing: -0.02em;
|
||||
text-transform: uppercase; margin: 6px 0 12px;
|
||||
}
|
||||
.step p { color: var(--muted); font-size: 15px; }
|
||||
|
||||
/* ===== CATEGORIES ===== */
|
||||
.cats { display: grid; grid-template-columns: repeat(4, 1fr); }
|
||||
.catcol { padding: 0 26px; border-left: 1px solid var(--line); }
|
||||
.catcol:first-child { padding-left: 0; border-left: none; }
|
||||
.catcol .cnum { font-family: 'Space Mono', monospace; font-size: 12px; color: var(--ac); }
|
||||
.catcol .cn {
|
||||
font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
|
||||
text-transform: uppercase; margin: 8px 0 4px;
|
||||
}
|
||||
.catcol .cs { color: var(--muted); font-size: 14px; }
|
||||
.catcol .cv {
|
||||
font-family: 'Space Mono', monospace; font-size: 12px; color: var(--ac);
|
||||
margin-top: 16px; letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* ===== PRIZES ===== */
|
||||
.prizes { display: grid; grid-template-columns: 1.4fr 1fr 1fr; }
|
||||
.prizeitem {
|
||||
padding: 36px 32px 36px 0; border-top: 2px solid var(--line);
|
||||
}
|
||||
.prizeitem + .prizeitem { padding-left: 32px; border-left: 1px solid var(--line); }
|
||||
.prizeitem.first { border-top-color: var(--ac); }
|
||||
.prizeitem .pr {
|
||||
font-family: 'Space Mono', monospace; font-size: 12px; letter-spacing: 2px;
|
||||
text-transform: uppercase; color: var(--muted);
|
||||
}
|
||||
.prizeitem.first .pr { color: var(--ac); }
|
||||
.prizeitem h3 {
|
||||
font-size: clamp(26px, 3vw, 40px); font-weight: 700; letter-spacing: -0.03em;
|
||||
text-transform: uppercase; margin: 14px 0 6px; line-height: 1;
|
||||
}
|
||||
.prizeitem.first h3 { color: var(--ac); }
|
||||
.prizeitem .dur {
|
||||
font-family: 'Space Mono', monospace; font-size: 13px; color: var(--muted);
|
||||
text-transform: uppercase; letter-spacing: 1px;
|
||||
}
|
||||
|
||||
/* ===== UPLOAD ===== */
|
||||
.uploadblock { max-width: 560px; }
|
||||
.uploadblock h3 {
|
||||
font-size: 22px; font-weight: 700; letter-spacing: -0.02em;
|
||||
text-transform: uppercase; margin-bottom: 20px;
|
||||
}
|
||||
.field { margin: 14px 0; }
|
||||
.field label {
|
||||
display: block; font-family: 'Space Mono', monospace; font-size: 11px;
|
||||
color: var(--muted); margin-bottom: 7px; text-transform: uppercase; letter-spacing: 1.5px;
|
||||
}
|
||||
.field input {
|
||||
width: 100%; background: var(--bg2); border: 1px solid var(--line2);
|
||||
padding: 13px 15px; color: var(--text); font-size: 15px; font-family: inherit;
|
||||
}
|
||||
.field input:focus { outline: none; border-color: var(--ac); }
|
||||
.dropzone {
|
||||
border: 1.5px dashed var(--line2); padding: 40px 24px; text-align: center;
|
||||
cursor: pointer; transition: all .15s; background: var(--bg2);
|
||||
}
|
||||
.dropzone:hover, .dropzone.drag { border-color: var(--ac); background: var(--panel); }
|
||||
.dropzone .dzi { color: var(--ac); margin-bottom: 12px; }
|
||||
.dropzone .dzi svg.ic { width: 28px; height: 28px; }
|
||||
.dropzone .big { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
|
||||
.dropzone .sm { color: var(--muted); font-size: 13px; font-family: 'Space Mono', monospace; }
|
||||
.btn {
|
||||
background: var(--ac); color: #ffffff; border: none;
|
||||
padding: 13px 30px; font-size: 14px; font-weight: 700; cursor: pointer;
|
||||
font-family: inherit; text-transform: uppercase; letter-spacing: 1px;
|
||||
transition: opacity .15s;
|
||||
}
|
||||
.btn:hover { opacity: 0.82; }
|
||||
.btn:disabled { background: var(--line2); color: var(--muted); cursor: not-allowed; }
|
||||
.status {
|
||||
font-family: 'Space Mono', monospace; font-size: 13px; margin-top: 16px; min-height: 20px;
|
||||
}
|
||||
.status.ok { color: var(--ac); }
|
||||
.status.err { color: #c0392b; }
|
||||
|
||||
/* ===== GALLERY ===== */
|
||||
.btn-ghost {
|
||||
background: var(--panel); border: 1px solid var(--line2); color: var(--text);
|
||||
padding: 10px 16px; font-size: 12px; font-weight: 600; cursor: pointer;
|
||||
font-family: 'Space Mono', monospace; text-transform: uppercase; letter-spacing: 1px;
|
||||
display: inline-flex; align-items: center; gap: 8px;
|
||||
}
|
||||
.btn-ghost:hover { border-color: var(--ac); }
|
||||
.btn-ghost svg.ic { width: 13px; height: 13px; }
|
||||
|
||||
.games { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 6px; }
|
||||
.game { background: var(--panel); border: 1px solid var(--line); }
|
||||
.game .frame { width: 100%; aspect-ratio: 16/10; border: none; background: var(--panel2); display: block; }
|
||||
.game .gm {
|
||||
padding: 15px 17px; display: flex; justify-content: space-between;
|
||||
align-items: center; gap: 12px; border-top: 1px solid var(--line);
|
||||
}
|
||||
.game .gt { font-weight: 700; font-size: 15px; text-transform: uppercase; letter-spacing: -0.01em; }
|
||||
.game .gte { font-family: 'Space Mono', monospace; font-size: 12px; color: var(--muted); }
|
||||
.game .gm a {
|
||||
color: var(--ac); font-family: 'Space Mono', monospace; font-size: 12px;
|
||||
text-transform: uppercase; letter-spacing: 1px; text-decoration: none;
|
||||
white-space: nowrap; display: inline-flex; align-items: center; gap: 5px;
|
||||
}
|
||||
.game .gm a svg.ic { width: 12px; height: 12px; }
|
||||
.notice {
|
||||
background: var(--bg2); border: 1px solid var(--line); border-left: 2px solid var(--ac);
|
||||
padding: 15px 18px; color: var(--muted); font-size: 14px;
|
||||
font-family: 'Space Mono', monospace;
|
||||
}
|
||||
|
||||
/* ===== FOOTER ===== */
|
||||
footer { border-top: 1px solid var(--line); padding: 54px 0; }
|
||||
footer .inner { display: flex; flex-direction: column; align-items: center; gap: 24px; text-align: center; }
|
||||
footer .logos { display: flex; align-items: center; gap: 28px; }
|
||||
footer .logos img { height: 30px; opacity: 0.6; }
|
||||
footer .logos .tc { height: 32px; }
|
||||
footer .ft {
|
||||
font-family: 'Space Mono', monospace; color: var(--muted); font-size: 12px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
@media (max-width: 820px) {
|
||||
.steps { grid-template-columns: 1fr; }
|
||||
.step + .step { padding-left: 0; border-left: none; border-top: 1px solid var(--line); }
|
||||
.step { padding-right: 0; }
|
||||
.cats { grid-template-columns: 1fr 1fr; gap: 24px 0; }
|
||||
.prizes { grid-template-columns: 1fr; }
|
||||
.prizeitem, .prizeitem + .prizeitem { padding: 28px 0; border-left: none; }
|
||||
.games { grid-template-columns: 1fr; }
|
||||
.hud { padding: 30px 28px; }
|
||||
section { padding: 70px 0; }
|
||||
.topbar .ev { display: none; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ===================== TOPBAR ===================== -->
|
||||
<div class="topbar">
|
||||
<div class="inner">
|
||||
<div class="left">
|
||||
<a href="/" aria-label="Zur ToolCTRL-Startseite"><img class="tc" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzEzLjMyIDY3OC42MSI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNSk7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNik7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNCk7CiAgICAgIH0KCiAgICAgIC5jbHMtNCB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMyk7CiAgICAgIH0KCiAgICAgIC5jbHMtNSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMik7CiAgICAgIH0KCiAgICAgIC5jbHMtNiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQpOwogICAgICB9CiAgICA8L3N0eWxlPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHgxPSI2NTguOTYiIHkxPSIzMS45NiIgeDI9IjI5Ny43IiB5Mj0iNDU4LjYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMDAwIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzMzMyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTIiIHgxPSIxNjg0LjMiIHkxPSIxMTQyLjc1IiB4Mj0iMjIwNi4wOSIgeTI9IjE1NTMuNTEiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4MzMuNzQgLTExMDguOTYpIHJvdGF0ZSg1LjA2KSBza2V3WCgxNC4yNSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjYjJiMmIyIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iLjc4IiBzdG9wLWNvbG9yPSIjZmZmIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMyIgeDE9IjE3MTkuMTMiIHkxPSIxMDk4LjUxIiB4Mj0iMjI0MC45MSIgeTI9IjE1MDkuMjgiIHhsaW5rOmhyZWY9IiNsaW5lYXItZ3JhZGllbnQtMiIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNCIgeDE9IjE3NjQuODIiIHkxPSIxMDQwLjQ3IiB4Mj0iMjI4Ni42IiB5Mj0iMTQ1MS4yNCIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC01IiB4MT0iMTgwNi4yNyIgeTE9Ijk4Ny44MiIgeDI9IjIzMjguMDUiIHkyPSIxMzk4LjU5IiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50LTIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTYiIHgxPSIzNDUuMDMiIHkxPSItMTAuMTUiIHgyPSIxMDE0LjU1IiB5Mj0iNTE2LjkxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwwKSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgPC9kZWZzPgogIDxnPgogICAgPHBhdGggZD0iTTY4OC43LDU3Mi4wOWwtMTYwLDk4Ljk1Yy05LjE0LDUuNzMtMTkuOTksOC4zNS0zMC43Nyw3LjM3bC0zODAuNjgtMzQuMzZjLTIyLjQ4LTIuMDEtNDAuNzYtMTkuMDEtNDQuMzUtNDEuMzFMLjY0LDE1OS4zMWMtMy4xNy0xOS41Niw1LjYtMzkuMTIsMjIuMy00OS43MkwxODkuNDYsOC4wOGMtMTMuOTUsOS43NSwyMy43NywzMS41NSwyNi44OCw0OS45NWw5MS4zLDM2MS4xM2M2LjIxLDM2LjY4LDM2LjM3LDY0LjU4LDczLjQyLDY3LjkzbDI3OC42NCw0Mi45YzguNjUuNzksMjEuODcsNDUuNjgsMjguOTQsNDIuMDNsLjA2LjA2WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy02IiBkPSJNNjg4LjY0LDU3Mi4wM2MtNy4wNywzLjY2LTE1LjIzLDUuMzYtMjMuODgsNC41N2wtMzQ5LTMxLjVjLTM3LjA0LTMuMzUtNjcuMjEtMzEuMjYtNzMuNDItNjcuOTNMMTcwLjM5LDUzLjM1Yy0zLjExLTE4LjQsNS4xMi0zNS41MiwxOS4wNy00NS4yN2wxLjk1LTEuMTZjNy45OC01LjA2LDE3LjYxLTcuNjIsMjcuOTEtNi43NmwzNTguNTYsMzAuMzRjMjkuNDksMi41LDUzLjU2LDI0LjYyLDU4LjYxLDUzLjhsNzYuMTYsNDQwLjM5YzMuNTMsMjAuMjktNy4xOSwzOC45OS0yNC4wMSw0Ny4zNFoiLz4KICA8L2c+CiAgPGc+CiAgICA8Zz4KICAgICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMzAwLjIyLDM0My45M2wtMTUuMDEsNC4yNiwxNS43Myw5Ni4wNWM0LjIzLDI1LjgzLDIxLjg4LDQyLjU5LDQ3LjIxLDQ0LjgzbDIwLjQyLDEuODEtMi40OC0xNS4xNC0yMC40Mi0xLjgxYy0xNS44MS0xLjQtMjYuMDQtMTEuNDQtMjguNzktMjguMjhsLTguMjQtNTAuMzQsNDQuOTMsMy45Ny0yLjQ1LTE0Ljk0LTQ0LjkzLTMuOTctNS45Ny0zNi40M1oiLz4KICAgICAgPHBhdGggY2xhc3M9ImNscy00IiBkPSJNNDIxLjk2LDM4Ny45N2MtMzEuODgtMi44Mi01MS4yNiwxOC4xLTQ2LjA4LDQ5LjczLDUuMTgsMzEuNjQsMzIuMDgsNTYuNjUsNjMuOTcsNTkuNDcsMzEuODgsMi44Miw1MS4yNi0xOC4xLDQ2LjA4LTQ5LjczLTUuMTgtMzEuNjQtMzIuMDgtNTYuNjUtNjMuOTctNTkuNDdaTTQzNy4zNiw0ODIuMDNjLTIyLjktMi4wMy00MS41NC0xOS42Ny00NS4zNS00Mi45LTMuOC0yMy4yMyw5LjUzLTM4LjA0LDMyLjQzLTM2LjAyLDIyLjksMi4wMyw0MS41NCwxOS42Niw0NS4zNSw0Mi45LDMuOCwyMy4yMy05LjUzLDM4LjA0LTMyLjQyLDM2LjAyWiIvPgogICAgICA8cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01NDEuMzcsMzk4LjUzYy0zMS44OC0yLjgyLTUxLjI2LDE4LjEtNDYuMDgsNDkuNzMsNS4xOCwzMS42NCwzMi4wOCw1Ni42NSw2My45Nyw1OS40NywzMS44OCwyLjgyLDUxLjI2LTE4LjEsNDYuMDgtNDkuNzMtNS4xOC0zMS42NC0zMi4wOC01Ni42NS02My45Ny01OS40N1pNNTU2Ljc3LDQ5Mi41OWMtMjIuOS0yLjAzLTQxLjU0LTE5LjY3LTQ1LjM1LTQyLjktMy44LTIzLjIzLDkuNTMtMzguMDQsMzIuNDMtMzYuMDIsMjIuOSwyLjAzLDQxLjU0LDE5LjY2LDQ1LjM1LDQyLjksMy44LDIzLjIzLTkuNTMsMzguMDQtMzIuNDIsMzYuMDJaIi8+CiAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI2MDcuNjcgMzY4LjQxIDYzMS4xIDUxMS40NiA2NDcuMDQgNTEyLjg3IDYyMi42OCAzNjQuMTUgNjA3LjY3IDM2OC40MSIvPgogICAgPC9nPgogICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNTgyLjM5LDE2NC4wN2wxOC4zLDEuNjItNTYuMjktNzUuMTJjLTMuMTUtNC4yLTcuOTMtNi44Ni0xMy4xNi03LjMzaDBjLTcuNjEtLjY3LTE0Ljg2LDMuNDEtMTguMjIsMTAuMjdsLTMwLjMsNjEuNzUsMTkuMiwxLjcsMjcuNTctNTYuMmMuOTktMi4wMSwzLjc1LTIuMjcsNS4xLS40OGw0Ny44MSw2My43OVoiLz4KICA8L2c+Cjwvc3ZnPg==" alt="ToolCTRL"></a>
|
||||
<a class="back" href="/"><svg class="ic" viewBox="0 0 24 24"><path d="M19 12H5M12 19l-7-7 7-7"/></svg> Startseite</a>
|
||||
</div>
|
||||
<div class="right">
|
||||
<span class="ev">TechDay Bruchsal · 27.05.2026</span>
|
||||
<img class="mit" src="data:image/png;base64,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 truncated
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===================== HERO ===================== -->
|
||||
<div class="hero">
|
||||
<div class="bg"></div>
|
||||
<div class="kicker">AI GameJam // TechDay Bruchsal 2026</div>
|
||||
<h1>Human in<br><span class="ln2">the Loop</span></h1>
|
||||
<div class="hsub">Ein Spiel bauen mit KI — in zwei Stunden. <b>Der Mensch steuert.</b></div>
|
||||
|
||||
<div class="hud">
|
||||
<span class="cn tl"></span><span class="cn br"></span>
|
||||
<div class="live" id="nowLabel"><span class="dot"></span> Jetzt läuft</div>
|
||||
<div class="pn" id="phaseName">—</div>
|
||||
<div class="ps" id="phaseSub">—</div>
|
||||
<div class="timer" id="timer">--:--</div>
|
||||
<div class="tl" id="timerLabel">bis zur nächsten Phase</div>
|
||||
</div>
|
||||
|
||||
<div class="hmeta">
|
||||
<span><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="18" rx="1"/><path d="M16 2v4M8 2v4M3 10h18"/></svg> 27. Mai 2026</span>
|
||||
<span><svg class="ic" viewBox="0 0 24 24"><path d="M20 10c0 6-8 12-8 12s-8-6-8-12a8 8 0 0 1 16 0Z"/><circle cx="12" cy="10" r="3"/></svg> TechDay Bruchsal</span>
|
||||
<span><svg class="ic" viewBox="0 0 24 24"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"/></svg> 15 Teilnehmer</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ===================== ABLAUF ===================== -->
|
||||
<section id="ablauf">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">Ablauf</div>
|
||||
<div id="schedule"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== THEME ===================== -->
|
||||
<section id="theme">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">Das Thema</div>
|
||||
<h2 class="big">Human in the Loop</h2>
|
||||
<p class="lead">
|
||||
<b>Der Mensch bleibt am Steuer — die KI ist Werkzeug, nicht Autopilot.</b>
|
||||
Heute baut ihr ein Spiel, indem ihr die KI führt: Konzept schärfen,
|
||||
Entscheidungen treffen, iterieren. Lasst das Thema auch in euer Spiel
|
||||
einfließen — die beste Interpretation fließt in die Bewertung ein.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== SO LÄUFT'S ===================== -->
|
||||
<section id="howto">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">So läuft's</div>
|
||||
<div class="steps">
|
||||
<div class="step">
|
||||
<div class="gn">1</div>
|
||||
<div class="sic"><svg class="ic" viewBox="0 0 24 24"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg></div>
|
||||
<div class="sk">Schritt 1</div>
|
||||
<h3>Planen</h3>
|
||||
<p>Im Terminal startet ihr den GDD-Dialog. Die KI stellt gezielte Fragen — am Ende steht euer Game-Konzept.</p>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="gn">2</div>
|
||||
<div class="sic"><svg class="ic" viewBox="0 0 24 24"><path d="m16 18 6-6-6-6M8 6l-6 6 6 6"/></svg></div>
|
||||
<div class="sk">Schritt 2</div>
|
||||
<h3>Bauen</h3>
|
||||
<p>Dann wird gecodet: ihr beschreibt, die KI baut, ihr testet im Browser und iteriert.</p>
|
||||
</div>
|
||||
<div class="step">
|
||||
<div class="gn">3</div>
|
||||
<div class="sic"><svg class="ic" viewBox="0 0 24 24"><path d="M6 9H4.5a2.5 2.5 0 0 1 0-5H6M18 9h1.5a2.5 2.5 0 0 0 0-5H18M4 22h16M10 14.66V17c0 .55-.47.98-.97 1.21C7.85 18.75 7 20.24 7 22M14 14.66V17c0 .55.47.98.97 1.21C16.15 18.75 17 20.24 17 22M18 2H6v7a6 6 0 0 0 12 0V2Z"/></svg></div>
|
||||
<div class="sk">Schritt 3</div>
|
||||
<h3>Zeigen</h3>
|
||||
<p>Game hochladen, Demo-Runde, die Jury bewertet. Die Besten gewinnen.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== BEWERTUNG ===================== -->
|
||||
<section id="bewertung">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">Bewertung</div>
|
||||
<h2 class="big">Vier Kategorien</h2>
|
||||
<p class="lead" style="margin-bottom:44px;">Je 0–10 Punkte. Der Durchschnitt ist die Gesamtnote — die Top 3 gewinnen.</p>
|
||||
<div class="cats">
|
||||
<div class="catcol"><div class="cnum">/01</div><div class="cn">Spielspaß</div><div class="cs">Macht es Spaß?</div><div class="cv">0 – 10 Punkte</div></div>
|
||||
<div class="catcol"><div class="cnum">/02</div><div class="cn">Kreativität</div><div class="cs">Wie originell?</div><div class="cv">0 – 10 Punkte</div></div>
|
||||
<div class="catcol"><div class="cnum">/03</div><div class="cn">Theme</div><div class="cs">Human in the Loop</div><div class="cv">0 – 10 Punkte</div></div>
|
||||
<div class="catcol"><div class="cnum">/04</div><div class="cn">Look & Feel</div><div class="cs">Präsentation & Game Feel</div><div class="cv">0 – 10 Punkte</div></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== PREISE ===================== -->
|
||||
<section id="preise">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">Preise</div>
|
||||
<div class="prizes">
|
||||
<div class="prizeitem first">
|
||||
<div class="pr">Erster Platz</div>
|
||||
<h3>Claude Max 5x</h3>
|
||||
<div class="dur">Ein Monat</div>
|
||||
</div>
|
||||
<div class="prizeitem">
|
||||
<div class="pr">Zweiter Platz</div>
|
||||
<h3>Claude Pro</h3>
|
||||
<div class="dur">Ein Monat</div>
|
||||
</div>
|
||||
<div class="prizeitem">
|
||||
<div class="pr">Dritter Platz</div>
|
||||
<h3>Claude Pro</h3>
|
||||
<div class="dur">Ein Monat</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== GAMES ===================== -->
|
||||
<section id="games">
|
||||
<div class="wrap">
|
||||
<div class="seclabel">Games</div>
|
||||
<h2 class="big">Spiel einreichen</h2>
|
||||
|
||||
<div class="uploadblock" style="margin:30px 0 60px;">
|
||||
<div class="field">
|
||||
<label>Teilnehmer</label>
|
||||
<input id="teamName" type="text" placeholder="z. B. Anna Schmidt" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Game-Name</label>
|
||||
<input id="gameName" type="text" placeholder="z. B. Cosmic Snake" />
|
||||
</div>
|
||||
<div class="dropzone" id="dropzone">
|
||||
<div class="dzi"><svg class="ic" viewBox="0 0 24 24"><path d="M12 13v8M16 16l-4-4-4 4M20.39 18.39A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.3"/></svg></div>
|
||||
<div class="big">HTML-Datei hier ablegen</div>
|
||||
<div class="sm">deine fertige .html — klicken zum Auswählen</div>
|
||||
<input id="fileInput" type="file" accept=".html,.htm" hidden />
|
||||
</div>
|
||||
<div style="margin-top:20px;">
|
||||
<button class="btn" id="uploadBtn" disabled>Einreichen</button>
|
||||
</div>
|
||||
<div class="status" id="uploadStatus"></div>
|
||||
</div>
|
||||
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:18px;">
|
||||
<span class="mono" style="color:var(--muted);font-size:13px;" id="galleryCount"></span>
|
||||
<button class="btn-ghost" id="refreshBtn">
|
||||
<svg class="ic" viewBox="0 0 24 24"><path d="M21 12a9 9 0 1 1-3-6.7L21 8M21 3v5h-5"/></svg> Aktualisieren
|
||||
</button>
|
||||
</div>
|
||||
<div class="games" id="gallery"></div>
|
||||
<div class="notice" id="galleryNotice" style="display:none;"></div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ===================== FOOTER ===================== -->
|
||||
<footer>
|
||||
<div class="inner">
|
||||
<div class="logos">
|
||||
<img class="tc" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgNzEzLjMyIDY3OC42MSI+CiAgPGRlZnM+CiAgICA8c3R5bGU+CiAgICAgIC5jbHMtMSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNSk7CiAgICAgIH0KCiAgICAgIC5jbHMtMiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNik7CiAgICAgIH0KCiAgICAgIC5jbHMtMyB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtNCk7CiAgICAgIH0KCiAgICAgIC5jbHMtNCB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMyk7CiAgICAgIH0KCiAgICAgIC5jbHMtNSB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQtMik7CiAgICAgIH0KCiAgICAgIC5jbHMtNiB7CiAgICAgICAgZmlsbDogdXJsKCNsaW5lYXItZ3JhZGllbnQpOwogICAgICB9CiAgICA8L3N0eWxlPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQiIHgxPSI2NTguOTYiIHkxPSIzMS45NiIgeDI9IjI5Ny43IiB5Mj0iNDU4LjYiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjMDAwIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iMSIgc3RvcC1jb2xvcj0iIzMzMyIvPgogICAgPC9saW5lYXJHcmFkaWVudD4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTIiIHgxPSIxNjg0LjMiIHkxPSIxMTQyLjc1IiB4Mj0iMjIwNi4wOSIgeTI9IjE1NTMuNTEiIGdyYWRpZW50VHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE4MzMuNzQgLTExMDguOTYpIHJvdGF0ZSg1LjA2KSBza2V3WCgxNC4yNSkiIGdyYWRpZW50VW5pdHM9InVzZXJTcGFjZU9uVXNlIj4KICAgICAgPHN0b3Agb2Zmc2V0PSIwIiBzdG9wLWNvbG9yPSIjYjJiMmIyIi8+CiAgICAgIDxzdG9wIG9mZnNldD0iLjc4IiBzdG9wLWNvbG9yPSIjZmZmIi8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtMyIgeDE9IjE3MTkuMTMiIHkxPSIxMDk4LjUxIiB4Mj0iMjI0MC45MSIgeTI9IjE1MDkuMjgiIHhsaW5rOmhyZWY9IiNsaW5lYXItZ3JhZGllbnQtMiIvPgogICAgPGxpbmVhckdyYWRpZW50IGlkPSJsaW5lYXItZ3JhZGllbnQtNCIgeDE9IjE3NjQuODIiIHkxPSIxMDQwLjQ3IiB4Mj0iMjI4Ni42IiB5Mj0iMTQ1MS4yNCIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgICA8bGluZWFyR3JhZGllbnQgaWQ9ImxpbmVhci1ncmFkaWVudC01IiB4MT0iMTgwNi4yNyIgeTE9Ijk4Ny44MiIgeDI9IjIzMjguMDUiIHkyPSIxMzk4LjU5IiB4bGluazpocmVmPSIjbGluZWFyLWdyYWRpZW50LTIiLz4KICAgIDxsaW5lYXJHcmFkaWVudCBpZD0ibGluZWFyLWdyYWRpZW50LTYiIHgxPSIzNDUuMDMiIHkxPSItMTAuMTUiIHgyPSIxMDE0LjU1IiB5Mj0iNTE2LjkxIiBncmFkaWVudFRyYW5zZm9ybT0ibWF0cml4KDEsMCwwLDEsMCwwKSIgeGxpbms6aHJlZj0iI2xpbmVhci1ncmFkaWVudC0yIi8+CiAgPC9kZWZzPgogIDxnPgogICAgPHBhdGggZD0iTTY4OC43LDU3Mi4wOWwtMTYwLDk4Ljk1Yy05LjE0LDUuNzMtMTkuOTksOC4zNS0zMC43Nyw3LjM3bC0zODAuNjgtMzQuMzZjLTIyLjQ4LTIuMDEtNDAuNzYtMTkuMDEtNDQuMzUtNDEuMzFMLjY0LDE1OS4zMWMtMy4xNy0xOS41Niw1LjYtMzkuMTIsMjIuMy00OS43MkwxODkuNDYsOC4wOGMtMTMuOTUsOS43NSwyMy43NywzMS41NSwyNi44OCw0OS45NWw5MS4zLDM2MS4xM2M2LjIxLDM2LjY4LDM2LjM3LDY0LjU4LDczLjQyLDY3LjkzbDI3OC42NCw0Mi45YzguNjUuNzksMjEuODcsNDUuNjgsMjguOTQsNDIuMDNsLjA2LjA2WiIvPgogICAgPHBhdGggY2xhc3M9ImNscy02IiBkPSJNNjg4LjY0LDU3Mi4wM2MtNy4wNywzLjY2LTE1LjIzLDUuMzYtMjMuODgsNC41N2wtMzQ5LTMxLjVjLTM3LjA0LTMuMzUtNjcuMjEtMzEuMjYtNzMuNDItNjcuOTNMMTcwLjM5LDUzLjM1Yy0zLjExLTE4LjQsNS4xMi0zNS41MiwxOS4wNy00NS4yN2wxLjk1LTEuMTZjNy45OC01LjA2LDE3LjYxLTcuNjIsMjcuOTEtNi43NmwzNTguNTYsMzAuMzRjMjkuNDksMi41LDUzLjU2LDI0LjYyLDU4LjYxLDUzLjhsNzYuMTYsNDQwLjM5YzMuNTMsMjAuMjktNy4xOSwzOC45OS0yNC4wMSw0Ny4zNFoiLz4KICA8L2c+CiAgPGc+CiAgICA8Zz4KICAgICAgPHBhdGggY2xhc3M9ImNscy01IiBkPSJNMzAwLjIyLDM0My45M2wtMTUuMDEsNC4yNiwxNS43Myw5Ni4wNWM0LjIzLDI1LjgzLDIxLjg4LDQyLjU5LDQ3LjIxLDQ0LjgzbDIwLjQyLDEuODEtMi40OC0xNS4xNC0yMC40Mi0xLjgxYy0xNS44MS0xLjQtMjYuMDQtMTEuNDQtMjguNzktMjguMjhsLTguMjQtNTAuMzQsNDQuOTMsMy45Ny0yLjQ1LTE0Ljk0LTQ0LjkzLTMuOTctNS45Ny0zNi40M1oiLz4KICAgICAgPHBhdGggY2xhc3M9ImNscy00IiBkPSJNNDIxLjk2LDM4Ny45N2MtMzEuODgtMi44Mi01MS4yNiwxOC4xLTQ2LjA4LDQ5LjczLDUuMTgsMzEuNjQsMzIuMDgsNTYuNjUsNjMuOTcsNTkuNDcsMzEuODgsMi44Miw1MS4yNi0xOC4xLDQ2LjA4LTQ5LjczLTUuMTgtMzEuNjQtMzIuMDgtNTYuNjUtNjMuOTctNTkuNDdaTTQzNy4zNiw0ODIuMDNjLTIyLjktMi4wMy00MS41NC0xOS42Ny00NS4zNS00Mi45LTMuOC0yMy4yMyw5LjUzLTM4LjA0LDMyLjQzLTM2LjAyLDIyLjksMi4wMyw0MS41NCwxOS42Niw0NS4zNSw0Mi45LDMuOCwyMy4yMy05LjUzLDM4LjA0LTMyLjQyLDM2LjAyWiIvPgogICAgICA8cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik01NDEuMzcsMzk4LjUzYy0zMS44OC0yLjgyLTUxLjI2LDE4LjEtNDYuMDgsNDkuNzMsNS4xOCwzMS42NCwzMi4wOCw1Ni42NSw2My45Nyw1OS40NywzMS44OCwyLjgyLDUxLjI2LTE4LjEsNDYuMDgtNDkuNzMtNS4xOC0zMS42NC0zMi4wOC01Ni42NS02My45Ny01OS40N1pNNTU2Ljc3LDQ5Mi41OWMtMjIuOS0yLjAzLTQxLjU0LTE5LjY3LTQ1LjM1LTQyLjktMy44LTIzLjIzLDkuNTMtMzguMDQsMzIuNDMtMzYuMDIsMjIuOSwyLjAzLDQxLjU0LDE5LjY2LDQ1LjM1LDQyLjksMy44LDIzLjIzLTkuNTMsMzguMDQtMzIuNDIsMzYuMDJaIi8+CiAgICAgIDxwb2x5Z29uIGNsYXNzPSJjbHMtMSIgcG9pbnRzPSI2MDcuNjcgMzY4LjQxIDYzMS4xIDUxMS40NiA2NDcuMDQgNTEyLjg3IDYyMi42OCAzNjQuMTUgNjA3LjY3IDM2OC40MSIvPgogICAgPC9nPgogICAgPHBhdGggY2xhc3M9ImNscy0yIiBkPSJNNTgyLjM5LDE2NC4wN2wxOC4zLDEuNjItNTYuMjktNzUuMTJjLTMuMTUtNC4yLTcuOTMtNi44Ni0xMy4xNi03LjMzaDBjLTcuNjEtLjY3LTE0Ljg2LDMuNDEtMTguMjIsMTAuMjdsLTMwLjMsNjEuNzUsMTkuMiwxLjcsMjcuNTctNTYuMmMuOTktMi4wMSwzLjc1LTIuMjcsNS4xLS40OGw0Ny44MSw2My43OVoiLz4KICA8L2c+Cjwvc3ZnPg==" alt="ToolCTRL">
|
||||
<img src="data:image/png;base64,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 truncated
|
||||
</div>
|
||||
<div class="ft">AI GameJam · Human in the Loop · veranstaltet von ToolCTRL beim TechDay Bruchsal 2026</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script type="module">
|
||||
/* ===================== PHASEN-LOGIK ===================== */
|
||||
const EVENT_DATE = "2026-05-27";
|
||||
const PHASES = [
|
||||
{ t: "17:00", name: "Begrüßung", sub: "Willkommen & Ablauf" },
|
||||
{ t: "17:10", name: "Intro & Orientierung", sub: "AI-Tools & BMAD kennenlernen" },
|
||||
{ t: "17:30", name: "Setup-Phase", sub: "Tools startklar machen" },
|
||||
{ t: "17:40", name: "Phase 1 — GDD-Dialog", sub: "Game-Konzept mit der KI schärfen" },
|
||||
{ t: "18:10", name: "Phase 2 — Coding", sub: "Jetzt wird das Game gebaut" },
|
||||
{ t: "19:00", name: "Freeze & Abgabe", sub: "Deadline — Game hochladen" },
|
||||
{ t: "19:10", name: "Demo-Runde", sub: "Jedes Team zeigt sein Game" },
|
||||
{ t: "19:30", name: "Jury-Beratung", sub: "Die Top 3 werden ermittelt" },
|
||||
{ t: "19:38", name: "Siegerehrung", sub: "Gewinner & Preise" },
|
||||
{ t: "19:48", name: "Networking", sub: "Ausklang — Games spielen & austauschen" },
|
||||
{ t: "20:10", name: "Ende", sub: "Danke fürs Dabeisein" },
|
||||
];
|
||||
|
||||
function phaseDate(hhmm) { return new Date(`${EVENT_DATE}T${hhmm}:00`); }
|
||||
function getNow() {
|
||||
const sim = new URLSearchParams(location.search).get("sim");
|
||||
if (sim && /^\d{1,2}:\d{2}$/.test(sim)) return phaseDate(sim.padStart(5, "0"));
|
||||
return new Date();
|
||||
}
|
||||
function fmt(ms) {
|
||||
if (ms < 0) ms = 0;
|
||||
const s = Math.floor(ms / 1000);
|
||||
const h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60;
|
||||
const pad = n => String(n).padStart(2, "0");
|
||||
return h > 0 ? `${pad(h)}:${pad(m)}:${pad(sec)}` : `${pad(m)}:${pad(sec)}`;
|
||||
}
|
||||
|
||||
function renderHud() {
|
||||
const now = getNow();
|
||||
const start = phaseDate(PHASES[0].t);
|
||||
const end = phaseDate(PHASES[PHASES.length - 1].t);
|
||||
const nameEl = document.getElementById("phaseName");
|
||||
const subEl = document.getElementById("phaseSub");
|
||||
const timerEl = document.getElementById("timer");
|
||||
const timerLabelEl = document.getElementById("timerLabel");
|
||||
const nowLabelEl = document.getElementById("nowLabel");
|
||||
const DOT = '<span class="dot"></span> ';
|
||||
|
||||
if (now < start) {
|
||||
nowLabelEl.innerHTML = DOT + "Startet bald";
|
||||
nameEl.textContent = "Gleich geht's los";
|
||||
subEl.textContent = "Die AI GameJam beginnt um " + PHASES[0].t + " Uhr";
|
||||
timerEl.textContent = fmt(start - now);
|
||||
timerLabelEl.textContent = "bis Start";
|
||||
} else if (now >= end) {
|
||||
nowLabelEl.innerHTML = DOT + "Vorbei";
|
||||
nameEl.textContent = "Event beendet";
|
||||
subEl.textContent = "Danke an alle — die Games gibt's unten zum Spielen";
|
||||
timerEl.textContent = "//";
|
||||
timerLabelEl.textContent = "bis bald";
|
||||
} else {
|
||||
let idx = 0;
|
||||
for (let i = 0; i < PHASES.length; i++) {
|
||||
if (now >= phaseDate(PHASES[i].t)) idx = i;
|
||||
}
|
||||
const cur = PHASES[idx], next = PHASES[idx + 1];
|
||||
nowLabelEl.innerHTML = DOT + "Jetzt läuft";
|
||||
nameEl.textContent = cur.name;
|
||||
subEl.textContent = cur.sub;
|
||||
if (next) {
|
||||
timerEl.textContent = fmt(phaseDate(next.t) - now);
|
||||
timerLabelEl.textContent = "bis: " + next.name;
|
||||
} else { timerEl.textContent = ""; timerLabelEl.textContent = ""; }
|
||||
}
|
||||
renderSchedule(now);
|
||||
}
|
||||
|
||||
const CHECK = '<svg class="ic" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></svg>';
|
||||
|
||||
function renderSchedule(now) {
|
||||
const box = document.getElementById("schedule");
|
||||
let html = "";
|
||||
PHASES.forEach((p, i) => {
|
||||
const startT = phaseDate(p.t);
|
||||
const nextT = i < PHASES.length - 1 ? phaseDate(PHASES[i + 1].t) : startT;
|
||||
let cls = "tl-row", mark = "";
|
||||
if (now >= nextT && i < PHASES.length - 1) { cls += " done"; mark = CHECK; }
|
||||
else if (now >= startT && now < nextT) { cls += " active"; }
|
||||
html += `<div class="${cls}"><div class="tt">${p.t}</div>` +
|
||||
`<div><div class="tn">${p.name}</div><div class="ts">${p.sub}</div></div>` +
|
||||
`<div class="tx">${mark}</div></div>`;
|
||||
});
|
||||
box.innerHTML = html;
|
||||
}
|
||||
|
||||
renderHud();
|
||||
setInterval(renderHud, 1000);
|
||||
|
||||
/* ===================== UPLOAD + GALERIE ===================== */
|
||||
/* API_BASE = Endpunkt der GameJam-API (Next.js-Routes in der mITapp, Postgres/Prisma).
|
||||
Solange leer -> Upload & Galerie zeigen einen Hinweis, der Live-Teil läuft trotzdem.
|
||||
Erwartete Endpunkte:
|
||||
GET {API_BASE}/games -> [ { id, teilnehmer, game, url } ]
|
||||
POST {API_BASE}/upload -> FormData { teilnehmer, game, file } */
|
||||
const API_BASE = "/api/gamejam";
|
||||
|
||||
const teamEl = document.getElementById("teamName");
|
||||
const gameEl = document.getElementById("gameName");
|
||||
const dz = document.getElementById("dropzone");
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const uploadBtn = document.getElementById("uploadBtn");
|
||||
const statusEl = document.getElementById("uploadStatus");
|
||||
const gallery = document.getElementById("gallery");
|
||||
const galleryCount = document.getElementById("galleryCount");
|
||||
const galleryNotice = document.getElementById("galleryNotice");
|
||||
let chosenFile = null;
|
||||
|
||||
function escapeHtml(s) {
|
||||
return String(s).replace(/[&<>"]/g, c => ({ "&": "&", "<": "<", ">": ">", '"': """ }[c]));
|
||||
}
|
||||
function setStatus(msg, kind) {
|
||||
statusEl.textContent = msg;
|
||||
statusEl.className = "status" + (kind ? " " + kind : "");
|
||||
}
|
||||
|
||||
dz.addEventListener("click", () => fileInput.click());
|
||||
dz.addEventListener("dragover", e => { e.preventDefault(); dz.classList.add("drag"); });
|
||||
dz.addEventListener("dragleave", () => dz.classList.remove("drag"));
|
||||
dz.addEventListener("drop", e => {
|
||||
e.preventDefault(); dz.classList.remove("drag");
|
||||
if (e.dataTransfer.files[0]) pickFile(e.dataTransfer.files[0]);
|
||||
});
|
||||
fileInput.addEventListener("change", () => { if (fileInput.files[0]) pickFile(fileInput.files[0]); });
|
||||
|
||||
function pickFile(f) {
|
||||
if (!/\.html?$/i.test(f.name)) { setStatus("Nur einzelne .html-Dateien.", "err"); return; }
|
||||
chosenFile = f;
|
||||
dz.querySelector(".big").textContent = f.name + " ausgewählt";
|
||||
refreshUploadBtn();
|
||||
}
|
||||
function refreshUploadBtn() {
|
||||
uploadBtn.disabled = !(API_BASE && chosenFile && teamEl.value.trim() && gameEl.value.trim());
|
||||
}
|
||||
teamEl.addEventListener("input", refreshUploadBtn);
|
||||
gameEl.addEventListener("input", refreshUploadBtn);
|
||||
|
||||
uploadBtn.addEventListener("click", async () => {
|
||||
if (!API_BASE || !chosenFile) return;
|
||||
uploadBtn.disabled = true;
|
||||
setStatus("Wird eingereicht…", null);
|
||||
try {
|
||||
const fd = new FormData();
|
||||
fd.append("teilnehmer", teamEl.value.trim());
|
||||
fd.append("game", gameEl.value.trim());
|
||||
fd.append("file", chosenFile);
|
||||
const res = await fetch(API_BASE + "/upload", { method: "POST", body: fd });
|
||||
if (!res.ok) throw new Error((await res.text()) || ("HTTP " + res.status));
|
||||
setStatus("Eingereicht — dein Spiel ist jetzt in der Galerie.", "ok");
|
||||
chosenFile = null;
|
||||
dz.querySelector(".big").textContent = "HTML-Datei hier ablegen";
|
||||
teamEl.value = ""; gameEl.value = "";
|
||||
loadGallery();
|
||||
} catch (e) {
|
||||
setStatus("Fehler: " + (e.message || e), "err");
|
||||
}
|
||||
refreshUploadBtn();
|
||||
});
|
||||
|
||||
async function loadGallery() {
|
||||
if (!API_BASE) {
|
||||
galleryCount.textContent = "";
|
||||
galleryNotice.style.display = "block";
|
||||
galleryNotice.textContent = "Upload & Galerie sind noch nicht verbunden — die GameJam-API fehlt (siehe API_BASE im Quelltext). Der Live-Teil der Seite funktioniert bereits.";
|
||||
return;
|
||||
}
|
||||
galleryCount.textContent = "Lädt…";
|
||||
gallery.innerHTML = "";
|
||||
galleryNotice.style.display = "none";
|
||||
let games = [];
|
||||
try {
|
||||
const res = await fetch(API_BASE + "/games?v=" + Date.now());
|
||||
if (res.ok) games = await res.json();
|
||||
} catch (_) {}
|
||||
if (!Array.isArray(games) || games.length === 0) {
|
||||
galleryCount.textContent = "";
|
||||
galleryNotice.style.display = "block";
|
||||
galleryNotice.textContent = "Sobald die Teams ihre Spiele eingereicht haben, erscheinen sie hier.";
|
||||
return;
|
||||
}
|
||||
galleryCount.textContent = games.length + (games.length > 1 ? " Spiele" : " Spiel");
|
||||
for (const g of games) {
|
||||
const url = g.url || "";
|
||||
const name = escapeHtml(g.game || "Spiel");
|
||||
const who = escapeHtml(g.teilnehmer || g.team || "");
|
||||
gallery.insertAdjacentHTML("beforeend", `
|
||||
<div class="game">
|
||||
<iframe class="frame" src="${url}" sandbox="allow-scripts allow-pointer-lock"
|
||||
loading="lazy" title="${name}"></iframe>
|
||||
<div class="gm">
|
||||
<div><div class="gt">${name}</div><div class="gte">${who}</div></div>
|
||||
<a href="${url}" target="_blank" rel="noopener">Spielen
|
||||
<svg class="ic" viewBox="0 0 24 24"><path d="M7 17 17 7M7 7h10v10"/></svg></a>
|
||||
</div>
|
||||
</div>`);
|
||||
}
|
||||
}
|
||||
loadGallery();
|
||||
document.getElementById("refreshBtn").addEventListener("click", loadGallery);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -21,6 +21,7 @@
|
||||
<a href="#leistungen">Leistungen</a>
|
||||
<a href="#vorgehen">Vorgehen</a>
|
||||
<a href="#arbeit">Organisation</a>
|
||||
<a href="/gamejam.html">GameJam</a>
|
||||
<a class="btn btn-solid btn-sm" href="#kontakt">Kontakt aufnehmen</a>
|
||||
</nav>
|
||||
<button class="nav-toggle" aria-label="Menü" aria-expanded="false">
|
||||
@@ -31,6 +32,7 @@
|
||||
<a href="#leistungen">Leistungen</a>
|
||||
<a href="#vorgehen">Vorgehen</a>
|
||||
<a href="#arbeit">Organisation</a>
|
||||
<a href="/gamejam.html">GameJam</a>
|
||||
<a class="btn btn-solid" href="#kontakt">Kontakt aufnehmen</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/* ============================================================
|
||||
ToolCTRL — Landing Page Server
|
||||
Abhängigkeitsfrei (nur Node-Standardbibliothek).
|
||||
Liefert /public und nimmt Leads unter POST /api/lead entgegen.
|
||||
- Liefert /public
|
||||
- POST /api/lead — Kontakt-Leads
|
||||
- POST /api/gamejam/upload — GameJam: Spiel einreichen (Datei-Upload)
|
||||
- GET /api/gamejam/games — GameJam: eingereichte Spiele
|
||||
============================================================ */
|
||||
|
||||
"use strict";
|
||||
@@ -9,6 +12,7 @@
|
||||
const http = require("http");
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const crypto = require("crypto");
|
||||
|
||||
const ROOT = __dirname;
|
||||
const PUBLIC_DIR = path.join(ROOT, "public");
|
||||
@@ -16,6 +20,12 @@ const LEADS_DIR = path.join(ROOT, "leads");
|
||||
const LEADS_JSON = path.join(LEADS_DIR, "leads.ndjson");
|
||||
const LEADS_CSV = path.join(LEADS_DIR, "leads.csv");
|
||||
|
||||
/* GameJam-Speicher */
|
||||
const GAMEJAM_DIR = path.join(ROOT, "gamejam");
|
||||
const SUBMISSIONS_JSON = path.join(GAMEJAM_DIR, "submissions.ndjson");
|
||||
const GAMES_DIR = path.join(PUBLIC_DIR, "gamejam-games");
|
||||
const MAX_UPLOAD = 5 * 1024 * 1024; /* 5 MB pro eingereichtem Spiel */
|
||||
|
||||
/* Bevorzugte Ports — der erste freie wird genutzt. */
|
||||
const PORT_CANDIDATES = [4317, 4318, 4417, 5317, 8317, 0];
|
||||
const HOST = "127.0.0.1";
|
||||
@@ -45,6 +55,12 @@ function ensureLeadStore() {
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------- GameJam-Speicher vorbereiten ---------- */
|
||||
function ensureGamejamStore() {
|
||||
if (!fs.existsSync(GAMEJAM_DIR)) fs.mkdirSync(GAMEJAM_DIR, { recursive: true });
|
||||
if (!fs.existsSync(GAMES_DIR)) fs.mkdirSync(GAMES_DIR, { recursive: true });
|
||||
}
|
||||
|
||||
function csvCell(value) {
|
||||
const s = String(value == null ? "" : value);
|
||||
return '"' + s.replace(/"/g, '""').replace(/\r?\n/g, " ") + '"';
|
||||
@@ -162,6 +178,154 @@ function handleLead(req, res) {
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- Multipart-Parser (abhängigkeitsfrei) ---------- */
|
||||
function parseMultipart(buffer, boundary) {
|
||||
const result = { fields: {}, files: [] };
|
||||
const delim = Buffer.from("--" + boundary);
|
||||
let start = buffer.indexOf(delim);
|
||||
if (start < 0) return result;
|
||||
start += delim.length;
|
||||
|
||||
while (start < buffer.length) {
|
||||
/* "--" direkt nach dem Delimiter => Ende */
|
||||
if (buffer[start] === 0x2d && buffer[start + 1] === 0x2d) break;
|
||||
if (buffer[start] === 0x0d && buffer[start + 1] === 0x0a) start += 2;
|
||||
|
||||
const next = buffer.indexOf(delim, start);
|
||||
if (next < 0) break;
|
||||
|
||||
let partEnd = next;
|
||||
if (buffer[partEnd - 2] === 0x0d && buffer[partEnd - 1] === 0x0a) partEnd -= 2;
|
||||
const part = buffer.slice(start, partEnd);
|
||||
start = next + delim.length;
|
||||
|
||||
const headerEnd = part.indexOf("\r\n\r\n");
|
||||
if (headerEnd < 0) continue;
|
||||
const headerStr = part.slice(0, headerEnd).toString("utf8");
|
||||
const content = part.slice(headerEnd + 4);
|
||||
|
||||
const nameM = headerStr.match(/name="([^"]*)"/i);
|
||||
if (!nameM) continue;
|
||||
const fileM = headerStr.match(/filename="([^"]*)"/i);
|
||||
|
||||
if (fileM) {
|
||||
result.files.push({
|
||||
field: nameM[1],
|
||||
filename: fileM[1],
|
||||
data: content
|
||||
});
|
||||
} else {
|
||||
result.fields[nameM[1]] = content.toString("utf8");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/* ---------- GameJam: Spiel einreichen ---------- */
|
||||
function handleGamejamUpload(req, res) {
|
||||
const ctype = req.headers["content-type"] || "";
|
||||
const bM = ctype.match(/boundary=(?:"([^"]+)"|([^;]+))/i);
|
||||
if (!/multipart\/form-data/i.test(ctype) || !bM) {
|
||||
return sendJSON(res, 400, { error: "Ungültiges Upload-Format." });
|
||||
}
|
||||
const boundary = (bM[1] || bM[2]).trim();
|
||||
|
||||
const chunks = [];
|
||||
let size = 0;
|
||||
let tooLarge = false;
|
||||
|
||||
req.on("data", (chunk) => {
|
||||
size += chunk.length;
|
||||
if (size > MAX_UPLOAD) {
|
||||
tooLarge = true;
|
||||
req.destroy();
|
||||
return;
|
||||
}
|
||||
chunks.push(chunk);
|
||||
});
|
||||
|
||||
req.on("end", () => {
|
||||
if (tooLarge) {
|
||||
return sendJSON(res, 413, { error: "Datei zu groß (max. 5 MB)." });
|
||||
}
|
||||
|
||||
let parsed;
|
||||
try {
|
||||
parsed = parseMultipart(Buffer.concat(chunks), boundary);
|
||||
} catch (e) {
|
||||
return sendJSON(res, 400, { error: "Upload konnte nicht gelesen werden." });
|
||||
}
|
||||
|
||||
const teilnehmer = String(parsed.fields.teilnehmer || "").trim();
|
||||
const game = String(parsed.fields.game || "").trim();
|
||||
const file = parsed.files.find((f) => f.field === "file");
|
||||
|
||||
if (!teilnehmer || !game) {
|
||||
return sendJSON(res, 400, { error: "Teilnehmer und Game-Name angeben." });
|
||||
}
|
||||
if (!file || !file.data || file.data.length === 0) {
|
||||
return sendJSON(res, 400, { error: "Keine Datei ausgewählt." });
|
||||
}
|
||||
if (!/\.html?$/i.test(file.filename || "")) {
|
||||
return sendJSON(res, 400, { error: "Nur einzelne .html-Dateien." });
|
||||
}
|
||||
|
||||
const id = Date.now().toString(36) + "-" + crypto.randomBytes(4).toString("hex");
|
||||
const entry = {
|
||||
id: id,
|
||||
zeitpunkt: new Date().toISOString(),
|
||||
teilnehmer: teilnehmer.slice(0, 200),
|
||||
game: game.slice(0, 200),
|
||||
url: "/gamejam-games/" + id + ".html"
|
||||
};
|
||||
|
||||
try {
|
||||
ensureGamejamStore();
|
||||
fs.writeFileSync(path.join(GAMES_DIR, id + ".html"), file.data);
|
||||
fs.appendFileSync(SUBMISSIONS_JSON, JSON.stringify(entry) + "\n", "utf8");
|
||||
} catch (e) {
|
||||
console.error("[gamejam] Speichern fehlgeschlagen:", e.message);
|
||||
return sendJSON(res, 500, { error: "Speichern fehlgeschlagen." });
|
||||
}
|
||||
|
||||
console.log(
|
||||
"[gamejam] " + entry.zeitpunkt + " — \"" + entry.game +
|
||||
"\" von " + entry.teilnehmer
|
||||
);
|
||||
sendJSON(res, 200, { ok: true, id: id });
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- GameJam: eingereichte Spiele ---------- */
|
||||
function handleGamejamGames(req, res) {
|
||||
let games = [];
|
||||
try {
|
||||
if (fs.existsSync(SUBMISSIONS_JSON)) {
|
||||
games = fs
|
||||
.readFileSync(SUBMISSIONS_JSON, "utf8")
|
||||
.split("\n")
|
||||
.filter(Boolean)
|
||||
.map((line) => {
|
||||
try {
|
||||
return JSON.parse(line);
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter(Boolean)
|
||||
.map((g) => ({
|
||||
id: g.id,
|
||||
teilnehmer: g.teilnehmer,
|
||||
game: g.game,
|
||||
url: g.url
|
||||
}));
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("[gamejam] Galerie konnte nicht gelesen werden:", e.message);
|
||||
}
|
||||
sendJSON(res, 200, games);
|
||||
}
|
||||
|
||||
function sendJSON(res, code, obj) {
|
||||
res.writeHead(code, { "Content-Type": "application/json; charset=utf-8" });
|
||||
res.end(JSON.stringify(obj));
|
||||
@@ -178,6 +342,20 @@ const server = http.createServer((req, res) => {
|
||||
return handleLead(req, res);
|
||||
}
|
||||
|
||||
if (route === "/api/gamejam/upload") {
|
||||
if (req.method !== "POST") {
|
||||
return sendJSON(res, 405, { error: "Methode nicht erlaubt." });
|
||||
}
|
||||
return handleGamejamUpload(req, res);
|
||||
}
|
||||
|
||||
if (route === "/api/gamejam/games") {
|
||||
if (req.method !== "GET") {
|
||||
return sendJSON(res, 405, { error: "Methode nicht erlaubt." });
|
||||
}
|
||||
return handleGamejamGames(req, res);
|
||||
}
|
||||
|
||||
if (req.method !== "GET" && req.method !== "HEAD") {
|
||||
res.writeHead(405).end("Method Not Allowed");
|
||||
return;
|
||||
@@ -204,13 +382,15 @@ function listen(candidates) {
|
||||
server.listen(port, HOST, () => {
|
||||
const actual = server.address().port;
|
||||
ensureLeadStore();
|
||||
ensureGamejamStore();
|
||||
console.log("");
|
||||
console.log(" ToolCTRL — Landing Page läuft");
|
||||
console.log(" ----------------------------------------");
|
||||
console.log(" URL: http://" + HOST + ":" + actual);
|
||||
console.log(" Leads: " + LEADS_CSV);
|
||||
console.log(" " + LEADS_JSON);
|
||||
console.log(" Stop: Strg + C");
|
||||
console.log(" URL: http://" + HOST + ":" + actual);
|
||||
console.log(" GameJam: http://" + HOST + ":" + actual + "/gamejam.html");
|
||||
console.log(" Leads: " + LEADS_CSV);
|
||||
console.log(" GameJam-Einreichungen: " + SUBMISSIONS_JSON);
|
||||
console.log(" Stop: Strg + C");
|
||||
console.log("");
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user