MCQ Quiz-Seite
Das Design der Seite ist fertig. Gestalten Sie es nicht neu. Ihre Aufgabe ist es, gute Fragen zu schreiben, sie als JSON in die untenstehende Vorlage einzufügen und zu veröffentlichen.
Was die Seite macht:
- Multiple Choice: Tippen Sie auf eine Option – sie wird grün (richtig) oder rot (falsch, wobei die richtige Option grün wird und eine Erklärung angezeigt wird). Eine kleine Schaltfläche „Diese Frage wiederholen“ unter jeder beantworteten Frage setzt nur diese zurück.
- Strukturierte / Programmanalyse-Fragen (Typ „short“): Der Benutzer gibt eine Antwort ein (optional), tippt auf „Musterlösung anzeigen“ und bewertet sich dann selbst mit „Habe ich verstanden“ oder „Nicht verstanden“. Nicht verstandene zählen als Fehler. Code-Ausschnitte werden in einem Monospace-Block angezeigt.
- Der Reiter „Überprüfung“ listet nur die Fehler auf, mit der richtigen Antwort / Musterlösung direkt darunter. Der Überprüfungsmodus bietet Export als PDF, Kopieren als Text und Fehler wiederholen.
- „Fehler wiederholen“ löscht die Antworten dieser Fragen und öffnet einen Reiter „Wiederholung“, der NUR die früheren Fehler zeigt (kein Scrollen durch das gesamte Quiz). Er zeigt den Fortschritt (erledigt/gesamt) und nach Abschluss eine Zusammenfassung mit „Die N noch falschen wiederholen“ und „Zurück zu allen Fragen“. Der Wiederholungsreiter bleibt verfügbar, bis „Alles zurücksetzen“ ausgeführt wird.
- Fortschritt, eingegebene Antworten und die Wiederholungsliste werden im Browser des Betrachters gespeichert.
Schritte
- Lesen Sie zuerst das Quellmaterial (Folien, Notizen, PDFs). Fragen müssen daraus stammen, nicht aus dem Gedächtnis. Verwenden Sie für PDFs
pdftotext -layout. Wenn der Benutzer Lösungen zu Übungen oder Altklausuren anhängt, erstellen Sie sowohl MCQs als auch strukturierte/Programmanalyse-Fragen darauf basierend (neue Variationen, keine wortwörtlichen Kopien, sofern nicht anders gewünscht). - Schreiben Sie die Fragen als JSON-Array (Schema unten). Standardmäßig 4 Optionen für MCQs. Wenn der Benutzer eine Anzahl angibt, verwenden Sie genau diese Anzahl. Fügen Sie strukturierte / Programmanalyse-Fragen hinzu, wenn die Quelle Kurzantwort- oder Code-Fragen enthält, oder wenn der Benutzer danach fragt (fügen Sie sie nach den MCQs desselben Abschnitts ein).
- Überprüfen Sie die Fragen mit den Ausgewogenheitsregeln unten, idealerweise mit einem kleinen Skript.
- Erstellen Sie die Seite: Kopieren Sie die Vorlage in
index.html, ersetzen Sie den Text__DATA__durch das JSON (escapen Sie jedes</als</), und ändern Sie nur: den<title>, die<h1>, den.sub-Satz und den Speicherschlüsselbps-quiz-v1(geben Sie jedem Quiz einen neuen Schlüssel, z. B.quiz-<thema>-v1, damit gespeicherte Fortschritte sich nie vermischen). Führen Sie nach Möglichkeitnode --checkfür das Skript aus (extrahieren Sie den Skriptblock in eine .js-Datei). Ein kurzer Playwright-Smoke-Test (Antwort, Markierung, Überprüfung, Fehler wiederholen) ist empfehlenswert. - Veröffentlichen Sie es als handgeschriebenes HTML-Artefakt: Nennen Sie das Artefakt zuerst
list_types(es gibt keinen Quiz-Typ; verwenden Siepublish_filesmitindex.html, einem aussagekräftigen Titel, Iconquiz). Rufen Sie danndeclare_capabilitiesmit{"downloads": true}auf, unter Verwendung der neuesten Versionsnummer. Die PDF-Schaltfläche funktioniert nur mit dieser Fähigkeit. Wenn Sie ein bestehendes Quiz aktualisieren, veröffentlichen Sie es erneut mitpublish_files(Modus patch, slug, base_version); die Capability-Deklaration bleibt erhalten. Wenn Sie keine Artefakte veröffentlichen können, liefern Sieindex.htmlstattdessen als Datei aus (die PDF-Schaltfläche bleibt dann ausgeblendet; „Als Text kopieren“ funktioniert trotzdem). - Antworten Sie in ein paar Sätzen: was die Seite ist, wie viele Fragen (MCQ und strukturiert) und aus welchen Abschnitten, und dass der PDF-Export den Betrachter auffordert, den Download zu bestätigen. Fügen Sie die Fragen nicht in den Chat ein.
JSON-Schema (ein Objekt pro Frage, in Reihenfolge)
Multiple Choice:
{"n": 1, "section": "Vorlesung 4 · Linkability", "q": "Fragetext?", "opts": ["A Text", "B Text", "C Text", "D Text"], "ans": 2, "ex": "Ein-Satz-Erklärung."}
Strukturierte oder Programmanalyse (optional code, optional kind, optional ex):
{"n": 5, "type": "short", "section": "Vorlesung 4 · Linkability", "kind": "Strukturierte Frage", "q": "Beschreiben Sie ...?", "model": ["Punkt 1 der Musterlösung", "Punkt 2"], "ex": "Optionaler Zusatzhinweis"}
{"n": 6, "type": "short", "section": "...", "kind": "Programmanalyse", "q": "Was ist hier falsch und wie behebt man es?", "code": "int f(char *s) {\n char b[8];\n strcpy(b, s);\n}", "model": ["(a) ...", "(b) ..."]}
kind ist standardmäßig „Kurzantwort“; verwenden Sie „Strukturierte Frage“ oder „Programmanalyse“. Jeder model-Eintrag ist ein Aufzählungspunkt; beschriften Sie Unterteile mit „(a)“, „(b)“ innerhalb der Aufzählungspunkte. Schreiben Sie code mit \n-Zeilenumbrüchen und 2-Leerzeichen-Einrückung.
Optionale Notizen pro Option (NUR wenn der Benutzer zusätzlichen Text unter den falschen Optionen wünscht): Fügen Sie "notes": ["", "Warum B falsch ist", "", "Warum D falsch ist"] zu einem MCQ hinzu, ein String pro Option in derselben Reihenfolge, mit "" für Optionen, die keine benötigen (normalerweise die richtige). Notizen erscheinen unter jeder Option, nachdem der Benutzer geantwortet hat, sowie in Kopie/PDF. Fügen Sie keine Notizen hinzu, wenn nicht danach gefragt wird.
n läuft von 1 bis N ohne Lücken über alle Fragen (die Seite indiziert mit n-1). ans ist der 0-basierte Index der richtigen Option. section gruppiert Fragen auf der Seite; verwenden Sie denselben String für Fragen in einer Gruppe und halten Sie Gruppen zusammenhängend. Vermeiden Sie nach Möglichkeit Zeichen außerhalb des einfachen lateinischen Texts (das PDF verwendet eine integrierte Schriftart; ungewöhnliche Symbole werden als ? gedruckt).
Regeln zur Fragenqualität (der Benutzer legt Wert darauf)
- Distraktoren müssen überzeugend sein: Verwenden Sie reale Konzepte aus demselben Material, die an die falsche Frage gehängt werden (die Eigenschaft eines benachbarten Begriffs, eine nahegelegene Zahl, ein plausibler Mechanismus). Keine Witz-Optionen, kein „Alle oben genannten“.
- Lassen Sie nicht die richtige Antwort die längste sein. Schreiben Sie die richtige Option und die Distraktoren in ähnlicher Länge und Detailtiefe, und machen Sie manchmal einen Distraktor zum längsten. Ziel: Die richtige Option ist bei nicht mehr als etwa 30 % der Fragen mit vollständigen Satzoptionen strikt die längste (überprüfen Sie dies mit einem Skript; es ist leicht, zu übertreiben).
- Verteilen Sie den richtigen Buchstaben gleichmäßig auf A-D (etwa 25 % jeder) und niemals denselben Buchstaben dreimal hintereinander. Einfachste Methode: Schreiben Sie die richtige Option und drei Distraktoren separat und mischen Sie sie dann mit einer ausgewogenen Positionsliste im Code.
- Testen Sie eine Idee pro Frage. Halten Sie den Fragetext in sich geschlossen.
- Jeder MCQ erhält eine Erklärung in
ex, die sagt, warum die Antwort richtig ist (und, wo hilfreich, was die Distraktoren tatsächlich sind). - Musterlösungen für strukturierte/Programmanalyse-Fragen sollten die Kernpunkte der Quellenlösung als kurze Aufzählungspunkte widerspiegeln, damit der Benutzer sich ehrlich selbst bewerten kann.
- Wenn eine Folie nur ein Diagramm ist, das Sie nicht lesen können, sagen Sie dies, anstatt Details zu erfinden.
Vorlage (index.html)
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Topic Quiz</title>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@500&display=swap">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
:root{--bg:#f5f6f8;--card:#ffffff;--ink:#16202e;--mute:#5b6678;--line:#d5dae3;--accent:#1d4ed8;--accent-soft:#e6ecff;
--ok:#0f7a4d;--ok-soft:#dcf3e6;--ok-line:#52b887;--bad:#b42318;--bad-soft:#fde4e1;--bad-line:#e57a70;
--body:"IBM Plex Sans",system-ui,-apple-system,"Segoe UI",sans-serif;--mono:"IBM Plex Mono",ui-monospace,Menlo,monospace}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){--bg:#10151d;--card:#171e29;--ink:#e6eaf1;--mute:#9aa6b8;--line:#2e3849;--accent:#8aa9ff;--accent-soft:#1f2a45;--ok:#6fe0aa;--ok-soft:#12332a;--ok-line:#2f8a63;--bad:#ff9a8f;--bad-soft:#3b1b1a;--bad-line:#a94a42;color-scheme:dark}}
:root[data-theme="dark"]{--bg:#10151d;--card:#171e29;--ink:#e6eaf1;--mute:#9aa6b8;--line:#2e3849;--accent:#8aa9ff;--accent-soft:#1f2a45;--ok:#6fe0aa;--ok-soft:#12332a;--ok-line:#2f8a63;--bad:#ff9a8f;--bad-soft:#3b1b1a;--bad-line:#a94a42;color-scheme:dark}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);font:400 16px/1.55 var(--body)}
main{max-width:760px;margin:0 auto;padding:24px 16px 64px}
h1{font-size:1.7rem;line-height:1.2;margin:0 0 6px;text-wrap:balance}
.sub{color:var(--mute);margin:0 0 14px}
.bar{position:sticky;top:0;z-index:3;background:var(--bg);border-bottom:1px solid var(--line);padding:10px 0;display:flex;flex-wrap:wrap;gap:8px 10px;align-items:center}
.tabs{display:inline-flex;border:1px solid var(--line);border-radius:9px;overflow:hidden;background:var(--card)}
.tabs button{border:0;background:transparent;color:var(--ink);font:500 .88rem var(--body);padding:8px 14px;cursor:pointer}
.tabs button[aria-pressed="true"]{background:var(--accent);color:var(--bg)}
.stats{font-size:.88rem;color:var(--mute);font-variant-numeric:tabular-nums;display:flex;gap:12px;flex-wrap:wrap}
.stats b{color:var(--ink)}
.acts{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.btn{font:500 .85rem var(--body);color:var(--ink);background:var(--card);border:1px solid var(--line);border-radius:8px;padding:7px 12px;cursor:pointer;text-decoration:none;display:inline-flex;gap:8px;align-items:center}
.btn.primary{background:var(--accent);border-color:var(--accent);color:var(--bg)}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn:not(:disabled):hover{filter:brightness(.95)}
:focus-visible{outline:3px solid var(--accent);outline-offset:2px}
.jump{display:flex;flex-wrap:wrap;gap:8px;margin:14px 0 0}
.jump a{font:500 .85rem var(--body);color:var(--ink);background:var(--card);border:1px solid var(--line);border-radius:8px;padding:7px 11px;text-decoration:none}
.jump a span{color:var(--mute);margin-left:8px;font-variant-numeric:tabular-nums}
h2{font-size:1.08rem;margin:30px 0 14px;padding-bottom:8px;border-bottom:2px solid var(--accent);text-wrap:balance;scroll-margin-top:70px}
.banner{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:14px 16px;margin:18px 0 6px}
.banner p{margin:0}.banner p+p{margin-top:8px;color:var(--mute);font-size:.92rem}
.q{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:16px 16px 14px;margin-bottom:14px;scroll-margin-top:70px}
h3{font-size:1rem;font-weight:600;margin:0 0 12px;display:flex;gap:10px;line-height:1.45}
.num{font:500 .8rem var(--mono);color:var(--accent);background:var(--accent-soft);border-radius:6px;padding:2px 7px;height:fit-content;font-variant-numeric:tabular-nums}
.sec{display:block;font-weight:400;font-size:.78rem;color:var(--mute);margin-bottom:2px}
.opts{display:grid;gap:8px}
.opt{display:flex;gap:10px;align-items:flex-start;text-align:left;width:100%;font:inherit;color:inherit;background:transparent;border:1px solid var(--line);border-radius:8px;padding:10px 12px;cursor:pointer}
.opt b{font:500 .85rem var(--mono);color:var(--mute);min-width:1.2em;padding-top:1px}
.opt:not(:disabled):hover{border-color:var(--accent);background:var(--accent-soft)}
.opt:disabled{cursor:default}
.opt.ok{background:var(--ok-soft);border-color:var(--ok-line)}
.opt.ok b,.opt.ok .tag{color:var(--ok)}
.opt.bad{background:var(--bad-soft);border-color:var(--bad-line)}
.opt.bad b,.opt.bad .tag{color:var(--bad)}
.opt .txt{flex:1}
.tag{font:500 .75rem var(--mono);white-space:nowrap;padding-top:2px}
.fb{margin-top:10px;border-radius:8px;padding:10px 12px;background:var(--accent-soft)}
.fb p{margin:0}.fb .head{font-weight:600}.fb.good .head{color:var(--ok)}.fb.miss .head{color:var(--bad)}
.fb .why{color:var(--mute);font-size:.92rem;margin-top:4px}
.empty{text-align:center;color:var(--mute);padding:36px 12px}
.code{margin:0 0 12px;padding:10px 12px;background:var(--bg);border:1px solid var(--line);border-radius:8px;font:500 .82rem/1.5 var(--mono);overflow-x:auto;white-space:pre;tab-size:2}
textarea.ans{width:100%;font:inherit;color:var(--ink);background:var(--card);border:1px solid var(--line);border-radius:8px;padding:10px 12px;resize:vertical;min-height:84px}
textarea.ans[readonly]{background:var(--bg)}
.row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:10px}
.ask{color:var(--mute);font-size:.9rem}
.model{margin:6px 0 0;padding-left:20px}
.model li{margin:3px 0}
.mark{margin:10px 0 0;font-weight:600;font-size:.92rem}
.mark.good{color:var(--ok)}.mark.miss{color:var(--bad)}
.onote{display:block;margin-top:4px;font-size:.86rem;font-weight:400;color:var(--mute)}
.btn.small{padding:5px 10px;font-size:.8rem;color:var(--mute)}
</style></head><body><main>
<h1>Topic Quiz</h1>
<p class="sub">N Fragen aus dem Kursmaterial. Tippen Sie auf eine Option, um zu antworten. Im Überprüfungsmodus sehen Sie nur die falsch beantworteten Fragen und können diese als PDF exportieren.</p>
<div class="bar" role="toolbar" aria-label="Quiz-Steuerung">
<div class="tabs" role="group" aria-label="Modus">
<button type="button" id="tab-quiz" aria-pressed="true">Quiz</button>
<button type="button" id="tab-review" aria-pressed="false">Überprüfung</button>
<button type="button" id="tab-retry" aria-pressed="false" hidden>Wiederholung</button>
</div>
<div class="stats" id="stats" aria-live="polite"></div>
<div class="acts" id="acts"></div>
</div>
<div id="view"></div>
</main>
<script>
var DATA=__DATA__;
var L="ABCD", KEY="bps-quiz-v1", DKEY=KEY+"-d", RKEY=KEY+"-r";
var answers={}, drafts={}, retry=[], mode="quiz", dl=null;
try{var s=localStorage.getItem(KEY); if(s) answers=JSON.parse(s)||{};}catch(e){}
try{var s2=localStorage.getItem(DKEY); if(s2) drafts=JSON.parse(s2)||{};}catch(e){}
try{var s3=localStorage.getItem(RKEY); if(s3) retry=JSON.parse(s3)||[];}catch(e){}
function save(){try{localStorage.setItem(KEY,JSON.stringify(answers));}catch(e){}}
function saveD(){try{localStorage.setItem(DKEY,JSON.stringify(drafts));}catch(e){}}
function saveR(){try{localStorage.setItem(RKEY,JSON.stringify(retry));}catch(e){}}
function esc(t){return String(t).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");}
function byN(n){return DATA[n-1];}
function isDone(q){var a=answers[q.n]; return q.type==="short" ? (a==="ok"||a==="miss") : a!==undefined;}
function wrongList(){return DATA.filter(function(q){return q.type==="short" ? answers[q.n]==="miss" : (answers[q.n]!==undefined&&answers[q.n]!==q.ans);});}
function doneCount(){return DATA.filter(isDone).length;}
function shortHTML(q,ctx){
var review=(ctx!=="quiz"), a=answers[q.n], marked=(a==="ok"||a==="miss"), shown=marked||a==="rev";
var lab=(review?esc(q.section)+" - ":"")+es
…
[truncated for translation]