# SANA-WM

SANA-WM est un modèle de monde image-vers-vidéo contrôlé par caméra, construit sur la base de SANA. À partir d'une image de première image, d'un prompt texte et d'une trajectoire de caméra (soit des poses `c2w` explicites, soit une chaîne d'actions WASD/IJKL), il génère une vidéo dont le mouvement suit le chemin de caméra demandé.

L'inférence s'exécute en deux étapes :

1. **Étape 1 — SANA-WM DiT.** Un DiT bidirectionnel de 1,6 milliard de paramètres doté d'une attention linéaire GDN-Triton et d'une branche de contrôle caméra UCPE. L'échantillonnage utilise un planificateur Euler de correspondance de flux de type LTX avec des pas de temps par jeton ; le premier cadre latent sert d'ancrage de conditionnement.
2. **Étape 2 — Rafineur LTX-2 (facultatif).** Un pipeline de raffinement Euler bidirectionnel avec puits distinct ([SanaWMLTX2Refiner](/docs/diffusers/main/fr/api/pipelines/sana_wm#diffusers.SanaWMLTX2Refiner)) qui encapsule [SanaWMLTX2RefinerTransformer3DModel](/docs/diffusers/main/fr/api/models/sana_wm_refiner_transformer3d#diffusers.SanaWMLTX2RefinerTransformer3DModel) + `LTX2TextConnectors` et un encodeur de texte Gemma-3, exécuté sur 3 étapes de sigma distillées.

Les deux étapes décodent via le VAE [AutoencoderKLLTX2Video](/docs/diffusers/main/fr/api/models/autoencoderkl_ltx_2#diffusers.AutoencoderKLLTX2Video).

Modèles disponibles :

| Modèle | dtype recommandé |
|:-----:|:-----------------:|
| [`Efficient-Large-Model/SANA-WM_bidirectional-diffusers`](https://huggingface.co/Efficient-Large-Model/SANA-WM_bidirectional-diffusers) | `torch.bfloat16` |
| [`Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner`](https://huggingface.co/Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner) | `torch.bfloat16` |

> [!TIP]
> SANA-WM est entraîné à une résolution fixe de 704×1280. Le dtype recommandé pour les poids du transformer est `torch.bfloat16` — conservez l'encodeur de texte en `torch.bfloat16` et le VAE en `torch.float32` pour une meilleure précision numérique. Le pipeline s'attend à des intrinsèques de caméra `[fx, fy, cx, cy]` dans les coordonnées de pixels de l'*image d'origine* ; la transformation de redimensionnement et de recadrage centré est appliquée en interne.

## Inférence

```python
import torch
from PIL import Image

from diffusers import SanaWMPipeline
from diffusers.utils import export_to_video

pipe = SanaWMPipeline.from_pretrained(
    "Efficient-Large-Model/SANA-WM_bidirectional-diffusers",
    torch_dtype=torch.bfloat16,
)
pipe.enable_model_cpu_offload()  # ~45 GB of weights — offload between stages

# SANA-WM was trained on the LTX-2 VAE in framewise mode with tiling enabled. Without these
# settings the VAE encodes the whole (B, C, T, H, W) clip in one shot, which gives subtly
# different numerics from the released checkpoint.
pipe.vae.enable_tiling()
pipe.vae.use_framewise_encoding = True
pipe.vae.use_framewise_decoding = True
pipe.vae.tile_sample_stride_num_frames = 64
pipe.vae.tile_sample_min_num_frames = 96

prompt = "A car driving across a vast desert plain at golden hour."
output = pipe(
    image=Image.open("input.png").convert("RGB"),
    prompt=prompt,
    action="w-80,jw-40,w-40",        # WASD-style action DSL: forward 80f, jump+forward 40f, forward 40f
    intrinsics=[800.0, 800.0, 845.0, 464.0],  # fx, fy, cx, cy in original-image pixels
    num_frames=161,
    num_inference_steps=60,
    guidance_scale=5.0,
    generator=torch.Generator(device="cuda").manual_seed(42),
    output_type="latent",            # hand the latents to the refiner below
)
```

Passez `action=None` et fournissez vos propres poses `c2w` (tableau numpy `(F, 4, 4)`) pour piloter explicitement la trajectoire de la caméra. Supprimez `output_type="latent"` pour obtenir la vidéo directement depuis l'étape 1 et ignorer le raffineur.

### Étape 2 — le raffineur LTX-2

[SanaWMLTX2Refiner](/docs/diffusers/main/fr/api/pipelines/sana_wm#diffusers.SanaWMLTX2Refiner) est fourni sous forme de dépôt distinct, à la manière dont SDXL sépare le modèle de base et le refiner. Transmettez le VAE du pipeline de base afin que les poids soient partagés plutôt que chargés deux fois :

```python
from diffusers import SanaWMLTX2Refiner

refiner = SanaWMLTX2Refiner.from_pretrained(
    "Efficient-Large-Model/SANA-WM_bidirectional-diffusers-refiner",
    vae=pipe.vae,
    torch_dtype=torch.bfloat16,
)
refiner.enable_model_cpu_offload()

frames = refiner(output.latent, prompt, fps=16)
export_to_video(list(frames), "sana_wm.mp4", fps=16)
```

Sans `vae`, le refiner renvoie des latents affinés au lieu de la vidéo, ce qui est utile si vous souhaitez effectuer le décodage vous-même.

> [!TIP]
> Activez le déchargement sur **les deux** pipelines, ou libérez l’étape 1 avant l’étape 2 (`pipe.transformer.to("cpu")`). Les deux étapes représentent environ 45 Go en `torch.bfloat16`, et les maintenir toutes deux sur une seule carte de 80 Go laisse trop peu de place pour les activations. Notez également que l’étape 2 respecte `torch_dtype` : charger le raffineur en `torch.float32` double approximativement sa consommation mémoire et modifie légèrement la sortie.

Si vous ne disposez pas des intrinsèques de la caméra, un [bloc modulaire](../../modular_diffusers/overview) hébergé peut les estimer à partir d'une seule image. Il se trouve en dehors de `diffusers` car il intègre Pi3X — une dépendance supplémentaire et un second point de contrôle — de sorte que rien n'est téléchargé tant que vous ne le demandez pas :

```python
from diffusers import ModularPipeline

# One-time per image. Requires `pip install pi3-vision`.
estimator = ModularPipeline.from_pretrained(
    "Efficient-Large-Model/pi3x-intrinsics-estimator", trust_remote_code=True
)
estimator.load_components(dtype=torch.bfloat16)
intrinsics = estimator(image=Image.open("input.png").convert("RGB"), output="intrinsics")
```

## Conversion du point de contrôle publié

Si vous disposez de la version source SANA-WM (et non du instantané diffusers pré-converti), exécutez le script de conversion une seule fois :

```bash
python scripts/convert_sana_wm_to_diffusers.py \
    --src Efficient-Large-Model/SANA-WM_bidirectional \
    --dst ./SANA-WM_bidirectional-diffusers
```

Cela écrit deux répertoires : le pipeline de base dans `--dst`, et le raffineur de l’étape 2 à côté, dans `./SANA-WM_bidirectional-diffusers-refiner` (à remplacer par `--dst-refiner`). Chargez ensuite chacun depuis son chemin local, comme d’habitude.

## Composants

- `tokenizer` — `GemmaTokenizerFast`
- `text_encoder` — Gemma-2 (renvoie les états cachés du décodeur)
- `vae` — [AutoencoderKLLTX2Video](/docs/diffusers/main/fr/api/models/autoencoderkl_ltx_2#diffusers.AutoencoderKLLTX2Video) (LTX-2, spatial ×32 / temporal ×8)
- `transformer` — [SanaWMTransformer3DModel](/docs/diffusers/main/fr/api/models/sana_wm_transformer3d#diffusers.SanaWMTransformer3DModel), DiT bidirectionnel de 1,6 milliard de paramètres
- `scheduler` — [FlowMatchEulerDiscreteScheduler](/docs/diffusers/main/fr/api/schedulers/flow_match_euler_discrete#diffusers.FlowMatchEulerDiscreteScheduler)

Le raffineur de l’étape 2 est un dépôt distinct disposant de son propre `transformer` ([SanaWMLTX2RefinerTransformer3DModel](/docs/diffusers/main/fr/api/models/sana_wm_refiner_transformer3d#diffusers.SanaWMLTX2RefinerTransformer3DModel)), de ses `connectors` (`LTX2TextConnectors`), de son `tokenizer`, de son `text_encoder` Gemma-3 et de son `scheduler`. Il ne possède pas de `vae` propre — transmettez celui du pipeline de base.

## SanaWMPipeline[[diffusers.SanaWMPipeline]]

#### diffusers.SanaWMPipeline[[diffusers.SanaWMPipeline]]

```python
diffusers.SanaWMPipeline(tokenizer: GemmaTokenizer | GemmaTokenizerFast, text_encoder: Gemma2PreTrainedModel, vae: AutoencoderKLLTX2Video, transformer: SanaWMTransformer3DModel, scheduler: FlowMatchEulerDiscreteScheduler)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L143)

**Paramètres :**

tokenizer ([*GemmaTokenizer*] ou [*GemmaTokenizerFast*]) : le tokenizer Gemma-2.

text_encoder ([*Gemma2PreTrainedModel*]) : L'encodeur de texte Gemma-2.

vae ([*AutoencoderKLLTX2Video*]) : Le VAE LTX-2.

transformer ([*SanaWMTransformer3DModel*]) : Le DiT bidirectionnel SANA-WM de 1600M.

scheduler ([*FlowMatchEulerDiscreteScheduler*]) : planificateur Euler de correspondance de flux (pas de temps par jeton de type LTX). latents directement.

Pipeline d'image vers vidéo contrôlé par caméra SANA-WM.

Génère une vidéo à partir d'une image de première image, d'un prompt texte et d'une trajectoire de caméra (poses `c2w` explicites ou chaîne d'actions WASD/IJKL). Utilise le SANA DiT bidirectionnel 1600M pour l'échantillonnage de l'étape 1 et le refineur Euler bidirectionnel à sink de LTX-2 pour la finition de l'étape 2 ; les deux sont décodés via le VAE de LTX-2.

#### __appel__[[diffusers.SanaWMPipeline.__call__]]

```python
__call__(image: PIL.Image.Image | str | Path, prompt: str, c2w: np.ndarray | None = None, action: str | None = None, intrinsics: np.ndarray | list[float] | None = None, height: int = 704, width: int = 1280, num_frames: int = 161, fps: int = 16, num_inference_steps: int = 60, guidance_scale: float = 5.0, negative_prompt: str = '', generator: torch.Generator | list[torch.Generator] | None = None, prompt_embeds: torch.Tensor | None = None, prompt_attention_mask: torch.Tensor | None = None, negative_prompt_embeds: torch.Tensor | None = None, negative_prompt_attention_mask: torch.Tensor | None = None, max_sequence_length: int = 300, chi_prompt: list[str] | None = None, output_type: Literal['np', 'pil', 'pt', 'latent'] = 'np', callback_on_step_end: Callable[[DiffusionPipeline, int, int, dict], dict] | None = None, callback_on_step_end_tensor_inputs: list[str] = ['latents'], return_dict: bool = True)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L457)

**Paramètres :**

image (*PIL.Image.Image* ou *str*) : Image de la première image (PIL ou chemin).

prompt (*str*) : Invite textuelle.

c2w (*np.ndarray*, *facultatif*) : poses caméra-monde de forme `(F, 4, 4)`. Mutuellement exclusif avec *action*.

action (*str*, *facultatif*) : Chaîne Action-DSL, par exemple `"w-80,jw-40,w-40"`. Mutuellement exclusif avec *c2w*.

intrinsics (*np.ndarray* ou *list[float]*) : `[fx, fy, cx, cy]` dans les coordonnées de pixels de l'**image d'origine**. Le pipeline applique la transformation de redimensionnement et de recadrage en interne.

height (*int*, par défaut 704) : Hauteur des images de sortie (fixe pour le modèle public).

width (*int*, par défaut 1280) : Largeur des images de sortie (fixe pour le modèle public).

num_frames (*int*, par défaut 161) : Nombre de cibles ; arrondi à `8k+1` (contrainte du VAE LTX-2).

fps (*int*, par défaut 16) : Taux de rafraîchissement de sortie (également transmis au refiner).

num_inference_steps (*int*, par défaut 60) : Nombre d'étapes d'échantillonnage DiT de l'étape 1.

guidance_scale (*float*, par défaut 5.0) : Échelle du guidage sans classifieur.

negative_prompt (*str*, par défaut "") : Prompt négatif facultatif.

generator (*torch.Generator* ou *list[torch.Generator]*, *facultatif*) : Un ou plusieurs générateurs torch pour rendre l'échantillonnage du bruit déterministe. Si *None*, l'échantillonnage est non déterministe.

prompt_embeds (*torch.Tensor*, *facultatif*) : Incrustations de texte précalculées, pour ignorer l'encodeur de texte. Doit être transmis avec *prompt_attention_mask*.

prompt_attention_mask (*torch.Tensor*, *facultatif*) : Masque d'attention pour *prompt_embeds*.

negative_prompt_embeds (*torch.Tensor*, *facultatif*) : Incrustations de texte négatif précalculées. Doit être transmis avec *negative_prompt_attention_mask*.

negative_prompt_attention_mask (*torch.Tensor*, *facultatif*) : Masque d'attention pour *negative_prompt_embeds*.

max_sequence_length (*int*, par défaut 300) : Nombre maximal de jetons de l'invite.

chi_prompt (*list[str]*, *facultatif*) : Remplace le préfixe du prompt chi (par défaut, identique à la version publique).

output_type (*"np"*, *"pil"*, *"pt"* ou *"latent"*, par défaut *"np"*) : Format de sortie.

callback_on_step_end (*Callable*, *facultatif*) : Appelé à la fin de chaque étape de débruitage sous la forme *callback_on_step_end(self, step, timestep, callback_kwargs)*, où *callback_kwargs* contient les tenseurs nommés dans *callback_on_step_end_tensor_inputs*. Les tenseurs du dictionnaire retourné remplacent ceux du pipeline.

callback_on_step_end_tensor_inputs (*list[str]*, par défaut *["latents"]*) : Tenseurs à passer à *callback_on_step_end* ; doit être un sous-ensemble de *._callback_tensor_inputs*.

return_dict (*bool*, par défaut True) : Retourner un [*SanaWMPipelineOutput*] plutôt qu'un tuple.

**Retourne :**

[*SanaWMPipelineOutput*] avec *.frames* de forme `(T, H, W, 3)`, tableau `np.ndarray` flottant dans `[0, 1]` pour *output_type="np"*, une liste de `PIL.Image.Image` de longueur `T` pour *"pil"*, un tenseur `(T, 3, H, W)` pour *"pt"*, ou le tenseur latent brut pour *"latent"*.

Générer une vidéo contrôlée par caméra SANA-WM.

Exemples :
```py
>>> import torch
>>> from PIL import Image
>>> from diffusers import SanaWMPipeline

>>> pipe = SanaWMPipeline.from_pretrained(
...     "Efficient-Large-Model/SANA-WM_bidirectional-diffusers", torch_dtype=torch.bfloat16
... ).to("cuda")

>>> output = pipe(
...     image=Image.open("input.png").convert("RGB"),
...     prompt="A car driving across a vast desert plain at golden hour.",
...     action="w-80,jw-40,w-40",
...     intrinsics=[800.0, 800.0, 845.0, 464.0],  # fx, fy, cx, cy in original-image pixels
...     num_inference_steps=60,
... )
>>> # output.frames is (T, H, W, 3) float np.ndarray in [0, 1] (diffusers convention).
```

#### check_inputs[[diffusers.SanaWMPipeline.check_inputs]]

```python
check_inputs(c2w: np.ndarray | None, action: str | None, intrinsics: np.ndarray | list[float] | None, callback_on_step_end_tensor_inputs: list[str] | None = None)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L335)

Valide les entrées de `__call__`. Lève une exception en cas d'entrée invalide et ne renvoie rien.

#### encode_prompt[[diffusers.SanaWMPipeline.encode_prompt]]

```python
encode_prompt(prompt: str, negative_prompt: str = '', device: torch.device | None = None, max_sequence_length: int = 300, chi_prompt: list[str] | None = None, prompt_embeds: torch.Tensor | None = None, prompt_attention_mask: torch.Tensor | None = None, negative_prompt_embeds: torch.Tensor | None = None, negative_prompt_attention_mask: torch.Tensor | None = None)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L204)

**Retourne :**

`(cond, cond_mask, neg, neg_mask)` où `cond` et `neg` sont des états cachés Gemma de forme `(1, 1, L, D)` et les masques sont de forme `(1, L)`.

Encoder le prompt et le prompt négatif via Gemma-2.

Reprend l’astuce du préfixe chi-prompt de SANA : le prompt chi est préfixé au prompt de l’utilisateur, puis une tranche `select_index = [0, -L+1, ..., -1]` extrait le jeton BOS ainsi que les `max_sequence_length - 1` derniers jetons.

#### prepare_camera_trajectory[[diffusers.SanaWMPipeline.prepare_camera_trajectory]]

```python
prepare_camera_trajectory(c2w: np.ndarray | None, action: str | None, intrinsics: np.ndarray | list[float], num_frames: int)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L365)

Normaliser les entrées de la caméra en `(c2w_(F, 4, 4), intrinsics_(F, 4))`.

Également arrondit `num_frames` à la valeur `8k+1` compatible avec le VAE et ajuste les deux tableaux en conséquence. L’image recadrée et les intrinsèques remises à l’échelle sont fournies plus tard, une fois la résolution cible connue.

#### prepare_latents[[diffusers.SanaWMPipeline.prepare_latents]]

```python
prepare_latents(first_latent: torch.Tensor, num_frames: int, height: int, width: int, dtype: torch.dtype, device: torch.device, generator: torch.Generator)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_sana_wm.py#L403)

Échantillonnez les latents initiaux et fixez le premier plan comme ancre de conditionnement.

Retourne `(latents, condition_mask)` où `condition_mask` contient des uns sur les jetons de la première image (ils restent propres tout au long de l'échantillonnage) et des zéros ailleurs.

## SanaWMLTX2Refiner[[diffusers.SanaWMLTX2Refiner]]

Le raffineur de l'étape 2 de LTX-2 est un [DiffusionPipeline](/docs/diffusers/main/fr/api/pipelines/overview#diffusers.DiffusionPipeline) autonome qui reçoit les latents de l'étape 1. Fournissez-lui un `vae` (celui du pipeline de base, afin que les poids soient partagés) pour qu'il décode en vidéo ; sans celui-ci, il renvoie des latents raffinés.

#### diffusers.SanaWMLTX2Refiner[[diffusers.SanaWMLTX2Refiner]]

```python
diffusers.SanaWMLTX2Refiner(transformer: SanaWMLTX2RefinerTransformer3DModel, connectors: LTX2TextConnectors, tokenizer: GemmaTokenizer | GemmaTokenizerFast, text_encoder: Gemma3ForConditionalGeneration, scheduler: FlowMatchEulerDiscreteScheduler, vae: AutoencoderKLLTX2Video | None = None, text_max_sequence_length: int = 1024)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/refiner.py#L47)

**Paramètres :**

transformer ([*SanaWMLTX2RefinerTransformer3DModel*]) : le DiT vidéo LTX-2 avec cache KV glissant causal par blocs.

connectors ([*LTX2TextConnectors*]) : connecteurs de texte LTX-2.

tokenizer : Tokenizer Gemma-3.

text_encoder : encodeur de texte Gemma-3.

scheduler ([*FlowMatchEulerDiscreteScheduler*]) : planificateur Euler de correspondance de flux. Construit avec `shift=1.0` afin que les sigmas distillés passent sans modification.

vae ([*AutoencoderKLLTX2Video*], *facultatif*) : le même VAE utilisé par [*SanaWMPipeline*] ; passez *vae=pipe.vae* pour partager les poids. S'il est fourni, le raffineur décode en vidéo, sinon il renvoie des latents raffinés.

text_max_sequence_length (*int*, par défaut 1024) : Nombre maximal de jetons transmis au tokeniseur Gemma-3.

LTX-2 sink-bidirectionnel Euler refiner — SANA-WM étape 2, en tant que pipeline autonome.

Encapsule les composants de LTX-2 (transformer de raffinement + connecteurs de texte + encodeur de texte Gemma-3 + tokeniseur) ainsi qu'un [*FlowMatchEulerDiscreteScheduler*] qui porte l'agenda sigma distillé et exécute les étapes d'Euler. Il est enregistré en tant que composant optionnel de [*SanaWMPipeline*] et peut également être utilisé de manière autonome pour raffiner les latents de l'étape 1.

#### __appel__[[diffusers.SanaWMLTX2Refiner.__call__]]

```python
__call__(sana_latent: torch.Tensor, prompt: str, fps: float, sink_size: int = 1, generator: torch.Generator | None = None, block_size: int = 3, kv_max_frames: int = 11, sigmas: tuple[float, ...] = (0.909375, 0.725, 0.421875, 0.0), output_type: str = 'np')
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/refiner.py#L107)

**Paramètres :**

sana_latent : `(B, C, F, H, W)` latent de l'étape 1.

prompt : invite de texte.

fps : fréquence d'images de la vidéo (pilote le redimensionnement temporel de RoPE pour LTX-2).

sink_size : nombre de trames brutes `z_sana` initiales à ancrer en tant que puits d'attention (valeur canonique : 1).

generator : torch.Generator pour le bruit de l'endpoint FM. Par défaut, un générateur initialisé avec la graine 42 est utilisé afin que les résultats soient reproductibles dès l'installation.

block_size : nombre de trames latentes par bloc AR (canonique : 3).

kv_max_frames : nombre maximal de contextes + cadres actifs conservés dans la fenêtre glissante (canonique : 11 = 1 sink + 10 récents).

sigmas : plan d'Euler descendant se terminant à 0.0 (distillation canonique en 3 étapes : `(0.909375, 0.725, 0.421875, 0.0)`). Fourni à `self.scheduler` (sans le 0.0 final, que le planificateur ajoute lui-même).

output_type : *"latent"* renvoie les latents affinés. Toute autre valeur décode via *self.vae* et post-traite vers ce type (*"np"*, *"pt"*, *"pil"*) ; en l'absence de *vae*, les latents sont renvoyés dans tous les cas.

**Retourne :** `*torch.Tensor*`

Latents VAE affinés de forme `(B, C, F, H, W)` — les `sink_size` premières images portent les latents bruts du sink de l'étape 1 sans modification, le reste porte la sortie affinée.

Exécutez le raffineur LTX-2 et renvoyez les latents VAE raffinés.

Utilise la recette AR causale par blocs sur laquelle le modèle a été entraîné (`block_size=3`, `kv_max_frames=11`) : une fenêtre glissante de K/V `[source_sink + recent_history + active_block]` est transmise au transformateur un bloc à la fois, de sorte que le calcul par bloc est borné et que le coût total de raffinement évolue linéairement avec la longueur de la vidéo.

## SanaWMPipelineOutput[[diffusers.SanaWMPipelineOutput]]

#### diffusers.SanaWMPipelineOutput[[diffusers.SanaWMPipelineOutput]]

```python
diffusers.SanaWMPipelineOutput(frames: typing.Union[torch.Tensor, numpy.ndarray, list[list[PIL.Image.Image]]], c2w: numpy.ndarray | None = None, latent: typing.Optional[torch.Tensor] = None)
```

[Source](https://github.com/huggingface/diffusers/blob/main/src/diffusers/pipelines/sana_wm/pipeline_output.py#L25)

**Paramètres :**

frames (*torch.Tensor*, *np.ndarray* ou *list[PIL.Image.Image]*) : Vidéo générée : un tableau `np.ndarray` flottant de forme `(T, H, W, 3)` dans `[0, 1]` pour `output_type="np"`, un tenseur `(T, 3, H, W)` pour `"pt"`, une liste de `T` ``PIL.Image` pour `"pil"`, ou le tenseur latent `(B, C, T_lat, H_lat, W_lat)` pour `"latent"`.

c2w (*np.ndarray*) : Poses caméra-monde `(T, 4, 4)` alignées avec `frames` (le refiner supprime le cadre d’ancrage sink ; ce tableau est réaligné en conséquence si le refiner a été exécuté).

latent (*torch.Tensor*, optionnel) : Tenseur latent dans l'espace VAE de LTX-2, de forme `(B, C, T_lat, H_lat, W_lat)`. Renvoyé lorsque `output_type="latent"``.

Classe de sortie pour le pipeline image-vers-vidéo SANA-WM.

