diff --git a/animation/post9-v4-animBuerokratie-1x1.mp4 b/animation/post9-v4-animBuerokratie-1x1.mp4
new file mode 100644
index 0000000..8dc6621
Binary files /dev/null and b/animation/post9-v4-animBuerokratie-1x1.mp4 differ
diff --git a/animation/post9-v4-animKi-1x1.mp4 b/animation/post9-v4-animKi-1x1.mp4
new file mode 100644
index 0000000..8afda13
Binary files /dev/null and b/animation/post9-v4-animKi-1x1.mp4 differ
diff --git a/animation/post9-v5-animBuerokratie-1x1.mp4 b/animation/post9-v5-animBuerokratie-1x1.mp4
new file mode 100644
index 0000000..200bfd9
Binary files /dev/null and b/animation/post9-v5-animBuerokratie-1x1.mp4 differ
diff --git a/animation/post9-v5-animKi-1x1.mp4 b/animation/post9-v5-animKi-1x1.mp4
new file mode 100644
index 0000000..66a4acc
Binary files /dev/null and b/animation/post9-v5-animKi-1x1.mp4 differ
diff --git a/post9-v4.html b/post9-v4.html
index ef4be52..4db8e25 100644
--- a/post9-v4.html
+++ b/post9-v4.html
@@ -1481,7 +1481,18 @@ if (location.search.indexOf("nur=anim") >= 0)
die Titelslide getragen haette. */
/* Variante 2 hat kein Bewegtbild: alle fuenf Elemente sind Standbilder.
Ein reines Bild-Carousel darf als Anzeige auch 4:5 bleiben. */
- const ANIMS = [];
+ /* Variante 4: Slide 2 und 3 laufen als Video (Dejan, 02.11.2026). Im
+ Carousel stehen sie an Stelle 2 und 3, die Standbilder im Streifen
+ zeigen ihren Endstand. Mit Video bleibt die Anzeige im Instagram-Feed
+ 1:1 und laeuft nicht in Reels (rules.md 5). */
+ const ANIMS = [
+ Object.assign({ key: "animBuerokratie", type: "feature", dauer: 6, eyebrow: "Bürokratie",
+ layouts: [{ id: "standard", label: "Standard" }], vis: "v4buerokratieAnim" },
+ { head: "", body: "", visW: 1080, visLeft: 0, visBottom: 0, quadrat: { visW: 1080, visLeft: 0, visBottom: 0 } }),
+ Object.assign({ key: "animKi", type: "feature", dauer: 6, eyebrow: "Künstliche Intelligenz",
+ layouts: [{ id: "standard", label: "Standard" }], vis: "v4kiAnim" },
+ { head: "", body: "", visW: 1080, visLeft: 0, visBottom: 0, quadrat: { visW: 1080, visLeft: 0, visBottom: 0 } }),
+ ];
/* Vorlage für eine selbst angelegte Slide. Sie startet bewusst mit Text
@@ -4903,6 +4914,7 @@ if (location.search.indexOf("nur=anim") >= 0)
const h = r * Math.sqrt(3) / 2;
const pkt = [[cx + r, cy], [cx + r / 2, cy + h], [cx - r / 2, cy + h], [cx - r, cy], [cx - r / 2, cy - h], [cx + r / 2, cy - h]];
return '";
}
@@ -5214,21 +5226,58 @@ if (location.search.indexOf("nur=anim") >= 0)
gezaehlt wird spaltenweise von links. Dejan, 02.11.2026: weniger Zahlen,
mehr Grafik, aber nichts erfunden. Die Grafik zeigt nur den Prozentwert
der Quelle, auf ganze Waben gerundet. */
- function v4Hundert(y0, art) {
+ function v4Hundert(y0, art, zeit) {
const r = 28, sx = 1.5 * r, w = r * Math.sqrt(3);
const x0 = V2_RAND + r + (1080 - 2 * V2_RAND - (19 * sx + 2 * r)) / 2;
- let g = "";
+ let g = "", oben = "";
for (let i = 0; i < 100; i++) {
const sp = Math.floor(i / 5), z = i % 5;
const cx = x0 + sp * sx, cy = y0 + w / 2 + z * w + (sp % 2 ? w / 2 : 0);
const a = art(i);
- g += a === "voll" ? v2Wabe(cx, cy, r - 4, V4.gelb)
- : a === "rand" ? v2Wabe(cx + 0, cy, r - 6, "none", { stroke: V4.gelb, sw: 3 })
- : v2Wabe(cx, cy, r - 4, V4.spurWabe);
+ /* p: wie weit diese Wabe schon da ist, 0 bis 1. Ohne zeit (Standbild)
+ ist alles fertig. Die graue Wabe liegt immer darunter, die gelbe
+ waechst darueber auf, mit leichtem Ueberschwingen (rueck). Unter
+ einer umrandeten Wabe verblasst das Grau, sobald sie steht. */
+ const p = a && zeit ? zeit(i) : 1;
+ g += v2Wabe(cx, cy, r - 4, V4.spurWabe, a === "rand" ? { deck: 1 - p } : null);
+ if (!a || p <= 0) continue;
+ const sk = rueck(p);
+ oben += a === "voll" ? v2Wabe(cx, cy, (r - 4) * sk, V4.gelb)
+ : v2Wabe(cx, cy, (r - 6) * sk, "none", { stroke: V4.gelb, sw: 3 });
}
- return g;
+ return g + oben;
}
+ /* Im Streifen (Uebersicht, Vergleichsseite) laufen Slide 2 und 3 als
+ Animation mit, damit man sieht, was ins Video kommt. Der Editor und der
+ Bildexport bleiben beim Endstand. 30 Bilder je Sekunde reichen. */
+ function v4StreifenAnimieren() {
+ if (!NUR_STREIFEN) return;
+ const start = performance.now();
+ let zuletzt = 0;
+ const schritt = jetzt => {
+ if (jetzt - zuletzt > 33) {
+ zuletzt = jetzt;
+ const t = ((jetzt - start) / 1000 % V4_DAUER) / V4_DAUER;
+ document.querySelectorAll(".vis.vis-v4buerokratie").forEach(v => { v.innerHTML = v4Buerokratie(t); });
+ document.querySelectorAll(".vis.vis-v4ki").forEach(v => { v.innerHTML = v4Ki(t); });
+ }
+ requestAnimationFrame(schritt);
+ };
+ requestAnimationFrame(schritt);
+ }
+
+ /* Der Zeitverlauf der animierten Karten, t von 0 bis 1 ueber V4_DAUER
+ Sekunden. Die Waben kommen nacheinander (start, abstand, je dauer), am
+ Ende ziehen sich alle zusammen zurueck, damit die Schleife auf
+ Instagram weich neu ansetzt statt zu springen. */
+ const V4_DAUER = 6;
+ const v4Welle = (t, k, start, abstand, dauer) => {
+ const rein = stufe(t, start + k * abstand, start + k * abstand + dauer);
+ const raus = 1 - daempfen(stufe(t, 0.92, 1));
+ return rein * raus;
+ };
+
/* 1 · Titel. Noah freigestellt vor der grossen gelben Wabe, wie in
Variante 2 auf der Zitat-Karte: Er traegt Schwarz und braucht das Gelb
dahinter. Die Karte teasert das Webinar, die Zahlen kommen danach. */
@@ -5239,7 +5288,9 @@ if (location.search.indexOf("nur=anim") >= 0)
g += v4Struktur();
g += v2Wabe(800, H - 170, 330, V4.gelb);
const pb = 1000, ph = pb * 1049 / 1600;
- g += v2Bild(800 - pb * 0.475, H - ph, pb, ph, "./assets/team/noah-person.webp", { passen: "meet" });
+ /* Gespiegelt an x 800 (Dejan, 02.11.2026): Noah schaut so zum Text. */
+ g += '' +
+ v2Bild(800 - pb * 0.475, H - ph, pb, ph, "./assets/team/noah-person.webp", { passen: "meet" }) + "";
g += v2Bild(V2_RAND, 86, 42 * 3.8, 42, "./assets/brand/logo-white.svg", { passen: "meet" });
g += v2Chamfer(V2_RAND, 186, 236, 50, 10, V2.gelbHell);
g += uiText(V2_RAND + 118, 219, "LIVE-WEBINAR", 20, 800, V2.gelbText, { anker: "middle", sperr: "0.14em" });
@@ -5255,11 +5306,13 @@ if (location.search.indexOf("nur=anim") >= 0)
/* 2 · Buerokratie. KfW: im mittelstaendischen Bau 8,1 % der Arbeitszeit.
Als Bild: 100 Waben, 8 gelb. */
- function v4Buerokratie() {
+ function v4Buerokratie(t) {
v4Ton();
let g = v4Kopf("Zeitfresser Bürokratie", "Im Bau: 8 von 100 Arbeitsstunden", "gehen für Bürokratie drauf.");
/* Grafik und Legende stehen mittig zwischen Kopf (bis 306) und Fuss (ab 952). */
- g += v4Hundert(456, i => i >= 92 ? "voll" : "");
+ /* Animiert: die 8 gelben ab 0,6 s nacheinander, je 0,5 s. */
+ g += v4Hundert(456, i => i >= 92 ? "voll" : "",
+ t == null ? null : i => v4Welle(t, i - 92, 0.10, 0.035, 0.08));
g += v2Wabe(V2_RAND + 13, 777, 13, V4.gelb);
g += uiText(V2_RAND + 40, 785, "Jede Wabe ist eine Arbeitsstunde. Gelb ist Bürokratie.", 24, 600, V4.text2);
g += v4Fuss(["Quelle: KfW-Mittelstandspanel, KfW Research Nr. 495, April 2025.",
@@ -5269,10 +5322,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* 3 · KI. Bitkom: 4 % nutzen KI, 9 % planen es. Dasselbe Bild, jede Wabe
ein Betrieb. */
- function v4Ki() {
+ function v4Ki(t) {
v4Ton();
let g = v4Kopf("Künstliche Intelligenz", "KI ist im Handwerk kaum angekommen.", "4 von 100 Betrieben nutzen sie.");
- g += v4Hundert(456, i => i < 4 ? "voll" : i < 13 ? "rand" : "");
+ /* Animiert: erst die 4 vollen, dann die 9 umrandeten. */
+ g += v4Hundert(456, i => i < 4 ? "voll" : i < 13 ? "rand" : "",
+ t == null ? null : i => i < 4 ? v4Welle(t, i, 0.10, 0.05, 0.08) : v4Welle(t, i - 4, 0.40, 0.03, 0.07));
g += v2Wabe(V2_RAND + 13, 777, 13, V4.gelb);
g += uiText(V2_RAND + 40, 785, "nutzen KI", 24, 600, V4.text2);
g += v2Wabe(V2_RAND + 213, 777, 11, "none", { stroke: V4.gelb, sw: 3 });
@@ -5375,8 +5430,10 @@ if (location.search.indexOf("nur=anim") >= 0)
anmeldung: () => visAnmeldung(),
animWebinar: (j, t) => animWebinar(j, t),
v4titel: () => v4Titel(),
- v4buerokratie: () => v4Buerokratie(),
- v4ki: () => v4Ki(),
+ v4buerokratie: () => v4Buerokratie(null),
+ v4buerokratieAnim: (j, t) => v4Buerokratie(t),
+ v4ki: () => v4Ki(null),
+ v4kiAnim: (j, t) => v4Ki(t),
v4zeit: () => v4Zeit(),
v4webinar: () => v4Webinar(),
v2betrieb: () => v2Betrieb(),
@@ -8573,6 +8630,7 @@ if (location.search.indexOf("nur=anim") >= 0)
weiter oben hat genau das ausgeloest -- "Cannot set properties of
null" beim Freischalten der Export-Knoepfe. */
animNurModus();
+ v4StreifenAnimieren();
} catch (err) {
console.error(err);
setStatus("Fehler beim Laden: " + err.message, "err");
diff --git a/post9-v5.html b/post9-v5.html
index ca53234..022164e 100644
--- a/post9-v5.html
+++ b/post9-v5.html
@@ -1481,7 +1481,18 @@ if (location.search.indexOf("nur=anim") >= 0)
die Titelslide getragen haette. */
/* Variante 2 hat kein Bewegtbild: alle fuenf Elemente sind Standbilder.
Ein reines Bild-Carousel darf als Anzeige auch 4:5 bleiben. */
- const ANIMS = [];
+ /* Variante 4: Slide 2 und 3 laufen als Video (Dejan, 02.11.2026). Im
+ Carousel stehen sie an Stelle 2 und 3, die Standbilder im Streifen
+ zeigen ihren Endstand. Mit Video bleibt die Anzeige im Instagram-Feed
+ 1:1 und laeuft nicht in Reels (rules.md 5). */
+ const ANIMS = [
+ Object.assign({ key: "animBuerokratie", type: "feature", dauer: 6, eyebrow: "Bürokratie",
+ layouts: [{ id: "standard", label: "Standard" }], vis: "v4buerokratieAnim" },
+ { head: "", body: "", visW: 1080, visLeft: 0, visBottom: 0, quadrat: { visW: 1080, visLeft: 0, visBottom: 0 } }),
+ Object.assign({ key: "animKi", type: "feature", dauer: 6, eyebrow: "Künstliche Intelligenz",
+ layouts: [{ id: "standard", label: "Standard" }], vis: "v4kiAnim" },
+ { head: "", body: "", visW: 1080, visLeft: 0, visBottom: 0, quadrat: { visW: 1080, visLeft: 0, visBottom: 0 } }),
+ ];
/* Vorlage für eine selbst angelegte Slide. Sie startet bewusst mit Text
@@ -4903,6 +4914,7 @@ if (location.search.indexOf("nur=anim") >= 0)
const h = r * Math.sqrt(3) / 2;
const pkt = [[cx + r, cy], [cx + r / 2, cy + h], [cx - r / 2, cy + h], [cx - r, cy], [cx - r / 2, cy - h], [cx + r / 2, cy - h]];
return '";
}
@@ -5214,21 +5226,58 @@ if (location.search.indexOf("nur=anim") >= 0)
gezaehlt wird spaltenweise von links. Dejan, 02.11.2026: weniger Zahlen,
mehr Grafik, aber nichts erfunden. Die Grafik zeigt nur den Prozentwert
der Quelle, auf ganze Waben gerundet. */
- function v4Hundert(y0, art) {
+ function v4Hundert(y0, art, zeit) {
const r = 28, sx = 1.5 * r, w = r * Math.sqrt(3);
const x0 = V2_RAND + r + (1080 - 2 * V2_RAND - (19 * sx + 2 * r)) / 2;
- let g = "";
+ let g = "", oben = "";
for (let i = 0; i < 100; i++) {
const sp = Math.floor(i / 5), z = i % 5;
const cx = x0 + sp * sx, cy = y0 + w / 2 + z * w + (sp % 2 ? w / 2 : 0);
const a = art(i);
- g += a === "voll" ? v2Wabe(cx, cy, r - 4, V4.gelb)
- : a === "rand" ? v2Wabe(cx + 0, cy, r - 6, "none", { stroke: V4.gelb, sw: 3 })
- : v2Wabe(cx, cy, r - 4, V4.spurWabe);
+ /* p: wie weit diese Wabe schon da ist, 0 bis 1. Ohne zeit (Standbild)
+ ist alles fertig. Die graue Wabe liegt immer darunter, die gelbe
+ waechst darueber auf, mit leichtem Ueberschwingen (rueck). Unter
+ einer umrandeten Wabe verblasst das Grau, sobald sie steht. */
+ const p = a && zeit ? zeit(i) : 1;
+ g += v2Wabe(cx, cy, r - 4, V4.spurWabe, a === "rand" ? { deck: 1 - p } : null);
+ if (!a || p <= 0) continue;
+ const sk = rueck(p);
+ oben += a === "voll" ? v2Wabe(cx, cy, (r - 4) * sk, V4.gelb)
+ : v2Wabe(cx, cy, (r - 6) * sk, "none", { stroke: V4.gelb, sw: 3 });
}
- return g;
+ return g + oben;
}
+ /* Im Streifen (Uebersicht, Vergleichsseite) laufen Slide 2 und 3 als
+ Animation mit, damit man sieht, was ins Video kommt. Der Editor und der
+ Bildexport bleiben beim Endstand. 30 Bilder je Sekunde reichen. */
+ function v4StreifenAnimieren() {
+ if (!NUR_STREIFEN) return;
+ const start = performance.now();
+ let zuletzt = 0;
+ const schritt = jetzt => {
+ if (jetzt - zuletzt > 33) {
+ zuletzt = jetzt;
+ const t = ((jetzt - start) / 1000 % V4_DAUER) / V4_DAUER;
+ document.querySelectorAll(".vis.vis-v4buerokratie").forEach(v => { v.innerHTML = v4Buerokratie(t); });
+ document.querySelectorAll(".vis.vis-v4ki").forEach(v => { v.innerHTML = v4Ki(t); });
+ }
+ requestAnimationFrame(schritt);
+ };
+ requestAnimationFrame(schritt);
+ }
+
+ /* Der Zeitverlauf der animierten Karten, t von 0 bis 1 ueber V4_DAUER
+ Sekunden. Die Waben kommen nacheinander (start, abstand, je dauer), am
+ Ende ziehen sich alle zusammen zurueck, damit die Schleife auf
+ Instagram weich neu ansetzt statt zu springen. */
+ const V4_DAUER = 6;
+ const v4Welle = (t, k, start, abstand, dauer) => {
+ const rein = stufe(t, start + k * abstand, start + k * abstand + dauer);
+ const raus = 1 - daempfen(stufe(t, 0.92, 1));
+ return rein * raus;
+ };
+
/* 1 · Titel. Noah freigestellt vor der grossen gelben Wabe, wie in
Variante 2 auf der Zitat-Karte: Er traegt Schwarz und braucht das Gelb
dahinter. Die Karte teasert das Webinar, die Zahlen kommen danach. */
@@ -5239,7 +5288,9 @@ if (location.search.indexOf("nur=anim") >= 0)
g += v4Struktur();
g += v2Wabe(800, H - 170, 330, V4.gelb);
const pb = 1000, ph = pb * 1049 / 1600;
- g += v2Bild(800 - pb * 0.475, H - ph, pb, ph, "./assets/team/noah-person.webp", { passen: "meet" });
+ /* Gespiegelt an x 800 (Dejan, 02.11.2026): Noah schaut so zum Text. */
+ g += '' +
+ v2Bild(800 - pb * 0.475, H - ph, pb, ph, "./assets/team/noah-person.webp", { passen: "meet" }) + "";
g += v2Bild(V2_RAND, 86, 42 * 3.8, 42, "./assets/brand/logo-white.svg", { passen: "meet" });
g += v2Chamfer(V2_RAND, 186, 236, 50, 10, V2.gelbHell);
g += uiText(V2_RAND + 118, 219, "LIVE-WEBINAR", 20, 800, V2.gelbText, { anker: "middle", sperr: "0.14em" });
@@ -5255,11 +5306,13 @@ if (location.search.indexOf("nur=anim") >= 0)
/* 2 · Buerokratie. KfW: im mittelstaendischen Bau 8,1 % der Arbeitszeit.
Als Bild: 100 Waben, 8 gelb. */
- function v4Buerokratie() {
+ function v4Buerokratie(t) {
v4Ton();
let g = v4Kopf("Zeitfresser Bürokratie", "Im Bau: 8 von 100 Arbeitsstunden", "gehen für Bürokratie drauf.");
/* Grafik und Legende stehen mittig zwischen Kopf (bis 306) und Fuss (ab 952). */
- g += v4Hundert(456, i => i >= 92 ? "voll" : "");
+ /* Animiert: die 8 gelben ab 0,6 s nacheinander, je 0,5 s. */
+ g += v4Hundert(456, i => i >= 92 ? "voll" : "",
+ t == null ? null : i => v4Welle(t, i - 92, 0.10, 0.035, 0.08));
g += v2Wabe(V2_RAND + 13, 777, 13, V4.gelb);
g += uiText(V2_RAND + 40, 785, "Jede Wabe ist eine Arbeitsstunde. Gelb ist Bürokratie.", 24, 600, V4.text2);
g += v4Fuss(["Quelle: KfW-Mittelstandspanel, KfW Research Nr. 495, April 2025.",
@@ -5269,10 +5322,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* 3 · KI. Bitkom: 4 % nutzen KI, 9 % planen es. Dasselbe Bild, jede Wabe
ein Betrieb. */
- function v4Ki() {
+ function v4Ki(t) {
v4Ton();
let g = v4Kopf("Künstliche Intelligenz", "KI ist im Handwerk kaum angekommen.", "4 von 100 Betrieben nutzen sie.");
- g += v4Hundert(456, i => i < 4 ? "voll" : i < 13 ? "rand" : "");
+ /* Animiert: erst die 4 vollen, dann die 9 umrandeten. */
+ g += v4Hundert(456, i => i < 4 ? "voll" : i < 13 ? "rand" : "",
+ t == null ? null : i => i < 4 ? v4Welle(t, i, 0.10, 0.05, 0.08) : v4Welle(t, i - 4, 0.40, 0.03, 0.07));
g += v2Wabe(V2_RAND + 13, 777, 13, V4.gelb);
g += uiText(V2_RAND + 40, 785, "nutzen KI", 24, 600, V4.text2);
g += v2Wabe(V2_RAND + 213, 777, 11, "none", { stroke: V4.gelb, sw: 3 });
@@ -5375,8 +5430,10 @@ if (location.search.indexOf("nur=anim") >= 0)
anmeldung: () => visAnmeldung(),
animWebinar: (j, t) => animWebinar(j, t),
v4titel: () => v4Titel(),
- v4buerokratie: () => v4Buerokratie(),
- v4ki: () => v4Ki(),
+ v4buerokratie: () => v4Buerokratie(null),
+ v4buerokratieAnim: (j, t) => v4Buerokratie(t),
+ v4ki: () => v4Ki(null),
+ v4kiAnim: (j, t) => v4Ki(t),
v4zeit: () => v4Zeit(),
v4webinar: () => v4Webinar(),
v2betrieb: () => v2Betrieb(),
@@ -8576,6 +8633,7 @@ if (location.search.indexOf("nur=anim") >= 0)
weiter oben hat genau das ausgeloest -- "Cannot set properties of
null" beim Freischalten der Export-Knoepfe. */
animNurModus();
+ v4StreifenAnimieren();
} catch (err) {
console.error(err);
setStatus("Fehler beim Laden: " + err.message, "err");