Animation: eigener Bereich unter dem Canvas, getrennt vom Bildexport
Jedes Projekt hat jetzt unter dem Canvas einen Bereich "Animation", im selben Fenster. Er zeigt jede Animation als echtes Blatt in Vorschau, mit Zeitregler, Abspielen und "MP4 exportieren". 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. Im Carousel ist sie ein eigenes Element, und ob sie mitkommt, entscheidet sich beim Posten. Ein erster Anlauf machte sie zur sechsten Slide; damit war sie in der Zaehlung und im ZIP mit drin. Der Export laeuft ueber den neuen Endpunkt POST /anim in serve.py. Er startet animation.mjs in einem eigenen Faden, die Seite fragt den Stand ueber GET /anim?id= ab und zeigt Fortschritt und Pfad. Ein Browser kann kein MP4 schreiben, und eine offene Anfrage ueber zwei Minuten geht nicht -- zumal sich animation.mjs waehrenddessen selbst Seiten von diesem Server holt. Aufgenommen wird im neuen Modus ?nur=anim&k=<key>: dort zeigt die Seite allein das Blatt der Animation, in 1080 x 1350 an 0,0. Damit entfaellt jede Ausschnittsrechnung und mit ihr die Falle, dass ein zu schmales Fenster ein leeres Bild liefert. Als erstes Beispiel post6-animChat, fuenf Sekunden: die Antwort wird Zeichen fuer Zeichen getippt, abgeschickt, waechst als Blase in den Verlauf, die Aufgabenkarte klappt auf, die Systemzeile bestaetigt, alles blendet zurueck auf den Anfang. Getippt wird VERLAUF[3].text, also die Nachricht, die im Werkzeug an dieser Stelle ohnehin folgt. H.264 High, yuv420p, 1080 x 1350, 30 fps, stumme AAC-Spur, +faststart: das nimmt Instagram fuer ein animiertes Element im Carousel an. GIF nicht, das landet als Standbild. Ein Video im Carousel wird auch kein Reel, das passiert nur bei einem einzeln geposteten Video. Nebenbei: - post4, post5 und post6 trugen im Panel noch den Kopf ihrer Vorlage. - video/README.md und video/bauen.mjs behaupteten, ffmpeg sei hier nicht installiert. Stimmt seit 9.0.1 nicht mehr; die Bildsequenz bleibt dort trotzdem, mit Begruendung. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
ce87a7fb57
commit
c7c05a85cc
14 files changed
+3295
-247
No files matched your search
@@ -221,10 +221,10 @@ Baustellenfotos.
|
||||
| Slide | Was sie leistet |
|
||||
|---|---|
|
||||
| 1 | Kanalliste und Verlauf nebeneinander, mit Filterzeile und Eingabefeld |
|
||||
| 2 | die Chatliste groß: Projektkanäle, Direktnachrichten, Gruppe |
|
||||
| 2 | links das Durcheinander als Zeichnung, rechts die Kanalliste |
|
||||
| 3 | Fotos, die Aufgabe daraus, die Bestätigung im Projekt |
|
||||
| 4 | das Menü hinter dem Plus im Eingabefeld |
|
||||
| 5 | das Handy-Mockup der Website, verwischt, mit Absperrband |
|
||||
| 5 | zwei Ausschnitte der Oberfläche, versetzt übereinander, mit Absperrband |
|
||||
|
||||
**Slide 3 ist der Kern**, und sie ist keine Konstruktion: im Werkzeug folgen
|
||||
die drei Nachrichten genau so aufeinander. Tobias schickt die Baustellenfotos,
|
||||
@@ -232,13 +232,35 @@ darauf eine Nachricht mit angehängter Aufgabe, darauf die Systemzeile
|
||||
„Aufgabe „Materialliste prüfen" im Projekt erstellt". Die letzte Zeile macht
|
||||
den Unterschied: die Aufgabe liegt danach im Projekt, nicht nur im Verlauf.
|
||||
|
||||
**Slide 5 kommt von der Website, nicht aus dem Pitch-Paket.** Die App gibt es
|
||||
noch nicht, und `ChatDemoSection.tsx` hat den Zustand bereits: ein Handy-Mockup
|
||||
mit `blur(3px)` und darüber ein **Absperrband** aus dem Bau, -13° gedreht, in
|
||||
`#F1B729` mit Kanten in `#171106`, darauf Schutzhelm und „BALD VERFÜGBAR".
|
||||
Auch Inhalt, Blasenfarben, Überschrift und Fließtext sind die der Website. Ein
|
||||
Zwischenstand hatte hier einen selbst erfundenen Aufkleber; das war eine eigene
|
||||
Bildsprache neben einer vorhandenen.
|
||||
**Slide 5 zeigt zwei Ausschnitte statt eines Geräts.** Die Machart ist die,
|
||||
die Signal für solche Slides benutzt: zwei Teile der Oberfläche,
|
||||
versetzt übereinander, jeder mit eigenem Schatten. Ein Zwischenstand hatte hier
|
||||
ein nachgebautes Handy samt Insel und Tasten; das kostet viel Platz für etwas,
|
||||
das nichts über das Produkt sagt, und der Rahmen war frei erfunden.
|
||||
|
||||
**Slide 2 stellt gegenüber statt zu zeigen:** links das Durcheinander als
|
||||
Zeichnung, rechts die Oberfläche als Ausschnitt. Die linke Hälfte gibt es in
|
||||
diesem Repo schon, in `post2.html` auf Slide 2 (`visProzesse`) — dort im
|
||||
Zeichenblock-Stil, hier glatt. Die Plättchen sind Redaktionstext und keine
|
||||
Produktstrings; sie beschreiben die Wirklichkeit im Betrieb.
|
||||
|
||||
**Die Leitung läuft über den Wisch hinweg:** sie beginnt links außerhalb der
|
||||
Slide, und mit `visLeft: -102` landet dieses Stück auf Slide 1. Das ist der
|
||||
Überstand, vor dem `rules.md` §5 sonst warnt — `.page` hat kein `overflow` —
|
||||
hier aber gewollt. `pruef.mjs` liest einen negativen `--vis-left` als Ansage
|
||||
und meldet ihn nicht mehr als Fehler.
|
||||
|
||||
Beide Ausschnitte auf Slide 5 sind leicht verwischt: erkennbar, aber nicht zu lesen.
|
||||
Scharf bleibt allein das Band. Von Slack kommt ein zweites Mittel, das auf
|
||||
Slide 3 sitzt: **ein dicker gelber Rahmen, der seitlich aus der Blase
|
||||
ausbricht** und auf die Anhangkarte der Aufgabe zeigt, weil die den Satz der
|
||||
Slide trägt.
|
||||
|
||||
Dass die App noch nicht da ist, sagt das **Absperrband** von der Website:
|
||||
`ChatDemoSection.tsx` hat es unter der Fahne `comingSoon`, -13° gedreht, in
|
||||
`#F1B729` mit Kanten in `#171106`, darauf Schutzhelm und „BALD VERFÜGBAR". Auch
|
||||
Überschrift und Fließtext sind die der Website; der Inhalt der Ausschnitte
|
||||
kommt aus dem Pitch-Paket wie auf allen anderen Slides.
|
||||
|
||||
**Die Tiefe kommt aus dem Stapel und gestaffelten Schatten, nicht aus
|
||||
Flächen.** Ein Zwischenstand legte graue Flächen hinter die Elemente; das nimmt
|
||||
@@ -339,6 +361,89 @@ sonst sieht ihn niemand sonst. Gibt es die Datei noch nicht, wird der Stand
|
||||
aus dem Browser einmalig hineingeschrieben.
|
||||
|
||||
|
||||
## Animation
|
||||
|
||||
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`.
|
||||
|
||||
**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
|
||||
ist sie ein eigenes Element, und ob sie mitkommt, entscheidest du beim Posten.
|
||||
|
||||
```js
|
||||
const ANIMS = [
|
||||
{ key: "animChat", type: "feature", dauer: 5,
|
||||
eyebrow: "Bewegtbild",
|
||||
head: 'Getippt,<br><span class="a">und schon im Projekt.</span>',
|
||||
body: "Eine Nachricht, ein Klick, und die Aufgabe hängt am richtigen Projekt.",
|
||||
vis: "animChat", visW: 700, visLeft: 190, visBottom: 120 },
|
||||
];
|
||||
```
|
||||
|
||||
Dieselben Felder wie bei einer Slide, dazu `dauer` in Sekunden. Die
|
||||
Zeichenfunktion aus `VIS` bekommt einen zweiten Wert `t` zwischen 0 und 1 und
|
||||
zeichnet daraus den Stand zu diesem Zeitpunkt. Blatt, Überschrift,
|
||||
Punktgrund und Schutzzone sind dieselben wie überall.
|
||||
|
||||
### Exportieren
|
||||
|
||||
**`MP4 exportieren`** im Bereich unter dem Canvas. Der Browser kann kein MP4
|
||||
schreiben, also stößt die Seite den Bau auf dem Server an (`POST /anim`) und
|
||||
fragt den Stand ab; die Zeile unter den Knöpfen zeigt den Fortschritt und am
|
||||
Ende den Pfad. Getrennt vom Bildexport, in beide Richtungen: „Alle Slides als
|
||||
ZIP" enthält kein Video, und dieser Knopf rendert kein Bild.
|
||||
|
||||
Auf der Kommandozeile geht dasselbe:
|
||||
|
||||
```sh
|
||||
./serve.sh # muss laufen
|
||||
node animation.mjs post6.html # alle Animationen des Projekts
|
||||
node animation.mjs post6.html animChat # nur diese
|
||||
```
|
||||
|
||||
Heraus kommt `animation/post6-animChat.mp4`. Angesprochen wird die Animation
|
||||
über ihren Schlüssel, nicht über eine Nummer: sie hat keine Position im
|
||||
Streifen, die sich verschieben könnte.
|
||||
|
||||
Für die Aufnahme lädt das Skript die Seite als `?nur=anim&k=<key>`. In diesem
|
||||
Modus zeigt sie allein das Blatt der Animation, in natürlicher Größe an 0,0 —
|
||||
damit entfällt jede Ausschnittsrechnung.
|
||||
|
||||
### Was Instagram bei so einem Beitrag tatsächlich annimmt
|
||||
|
||||
Kurz: **ein MP4, kein GIF.**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Format | MP4, H.264 High, `yuv420p`, `+faststart` |
|
||||
| Maße | 1080 × 1350 (4:5), wie die Standbilder |
|
||||
| Bildrate | 30 fps, Schlüsselbild jede Sekunde |
|
||||
| Datenrate | rund 12 Mbit/s |
|
||||
| Länge | mindestens 3 s, höchstens 60 s je Carousel-Element |
|
||||
| Ton | eine stumme AAC-Spur |
|
||||
|
||||
Vier Dinge, die den Aufbau bestimmen:
|
||||
|
||||
- **GIF geht nicht.** Instagram nimmt keine GIF-Uploads an; die Datei landet
|
||||
als Standbild. Was in der App wie ein animierter Beitrag aussieht, ist ein
|
||||
kurzes Video.
|
||||
- **Ein Video im Carousel wird kein Reel.** Seit 2022 wandert nur ein
|
||||
*einzeln* geposteter Video-Beitrag automatisch in die Reels. Liegt das Video
|
||||
in einem Carousel, bleibt der Beitrag ein Beitrag.
|
||||
- **Der erste Beitrag im Carousel bestimmt den Ausschnitt für alle.** Ein
|
||||
Element in einem anderen Seitenverhältnis wird beschnitten, nicht
|
||||
eingepasst. Deshalb rendert die Animation in genau denselben 1080 × 1350 wie
|
||||
jedes Standbild.
|
||||
- **Eine stumme Tonspur muss mit.** Manche Upload-Wege lehnen ein Video ohne
|
||||
Audiostrom ab. Die Spur kostet 128 kbit/s und erspart die Fehlersuche.
|
||||
|
||||
Die Bewegung läuft in Schleife. Das letzte Bild ist deshalb **nicht** dasselbe
|
||||
wie das erste (`t = n / anzahl`, nicht `n / (anzahl − 1)`) — sonst steht der
|
||||
Stoß eine Dreißigstelsekunde still.
|
||||
|
||||
|
||||
## Bedienung
|
||||
|
||||
| Taste | Wirkung |
|
||||
@@ -400,7 +505,9 @@ assets/
|
||||
└── fonts/ Manrope 400–800, lokal
|
||||
vendor/ html-to-image, JSZip
|
||||
state/ Projektstände, gehören ins Repo
|
||||
serve.py Statischer Server + /save, /state, /upload, /bilder
|
||||
animation.mjs baut aus einem ANIMS-Eintrag ein MP4 (braucht ffmpeg)
|
||||
animation/ die fertigen MP4s, ein Carousel-Element je Datei
|
||||
serve.py Statischer Server + /save, /state, /upload, /bilder, /anim
|
||||
rules.md Gestaltungsregeln, Farbwerte, Export-Wissen
|
||||
```
|
||||
|
||||
|
||||
Reference in new issue
Block a user