extras:codikon:p5js:plakatgenerator
This is an old revision of the document!
<!– Plakat-Inhalte-Generator · p5.js · zum Einbetten ins Wiki –>
<script src=“https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.min.js”></script> <script> (function () {
// ───────── Einstellungen (hier kannst du alles anpassen) ───────── var BLUE = '#0000FF';
// t = Thema, d = erklärender Satz
var TOPICS = [
{ t: 'Warten an der Haltestelle', d: 'Die Minuten zwischen Ankunft und Abfahrt machen aus einem Durchgangsort kurzzeitig einen Aufenthaltsraum.' },
{ t: 'Die letzte Bahn', d: 'Spät am Abend wird die Abfahrtszeit zur Deadline, und die Station zu einem Ort zwischen Eile und Erleichterung.' },
{ t: 'Fahrradstraße', d: 'Eine Straße, auf der Radfahrende Vorrang haben und das Tempo der Stadt neu verhandelt wird.' },
{ t: 'Mittagspause am Bahnhof', d: 'Zwischen Gleisen und Imbiss entsteht eine kurze Pause im Alltag vieler Menschen unterwegs.' },
{ t: 'Eine Bank im Park', d: 'Ein einfaches Möbel, das zum Innehalten einlädt und Fremde nebeneinander setzt.' },
{ t: 'Umsteigen', d: 'Der Moment zwischen zwei Verkehrsmitteln, in dem Orientierung, Wege und Zeitdruck zusammentreffen.' },
{ t: 'Verspätung', d: 'Wenn der Fahrplan nicht aufgeht, wird aus Wartezeit ungeplante Zeit mit Fragen, Ärger und Zufallsbegegnungen.' },
{ t: 'Zebrastreifen', d: 'Ein Streifen Farbe auf dem Asphalt, der Fußgängern für einen Moment Vorrang gibt.' },
{ t: 'Parklet statt Parkplatz', d: 'Ein Parkplatz wird zur kleinen Sitzfläche und verwandelt Straßenraum in Aufenthaltsraum.' },
{ t: 'Pendeln', d: 'Tägliche Wege zwischen Wohnen und Arbeiten, die viel Zeit füllen und kaum Aufmerksamkeit bekommen.' },
{ t: 'Leihräder', d: 'Fahrräder, die niemandem gehören und überall in der Stadt auftauchen, wo sie gerade gebraucht werden.' },
{ t: 'Rolltreppe', d: 'Eine Fläche, die sich bewegt: Man steht und fährt zugleich, links oder rechts, schnell oder langsam.' },
{ t: 'Der Weg zur Uni', d: 'Eine Strecke, die man so oft geht, dass man sie kaum noch sieht, und auf der doch jeden Tag etwas passiert.' },
{ t: 'Schienenersatzverkehr', d: 'Wenn die Bahn ausfällt, entstehen provisorische Wege, Schilder und Warteschlangen im Stadtraum.' },
{ t: 'Ruhe im Lärm der Stadt', d: 'Orte und Momente, an denen es in der lauten Stadt für einen Augenblick leise wird.' },
{ t: 'Fußgängerzone', d: 'Ein Stück Stadt ohne Autos, in dem das Gehen, Schauen und Verweilen den Takt vorgeben.' },
{ t: 'Bushaltestelle bei Regen', d: 'Ein kleines Dach, ein Wartehäuschen und die Frage, wie viel Schutz öffentlicher Raum bieten soll.' },
{ t: 'Nachtbus', d: 'Das nächtliche Verkehrsmittel für Heimweg und Schichtende, mit leeren Sitzen und viel Stille.' },
{ t: 'Zeit zum Sitzen', d: 'Sitzgelegenheiten im öffentlichen Raum entscheiden darüber, wer bleiben darf und wie lange.' },
{ t: 'Straßenkreuzung', d: 'Ein Knotenpunkt, an dem Wege, Regeln und Geschwindigkeiten aufeinandertreffen.' },
{ t: 'Kaffee to go', d: 'Das Getränk im Gehen steht für die Idee, Pausen nebenbei zu erledigen, statt sie zu nehmen.' },
{ t: 'Fahrplan', d: 'Ein Raster aus Zahlen, das die Zeit einer ganzen Stadt in lesbare Spalten und Zeilen ordnet.' },
{ t: 'Der Platz vor dem Bahnhof', d: 'Eine Schwelle zwischen Ankommen und Weiterreisen, an der sich die Stadt zum ersten Mal zeigt.' },
{ t: 'Langsamer werden', d: 'Im Verkehr zählt meist Tempo, doch manchmal entsteht Qualität erst, wenn man bewusst bremst.' },
{ t: 'Tempo 30', d: 'Eine Zahl auf einem Schild, die verändert, wie sicher, leise und lebendig eine Straße ist.' },
{ t: 'Gleis 4', d: 'Ein Ort mit einer Nummer, an dem sich Ankünfte, Abschiede und Ansagen täglich wiederholen.' },
{ t: 'Stadtbrunnen', d: 'Ein Treffpunkt, an dem Wasser, Stein und Menschen für eine Weile zusammenkommen.' },
{ t: 'Unterführung', d: 'Ein Weg unter der Straße, der verbindet, aber auch Fragen von Licht, Sicherheit und Atmosphäre aufwirft.' },
{ t: 'Pause im öffentlichen Raum', d: 'Das Semesterthema: Wie und wo darf man in der Stadt anhalten, ohne etwas konsumieren zu müssen?' }
];
// s: true = mit Serifen, false = ohne Serifen
// Displayschriften (Titel), nur ein Schnitt bzw. fester Gewichtswert
var DISPLAY = [
{ n: 'Anton', w: 400, s: false }, { n: 'Bebas Neue', w: 400, s: false }, { n: 'Archivo Black', w: 400, s: false },
{ n: 'Oswald', w: 700, s: false }, { n: 'Syne', w: 800, s: false }, { n: 'Space Grotesk', w: 700, s: false },
{ n: 'Abril Fatface', w: 400, s: true }, { n: 'DM Serif Display', w: 400, s: true },
{ n: 'Playfair Display', w: 900, s: true }, { n: 'Bodoni Moda', w: 700, s: true }
];
// Textschriften
var BODY = [
{ n: 'Inter', w: 400, s: false }, { n: 'IBM Plex Sans', w: 400, s: false }, { n: 'Work Sans', w: 400, s: false },
{ n: 'DM Sans', w: 400, s: false }, { n: 'Libre Franklin', w: 400, s: false },
{ n: 'Source Serif 4', w: 400, s: true }, { n: 'Libre Baskerville', w: 400, s: true },
{ n: 'Lora', w: 400, s: true }, { n: 'Merriweather', w: 400, s: true }
];
// Eine Schrift für alles (t = Gewicht Titel, b = Gewicht Text)
var SINGLE = [
{ n: 'Inter', t: 800, b: 400, s: false }, { n: 'Archivo', t: 800, b: 400, s: false },
{ n: 'Work Sans', t: 800, b: 400, s: false }, { n: 'Space Grotesk', t: 700, b: 400, s: false },
{ n: 'IBM Plex Sans', t: 700, b: 400, s: false }, { n: 'DM Sans', t: 800, b: 400, s: false },
{ n: 'Libre Franklin', t: 800, b: 400, s: false },
{ n: 'Source Serif 4', t: 700, b: 400, s: true }, { n: 'Lora', t: 700, b: 400, s: true },
{ n: 'Libre Baskerville', t: 700, b: 400, s: true }, { n: 'Merriweather', t: 900, b: 400, s: true },
{ n: 'Playfair Display', t: 900, b: 400, s: true }
];
// ───────── Google Fonts laden ─────────
function gfUrl() {
var map = {};
function add(n, w) { (map[n] = map[n] || {})[w] = true; }
DISPLAY.forEach(function (f) { add(f.n, f.w); });
BODY.forEach(function (f) { add(f.n, f.w); });
SINGLE.forEach(function (f) { add(f.n, f.t); add(f.n, f.b); });
var parts = Object.keys(map).map(function (n) {
var ws = Object.keys(map[n]).map(Number).sort(function (a, b) { return a - b; });
var fam = n.replace(/ /g, '+');
if (ws.length === 1 && ws[0] === 400) return 'family=' + fam;
return 'family=' + fam + ':wght@' + ws.join(';');
});
return 'https://fonts.googleapis.com/css2?' + parts.join('&') + '&display=swap';
}
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = gfUrl();
document.head.appendChild(link);
// ───────── Sketch ─────────
var sketch = function (p) {
var S = {
topic: TOPICS[0], fontMode: 'zwei', styleMode: 'beliebig',
title: DISPLAY[0], body: BODY[0], titleSerif: false, bodySerif: false,
nText: 3, nImg: 2, ruleMode: 'zufall', rule: false
};
var host = document.getElementById('plakat-generator');
function pick(a) { return a[Math.floor(Math.random() * a.length)]; }
function cw() { return Math.max(300, Math.min(900, host.clientWidth || 600)); }
function byStyle(arr) {
if (S.styleMode === 'beliebig') return arr;
var want = S.styleMode === 'serif';
var r = arr.filter(function (f) { return f.s === want; });
return r.length ? r : arr;
}
function rollTopic() {
var t;
do { t = pick(TOPICS); } while (t === S.topic && TOPICS.length > 1);
S.topic = t;
}
function rollFont() {
if (S.fontMode === 'eine') {
var f = pick(byStyle(SINGLE));
S.title = { n: f.n, w: f.t };
S.body = { n: f.n, w: f.b };
S.titleSerif = S.bodySerif = f.s;
} else {
var a = pick(byStyle(DISPLAY)), b = pick(byStyle(BODY));
S.title = a; S.body = b;
S.titleSerif = a.s; S.bodySerif = b.s;
}
loadFonts();
}
function rollContent() {
S.nText = 2 + Math.floor(Math.random() * 4); // 2–5
S.nImg = 1 + Math.floor(Math.random() * 4); // 1–4
}
function rollRule() {
S.rule = S.ruleMode === 'an' ? true : S.ruleMode === 'aus' ? false : Math.random() < 0.5;
}
function rollAll() { rollTopic(); rollContent(); rollRule(); rollFont(); p.redraw(); }
function loadFonts() {
try {
Promise.all([
document.fonts.load(S.title.w + ' 32px "' + S.title.n + '"'),
document.fonts.load(S.body.w + ' 20px "' + S.body.n + '"')
]).then(function () { p.redraw(); });
} catch (e) { /* Fallback-Schrift */ }
}
function sty(serif) { return serif ? 'mit Serifen' : 'ohne Serifen'; }
function summary() {
return 'Thema: ' + S.topic.t + '\n' +
'Erklärung: ' + S.topic.d + '\n' +
'Schrift: ' + (S.fontMode === 'eine'
? S.title.n + ' (nur eine Schrift, ' + sty(S.titleSerif) + ')'
: S.title.n + ' (Titel, ' + sty(S.titleSerif) + ') + ' + S.body.n + ' (Text, ' + sty(S.bodySerif) + ')') + '\n' +
'Inhalte: ' + S.nText + ' Textabschnitte, ' + S.nImg + ' Bilder\n' +
'Zusatzregel: ' + (S.rule ? 'Rasterbruch (ein Element bricht bewusst aus dem Raster aus)' : 'keine');
}
// ───────── UI ─────────
function styleBtn(b, main) {
b.style('background', main ? BLUE : '#000');
b.style('color', '#fff');
b.style('border', '0');
b.style('padding', '10px 14px');
b.style('margin', '6px 6px 0 0');
b.style('font', '600 14px system-ui, sans-serif');
b.style('cursor', 'pointer');
}
function buildUI() {
var row = p.createDiv('').parent(host);
var b0 = p.createButton('Alles würfeln').parent(row); styleBtn(b0, true); b0.mousePressed(rollAll);
var b1 = p.createButton('Thema neu').parent(row); styleBtn(b1); b1.mousePressed(function () { rollTopic(); p.redraw(); });
var b2 = p.createButton('Schrift neu').parent(row); styleBtn(b2); b2.mousePressed(function () { rollFont(); p.redraw(); });
var b3 = p.createButton('Inhalte neu').parent(row); styleBtn(b3); b3.mousePressed(function () { rollContent(); p.redraw(); });
var b4 = p.createButton('Regel neu').parent(row); styleBtn(b4); b4.mousePressed(function () { rollRule(); p.redraw(); });
var row2 = p.createDiv('').parent(host);
row2.style('margin-top', '12px');
row2.style('font', '14px system-ui, sans-serif');
row2.style('line-height', '2.2');
p.createSpan('Schriften: ').parent(row2);
var sel1 = p.createSelect().parent(row2);
sel1.option('zwei Schriften (Titel + Text)', 'zwei');
sel1.option('eine Schrift insgesamt', 'eine');
sel1.selected('zwei');
sel1.changed(function () { S.fontMode = sel1.value(); rollFont(); p.redraw(); });
p.createSpan(' Schriftart: ').parent(row2);
var sel3 = p.createSelect().parent(row2);
sel3.option('beliebig', 'beliebig');
sel3.option('mit Serifen', 'serif');
sel3.option('ohne Serifen', 'sans');
sel3.selected('beliebig');
sel3.changed(function () { S.styleMode = sel3.value(); rollFont(); p.redraw(); });
p.createSpan(' Rasterbruch: ').parent(row2);
var sel2 = p.createSelect().parent(row2);
sel2.option('zufällig', 'zufall');
sel2.option('immer', 'an');
sel2.option('nie', 'aus');
sel2.selected('zufall');
sel2.changed(function () { S.ruleMode = sel2.value(); rollRule(); p.redraw(); });
var row3 = p.createDiv('').parent(host);
var b5 = p.createButton('Ergebnis als Text kopieren').parent(row3); styleBtn(b5);
b5.mousePressed(function () {
try {
navigator.clipboard.writeText(summary());
b5.html('Kopiert ✓');
setTimeout(function () { b5.html('Ergebnis als Text kopieren'); }, 1500);
} catch (e) { b5.html('Kopieren nicht möglich'); }
});
}
// ───────── Zeichnen ─────────
function wrap(ctx, str, maxW) {
var words = str.split(' '), lines = [], line = '';
words.forEach(function (w) {
var test = line ? line + ' ' + w : w;
if (ctx.measureText(test).width > maxW && line) { lines.push(line); line = w; }
else line = test;
});
if (line) lines.push(line);
return lines;
}
// dry = true: nur Höhe berechnen
function layout(dry) {
var W = p.width, ctx = p.drawingContext;
var m = Math.round(W * 0.06), iw = W - 2 * m, y = m;
ctx.textBaseline = 'alphabetic';
ctx.textAlign = 'left';
function lab(t) {
if (!dry) { ctx.font = '700 12px system-ui, sans-serif'; ctx.fillStyle = BLUE; ctx.fillText(t.toUpperCase(), m, y + 10); }
y += 28;
}
function para(str, fam, wt, size, lh, color) {
ctx.font = wt + ' ' + size + 'px "' + fam + '", sans-serif';
var lines = wrap(ctx, str, iw);
lines.forEach(function (ln, i) {
if (!dry) { ctx.fillStyle = color; ctx.fillText(ln, m, y + size * 0.85 + i * lh); }
});
y += lines.length * lh;
}
function note(str) {
ctx.font = '400 13px system-ui, sans-serif';
var lines = wrap(ctx, str, iw);
lines.forEach(function (ln, i) {
if (!dry) { ctx.fillStyle = '#555'; ctx.fillText(ln, m, y + 12 + i * 18); }
});
y += lines.length * 18 + 4;
}
function gap() {
if (!dry) { p.stroke(0); p.strokeWeight(1); p.line(m, y + 14, W - m, y + 14); }
y += 30;
}
// 1 · Thema + erklärender Satz
lab('Thema');
var ts = Math.max(30, Math.min(64, W * 0.075));
para(S.topic.t, S.title.n, S.title.w, ts, ts * 1.08, '#000');
y += 10;
para(S.topic.d, S.body.n, S.body.w, 18, 27, '#000');
gap();
// 2 · Schrift
lab(S.fontMode === 'eine' ? 'Schrift (nur eine)' : 'Schriften (zwei)');
para('Titel: ' + S.title.n, S.title.n, S.title.w, 32, 40, '#000');
y += 4;
para('Text: ' + S.body.n + ' – Die Stadt macht Pause.', S.body.n, S.body.w, 20, 28, '#000');
y += 4;
note(S.fontMode === 'eine'
? 'Nur eine Schrift (' + sty(S.titleSerif) + '): Hierarchie ausschließlich über Größe, Gewicht und Abstand herstellen.'
: 'Zwei Schriften: Displayschrift (' + sty(S.titleSerif) + ') für den Titel, Textschrift (' + sty(S.bodySerif) + ') für alle Textabschnitte.');
gap();
// 3 · Inhalte
lab('Inhalte');
ctx.font = '700 22px system-ui, sans-serif';
if (!dry) { ctx.fillStyle = '#000'; ctx.fillText(S.nText + ' Textabschnitte · ' + S.nImg + ' Bilder', m, y + 20); }
y += 36;
var n = S.nText + S.nImg, g = 10;
var s = Math.min(48, (iw - g * (n - 1)) / n), h = s * 1.25;
if (!dry) {
for (var i = 0; i < n; i++) {
var x = m + i * (s + g);
if (i < S.nText) {
p.noFill(); p.stroke(0); p.strokeWeight(2); p.rect(x, y, s, h);
p.strokeWeight(Math.max(1, s * 0.05));
for (var k = 0; k < 4; k++) {
var ly = y + h * (0.2 + k * 0.18);
p.line(x + s * 0.15, ly, x + s * (k === 3 ? 0.5 : 0.85), ly);
}
} else {
p.noStroke(); p.fill(0, 0, 255); p.rect(x, y, s, h);
p.stroke(255); p.strokeWeight(2);
p.line(x, y, x + s, y + h); p.line(x + s, y, x, y + h);
}
}
}
y += h + 4;
gap();
// 4 · Zusatzregel
lab('Zusatzregel');
if (S.rule) {
ctx.font = '700 22px system-ui, sans-serif';
if (!dry) { ctx.fillStyle = BLUE; ctx.fillText('Rasterbruch', m, y + 20); }
y += 34;
note('Genau ein Element bricht bewusst aus dem Raster aus (Größe, Drehung oder Position). Der Bruch braucht eine Begründung.');
} else {
ctx.font = '700 22px system-ui, sans-serif';
if (!dry) { ctx.fillStyle = '#000'; ctx.fillText('Keine Zusatzregel', m, y + 20); }
y += 34;
note('Dieses Mal bleibt alles konsequent im Raster.');
}
return y + m;
}
p.setup = function () {
var c = p.createCanvas(cw(), 600);
c.parent(host);
p.noLoop();
buildUI();
rollTopic(); rollContent(); rollRule(); rollFont();
};
p.draw = function () {
var need = Math.ceil(layout(true));
if (Math.abs(need - p.height) > 2) {
p.resizeCanvas(p.width, need);
setTimeout(function () { p.redraw(); }, 0);
return;
}
p.background(255);
p.noFill(); p.stroke(0); p.strokeWeight(3);
p.rect(1.5, 1.5, p.width - 3, p.height - 3);
layout(false);
};
p.windowResized = function () {
p.resizeCanvas(cw(), p.height);
};
};
new p5(sketch, 'plakat-generator');
})(); </script>
/var/www/vhosts/ct-lab.info/wiki.ct-lab.info/data/attic/extras/codikon/p5js/plakatgenerator.1792694856.txt.gz · Last modified: by Leonie Winkelmann