Animation: die Leiste laesst sich zuklappen

Ein Klick auf den Kopf klappt sie zu, dann bleiben 40 px und der Canvas hat
den Platz. Sie ist dafuer ein <details> mit dem Kopf als <summary> -- damit
ist die ganze Zeile die Trefferflaeche und die Tastaturbedienung kommt von
selbst, statt dass ein eigener Knopf eine zweite Flaeche fuer dieselbe Sache
aufmacht.

Ob sie offen ist, merkt sich der Browser je Projekt im localStorage und nicht
der Projektstand: das ist eine Vorliebe und keine Gestaltung, in
state/<projekt>.json wuerde sie bei jedem einen Diff machen.

In allen sechs Projekten nachgezogen. Im Streifenmodus faellt sie weiterhin
ganz weg, die Uebersicht zeigt alle sieben Rahmen unveraendert, und der
Bildexport laeuft wie vorher.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
dejanandClaude Opus 5 committed 2026-08-26 14:22:46 +02:00
1 parent a8f79c1224
commit 82913d78b8
7 files changed
+228 -48

No files matched your search

+6
View File
@@ -367,6 +367,12 @@ Unter dem Canvas liegt in **jedem** Projekt, im selben Fenster, ein Bereich
„Animation". Er zeigt jede Animation als eigenes Blatt in Vorschau, mit
Zeitregler, `Abspielen` und `MP4 exportieren`.
**Ein Klick auf den Kopf klappt ihn zu**, dann bleibt eine Zeile von 40 px und
der Canvas hat den Platz. Ob er offen ist, merkt sich der Browser je Projekt
(`localStorage`) und nicht der Projektstand: es ist eine Vorliebe und keine
Gestaltung, sie hat in `state/<projekt>.json` nichts verloren, wo sie bei jedem
einen Diff machen würde.
**Eine Animation ist keine Slide.** Sie steht in `ANIMS` und nicht in
`SLIDES`, liegt also nicht im Streifen, taucht in der Slide-Auswahl nicht auf
und wird vom Bildexport nicht angefasst. Das ist der ganze Punkt: im Carousel
+37 -8
View File
@@ -553,16 +553,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -3654,6 +3670,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -3669,14 +3691,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"
+37 -8
View File
@@ -472,16 +472,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -3284,6 +3300,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -3299,14 +3321,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"
+37 -8
View File
@@ -451,16 +451,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -2953,6 +2969,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -2968,14 +2990,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"
+37 -8
View File
@@ -490,16 +490,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -3788,6 +3804,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -3803,14 +3825,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"
+37 -8
View File
@@ -490,16 +490,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -4030,6 +4046,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -4045,14 +4067,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"
+37 -8
View File
@@ -494,16 +494,32 @@ if (location.search.indexOf("nur=anim") >= 0)
und Grund, ohne dass irgendwo ein Fehler auftauchte. */
#animleiste {
flex: 0 0 auto; border-top: 1px solid #24262F;
background: #14161C; padding: 13px 20px 16px;
max-height: 42vh; overflow-y: auto;
background: #14161C; padding: 0 20px;
max-height: 46vh; overflow-y: auto;
}
.animkopf { display: flex; align-items: baseline; gap: 10px; margin-bottom: 11px; }
#animleiste[open] { padding-bottom: 16px; }
/* Der Kopf ist der Schalter. Ein eigener Knopf daneben waere eine zweite
Trefferflaeche fuer dieselbe Sache -- die ganze Zeile ist gross genug,
und ein <details> bringt Tastaturbedienung von selbst mit. */
.animkopf {
display: flex; align-items: center; gap: 10px;
padding: 12px 0; cursor: pointer; user-select: none;
list-style: none;
}
.animkopf::-webkit-details-marker { display: none; }
.animkopf:hover b { color: #FFFFFF; }
.animpfeil {
flex: none; width: 13px; height: 13px; color: #6E7480;
transition: transform .16s ease;
}
#animleiste[open] .animpfeil { transform: rotate(90deg); }
.animkopf b {
font-size: 11px; font-weight: 700; letter-spacing: .09em;
text-transform: uppercase; color: #E8EAEE;
}
.animkopf span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; }
.animkopf > span { font-size: 11.5px; color: #6E7480; }
.animreihe { display: flex; gap: 14px; flex-wrap: wrap; padding-bottom: 2px; }
.animkarte {
display: flex; gap: 14px; align-items: stretch;
border: 1px solid #2E313B; border-radius: 10px;
@@ -4549,6 +4565,12 @@ if (location.search.indexOf("nur=anim") >= 0)
/* Der Bereich unter dem Canvas. Er zeigt jede Animation als eigenes Blatt
in Vorschau, nicht als Eintrag in einer Liste: was hier laeuft, ist
dasselbe Blatt, das hinterher im Video steht. */
const ANIM_OFFEN = "postgrid-anim-" + PROJECT;
const ANIM_PFEIL =
'<svg class="animpfeil" viewBox="0 0 24 24" fill="none" stroke="currentColor" ' +
'stroke-width="3" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">' +
'<path d="m9 18 6-6-6-6"/></svg>';
function animLeisteBauen() {
const liste = window.ANIM_LISTE();
let leiste = document.getElementById("animleiste");
@@ -4564,14 +4586,21 @@ if (location.search.indexOf("nur=anim") >= 0)
while (buehne.firstChild) flaeche.appendChild(buehne.firstChild);
buehne.appendChild(flaeche);
}
leiste = document.createElement("section");
leiste = document.createElement("details");
leiste.id = "animleiste";
/* Ob sie offen ist, ist eine Vorliebe und kein Projektstand: sie
gehoert in den Browser und nicht in state/<projekt>.json, das
gepusht wird und wo sie bei jedem einen Diff machen wuerde. */
leiste.open = localStorage.getItem(ANIM_OFFEN) !== "zu";
leiste.addEventListener("toggle", () => {
localStorage.setItem(ANIM_OFFEN, leiste.open ? "auf" : "zu");
});
(buehne || document.body).appendChild(leiste);
}
const kopf = document.createElement("div");
const kopf = document.createElement("summary");
kopf.className = "animkopf";
kopf.innerHTML = "<b>Animation</b><span>" +
kopf.innerHTML = ANIM_PFEIL + "<b>Animation</b><span>" +
(liste.length
? liste.length + (liste.length === 1 ? " Element" : " Elemente") +
" &middot; 1080 &times; 1350 &middot; 30 fps &middot; MP4, getrennt vom Bildexport"