# For loops

{% hint style="success" %}
Key learnings:

* [x] You can add for loops in your apps to repeat various set of nodes.
* [x] Using `let latent: Comfy.Signal['LATENT'] = ...` is a great way to allow to cary a "Latent" signal
  {% endhint %}

## Objective

Start from the default app, and enhance it to allow for a configurable number of recursive samplers.

1. Add a new number input to control how many ksampler we want
2. Use that number to genearte

<div data-full-width="true"><figure><img src="https://1334536949-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fp2KKP8nDCeZzdDzol4lf%2Fuploads%2F8PfsZJenIB46ks2Adgd6%2Fimage.png?alt=media&#x26;token=83830d39-e638-4e47-b391-a35de8aaeee3" alt=""><figcaption></figcaption></figure></div>

<details>

<summary>Final Code</summary>

```typescript
app({
    metadata: { name: 'demo for-loops', description: 'my app description' },
    ui: (form) => ({
        model: form.enum['CheckpointLoaderSimple.ckpt_name']({}),
        positive: form.string({ default: 'masterpiece, tree' }),
        seed: form.seed({}),
        // 1. add new UI control to display how many loops you want
        loops: form.number({ default: 3 }),
    }),
    run: async (run, ui) => {
        const workflow = run.workflow
        const graph = workflow.builder

        const ckpt = graph.CheckpointLoaderSimple({ ckpt_name: ui.model })
        // 2. here, I'm using the _LATENT annotation to allow to assign any node
        // that produce a latent, and not just an EmptyLatentImage node.
        let latent: Comfy.Signal['LATENT'] = graph.EmptyLatentImage({})

        // 3. moving embeddigns node definition outside of the Ksampler,
        // as variable, so they can be used in the loop below
        const pos = graph.CLIPTextEncode({ clip: ckpt, text: ui.positive })
        const neg = graph.CLIPTextEncode({ clip: ckpt, text: '' })
        latent = graph.KSampler({
            seed: ui.seed,
            latent_image: latent,
            model: ckpt,
            sampler_name: 'ddim',
            scheduler: 'karras',
            positive: pos, // use the variables
            negative: neg, // use the variables
        })

        // 4. add a for loop
        for (let i = 0; i < ui.loops; i++) {
            // 👇 I'm reassigning latent variable
            latent = graph.KSampler({
                seed: ui.seed,
                latent_image: latent, // 👈 from the previous latent
                model: ckpt,
                sampler_name: 'ddim',
                scheduler: 'karras',
                positive: pos,
                negative: neg,
            })
        }

        const image = graph.VAEDecode({
            samples: latent,
            vae: ckpt,
        })
        graph.PreviewImage({ images: image })
        await workflow.sendPromptAndWaitUntilDone()
    },
})
```

</details>

## Diff

```diff
app({
         model: form.enum['CheckpointLoaderSimple.ckpt_name']({}),
         positive: form.string({ default: 'masterpiece, tree' }),
         seed: form.seed({}),
+        // 1. add new UI control to display how many loops you want
+        loops: form.number({ default: 3 }),
     }),
     run: async (run, ui) => {
         const workflow = run.workflow
         const graph = workflow.builder

         const ckpt = graph.CheckpointLoaderSimple({ ckpt_name: ui.model })
+        // 2. here, I'm using the _LATENT annotation to allow to assign any node
+        // that produce a latent, and not just an EmptyLatentImage node.
         let latent: Comfy.Signal['LATENT'] = graph.EmptyLatentImage({})

+        // 3. moving embeddigns node definition outside of the Ksampler,
+        // as variable, so they can be used in the loop below
+        const pos = graph.CLIPTextEncode({ clip: ckpt, text: ui.positive })
+        const neg = graph.CLIPTextEncode({ clip: ckpt, text: '' })
         latent = graph.KSampler({
             seed: ui.seed,
             latent_image: latent,
             model: ckpt,
             sampler_name: 'ddim',
             scheduler: 'karras',
-            positive: graph.CLIPTextEncode({ clip: ckpt, text: ui.positive }),
-            negative: graph.CLIPTextEncode({ clip: ckpt, text: '' }),
+            positive: pos, // use the variables
+            negative: neg, // use the variables
         })
+
+        // 4. add a for loop
+        for (let i = 0; i < ui.loops; i++) {
+            // 👇 I'm reassigning latent variable
+            latent = graph.KSampler({
+                seed: ui.seed,
+                latent_image: latent, // 👈 from the previous latent
+                model: ckpt,
+                sampler_name: 'ddim',
+                scheduler: 'karras',
+                positive: pos,
+                negative: neg,
+            })
+        }
+
         const image = graph.VAEDecode({
             samples: latent,
             vae: ckpt,

```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cushystudio.com/going-further/creating-apps/for-loops.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
