tempo di lettura : 8 minutes

Due settimane fa, ho lanciato`capsule-gradle`— un plugin che trasforma un deck reveal.js in una capsula video WebM con TTS. Oggi, aggiungo un nuovo plugin: hyperframes-gradle. Fa qualcosa che capsule-gradle non fa : trasformare l’AsciiDoc direttamente in video MP4, senza passare da reveal.js.

Ecco perché questo plugin esiste, come si articola con l’esistente, e ciò che il motore HyperFrames di HeyGen apporta al pipeline di produzione del contenuto

il buco nel pipeline video

Il mio pipeline documentario produce due tipi di video:

  1. Capsula di revisione (capsule-gradle) — un deck reveal.js catturato in WebM con

narrazione TTS. Perfetto per rivedere un modulo.

  1. Slides d’animation (slider-gradle) — un deck reveal.js HTML interattivo per

Il formatore in presenza

Ma manca un terzo formato : il video standalone

caso d’uso

Soluzione attuale

Mancanza

Slides formatore

slider-gradle → reveal.js

(No output)

Capsula revisione

capsule-gradle → WebM

�✅

Video teaser

nessuna

❌

Demo tecnica animata

nessuna

�❌

Da documento a video

Nessuna

❌

Il primo use case è critico: come generare automaticamente un video di 60 secondi che presenta un progetto o un modulo, con animazioni GSAP, narration TTS, e sottofondo musicale — il tutto dallo stesso file AsciiDoc cosa le slide ?

Capsule-gradle non può rispondere: gli serve già un deck reveal.js. slider-gradle produce bene questo deck, ma non è progettato per il rendering video. Era necessario avere un pipeline direct : AsciiDoc → video.

HyperFrames : Il Motore

Ho scopertohttps://github.com/heygen-com/hyperframes[HyperFrames] il y a alcuni giorni. È un framework open-source (Apache 2.0) creato da HeyGen, l’unicorno del video IA. 22 700 stelle su GitHub. Il pitch contiene in una frase :

Scrivi HTML. Renderizza video. Realizzato per gli agenti.

Il principio: voi scrivete HTML con dei`data-*`attributi, fate riferimento un’animazione GSAP (o CSS, Lottie, Three.js…), e il motore rende tutto in MP4 via Puppeteer (Chrome headless) + FFmpeg. Risultato deterministico: stesso input, stessi frame, stesso video

<div id="stage" data-composition-id="intro" data-start="0" data-width="1920" data-height="1080">
  <video class="clip" data-start="0" data-duration="6" data-track-index="0"
         src="background.mp4" muted playsinline></video>

  <h1 id="title" class="clip" data-start="1" data-duration="4" data-track-index="1">
    Formation Docker & Kubernetes
  </h1>

  <audio data-start="0" data-duration="6" data-track-index="2"
         data-volume="0.3" src="music.wav"></audio>

  <script src="https://cdn.jsdelivr.net/npm/gsap@3/dist/gsap.min.js"></script>
  <script>
    const tl = gsap.timeline({ paused: true });
    tl.from("#title", { opacity: 0, y: 40, duration: 0.8 }, 1);
    window.__timelines = window.__timelines || {};
    window.__timelines.intro = tl;
  </script>
</div>

Che cosa rende HyperFrames diverso da Remotion? Nessun React, nessun bundler, senza JSX. HTML grezzo che gli agenti IA sanno scrivere nativamente. È tagliato esattamente per il mio pipeline : planner-gradle con deepseek può generare questo HTML a partire da un piano SPG/SPD, e un plugin Gradle può convertirlo in MP4.

L’architettura del plugin

hyperframes-gradle segue lo stesso pattern di tutti i miei plugin : il pattern « Plugin Indipendente + Radice Consumatore ».

hyperframes-gradle/
├── settings.gradle.kts          ← racine consommateur (dogfood)
├── build.gradle.kts              ← 3 lignes : apply plugin hyperframes
├── hyperframes-plugin/           ← BUILD INDÉPENDANT
│   ├── gradlew                    ← son propre wrapper
│   ├── build.gradle.kts           ← java-gradle-plugin
│   ├── src/main/kotlin/education/cccp/hyperframes/
│   │   ├── HyperframesPlugin.kt
│   │   ├── GenerateHyperframesHtmlTask.kt
│   │   ├── RenderHyperframesTask.kt
│   │   └── HyperframesExtension.kt
│   ├── .agents/                   ← gouvernance agent
│   └── doc/
│       └── HYPERFRAMES_ARCHITECTURE.adoc
└── video.yml                      ← configuration dogfood

