Creative Technologies Lab | dokuWiki

Repository of academic adventures, experimental technology, accidental brilliance, and collaborative nerdery.

User Tools

Site Tools


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('&nbsp;&nbsp; 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('&nbsp;&nbsp; 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>

This website uses cookies. By using our website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website. Privacy Policy
/var/www/vhosts/ct-lab.info/wiki.ct-lab.info/data/attic/extras/codikon/p5js/plakatgenerator.1792694856.txt.gz · Last modified: by Leonie Winkelmann