Il pipeline in quattro fasi

Failed to generate image: PlantUML preprocessing failed: [From <input> (line 9) ]

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11

title condotta hyperframes-gradle
rectangle "AsciiDoc\nsorgente" as adoc #LightYellow
rectangle "AsciidoctorJ" as asciidoctorj #LightBlue
rectangle "HTML HyperFrames
(data-* attributi)" as html #LightGreen
^^^^^
 Syntax Error? (Assumed diagram type: activity)

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultFontSize 11

title condotta hyperframes-gradle
rectangle "AsciiDoc\nsorgente" as adoc #LightYellow
rectangle "AsciidoctorJ" as asciidoctorj #LightBlue
rectangle "HTML HyperFrames
(data-* attributi)" as html #LightGreen
rectangle "HyperFrames CLI
(Node.js 22+)" as cli #Lavender
rectangle "video.mp4" as mp4 #Gold

adoc -right-> asciidoctorj : parse blocs customs
asciidoctorj -right-> html : génère HTML
html -right-> cli : ProcessBuilder\nnpx hyperframes render
cli -right-> mp4 : Puppeteer + FFmpeg
@enduml
  1. AsciidoctorJ analizza il sorgente AsciiDoc e estrae i blocchi personalizzati

[hyperframes-composition], [hyperframes-track], [hyperframes-animation].

  1. GenerateHyperframesHtmlTask genera l’HTML HyperFrames con le

`data-*`attributi corrispondenti.

  1. RenderHyperframesTask appelle la CLI HyperFrames via ProcessBuilder:

npx hyperframes render --input index.html --output video.mp4.

  1. Il MP4 è distribuito in`output/`con un`metadata.json`per l’orchestrazione.

Il DSL AsciiDoc

Il vero valore aggiunto del plugin è il DSL AsciiDoc. L’utente Non scrive mai HTML. Annota il suo documento AsciiDoc esistente:

= Formation Docker & Kubernetes
:hyperframes-width: 1920
:hyperframes-height: 1080
:hyperframes-fps: 30

[hyperframes-composition, id="intro"]
== Introduction

Le titre apparaît avec un fondu GSAP sur fond vidéo.

[hyperframes-track, index=0, start=0, duration=6]
video::assets/background.mp4[muted, playsinline]

[hyperframes-track, index=1, start=1, duration=4]
Formation Docker & Kubernetes

[hyperframes-animation, type=gsap]

const tl = gsap.timeline({ paused: true }); tl.from("#title", { opacity: 0, y: 40, duration: 0.8 }, 1); window.timelines = window.timelines || {}; window.__timelines.intro = tl;

Gli attributi docinfo`:hyperframes-width:`) configurano le dimensioni. I blocchi personalizzati definiscono le composizioni e le tracce. `[hyperframes-animation]`contiene il codice GSAP grezzo — che l’agente IA può generare a partire da una descrizione in linguaggio naturale.

Il Bridge Node.js

L’unico punto di attrito tecnico: HyperFrames è in Node.js/TypeScript, e i miei plugin sono in Kotlin/JVM. La soluzione è un`ProcessBuilder`:

class RenderHyperframesTask : DefaultTask() {

    @TaskAction
    fun render() {
        val process = ProcessBuilder(
            "npx", "hyperframes", "render",
            "--input", inputHtml.absolutePath,
            "--output", outputMp4.absolutePath
        )
            .inheritIO()
            .start()

        val exitCode = process.waitFor()
        require(exitCode == 0) {
            "HyperFrames render failed with exit code $exitCode"
        }
    }
}

Zero accoppiamento tra il codice JVM e Node.js. Il contratto è via riga di comando. e file su disco. È lo stesso modello che`plantuml-gradle` # Gradle Integration JBake can be integrated into Gradle builds using the JBake Gradle plugin or by calling the JBake CLI directly:

----
tasks.register<JavaExec>("bake") {
    mainClass.set("org.jbake.launcher.Main")
    classpath = configurations["jbake"]
    args = listOf(projectDir.absolutePath, "$buildDir/jbake")
}`slider-gradle`(chi chiama AsciidoctorJ). Niente di nuovo sotto il sole — semplicemente applicato a uno strumento più recente.

== Due Plugins Video, Due Usi

|===
| |capsula-gradle |hyperframes-gradle |Source |Deck reveal.js (HTML esistante) |AsciiDoc → HyperFrames HTML |Caso d'uso |Capsula di revisione |Video standalone esplicativa |Natura |Diapositive → video |Documento → video |reso |Playwright Java → WebM |HyperFrames CLI → MP4 |Animazione |Transizioni reveal.js nativi |GSAP/CSS attributi data |pila |100% JVM (Kotlin) |### Integrazione Gradle
JBake può essere integrato nelle build Gradle utilizzando il plugin JBake per Gradle oppure richiamando direttamente la CLI di JBake:

----

tasks.register<JavaExec>("bake") { mainClass.set("org.jbake.launcher.Main") classpath = configurations["jbake"] args = listOf(projectDir.absolutePath, "$buildDir/jbake") }

|===
|===

|EPIC |Description |Priorità |HF-0 |Bootstrap governance + inquadramento architettura |TERMINATO |HF-1 |Plugin Gradle stub + integrazione AsciidoctorJ |P0 |HF-2 |### Integrazione Gradle JBake può essere integrato nelle build Gradle utilizzando il plugin JBake Gradle oppure chiamando direttamente la CLI di JBake:

```kotlin
----
tasks.register<JavaExec>("bake") {
    mainClass.set("org.jbake.launcher.Main")
    classpath = configurations["jbake"]
    args = listOf(projectDir.absolutePath, "$buildDir/jbake")
} |P1 |HF-3 |DSL AsciiDoc abitudini (blocchi, docinfo, template) |P1 |HF-4 |Integrazione runner-gradle (metadata.json) |P2 |HF-5 |Template pronti all'uso (title-card, code-diff, captions) |P3 |HF-6 |CI + pubblicazione Maven Central / Gradle Portal |P3
|===

La session 000 (bootstrap) è già terminata. La session 001 attaccherà HF-1 : lo stub del plugin Gradle e l'integrazione AsciidoctorJ.

== Perché funziona

Tre ragioni:

1. *HyperFrames è "built for agents*". Il mio pipeline si basa su agenti IA

(planner-gradle + deepseek) che generano contenuto. HyperFrames accetta HTML grezzo — il formato che i LLM padroneggiano meglio. Niente React, niente di JSX, nessuna curva di apprendimento per l'agente.

1. *Il DSL AsciiDoc è naturale*. Tutto il mio ecosistema parla AsciiDoc.

slider-gradle, codex-gradle, training-gradle — tutti consumano del`.adoc`. Aggiungere blocchi personalizzati`[hyperframes-composition]`è un'estensione logico, non una rottura.

1. *Il bridge Node.js è un pattern collaudato*. ProcessBuilder fuori dalla JVM,

Questo è quello che faccio già per PlantUML, Graphviz, Piper. Aggiungi HyperFrames non cambia nulla all'architettura — è uno strumento esterno in più, pilotato da Gradle

[NOTE]
====
La vera forza del pattern è che non c'è *nessuna* dipendenza npm in la build Gradle. Il plugin non importa alcun codice Node.js. Esegue una comando shell. Se HyperFrames evolve o si rompe, il plugin non è accoppiato. — basta aggiornare il comando.
====

== Conclusion: L'anello mancante

Con hyperframes-gradle, il mio pipeline video è completo. Ho:

* Le *slide interattive* (slider-gradle)
* Le *capsule di revisione* (capsule-gradle)
* Le *video standalone* (hyperframes-gradle)

Tre formati. Un unico file sorgente: l'AsciiDoc.

L'obiettivo successivo è HF-1 : fare compilare il plugin e generare un primo HTML HyperFrames a partire da un documento AsciiDoc annotato. La sessione 001 è già inquadrata.

hyperframes-gradle esiste. La governance è in atto. Il backlog è scritto. L'architettura è documentata. Il plugin è nato.

== Riferimenti

* ### Integrazione Gradle
JBake può essere integrato nelle build Gradle utilizzando il plugin Gradle JBake o chiamando direttamente la CLI JBake:

----

tasks.register<JavaExec>("bake") { mainClass.set("org.jbake.launcher.Main") classpath = configurations["jbake"] args = listOf(projectDir.absolutePath, "$buildDir/jbake") } ```

xref:0124_architecture_plugin_gradle_racine_consommateur_independant_post.adoc[Articolo 0124 — L'Architettura Plugin Indipendente + Radice Consumatore]

* https://github.com/heygen-com/hyperframes[HyperFrames — GitHub]
* https://hyperframes.heygen.com/introduction[HyperFrames — Documentazione]
* `foundry/public/hyperframes-gradle/hyperframes-plugin/doc/HYPERFRAMES_ARCHITECTURE.adoc`— Architettura dettagliata

Articoli correlati