# ESP IDE Add-on Manual + Universal Prompt (Blockly 6 + MicroPython)

Tento dokument je urceny pro lidi i AI, kteri NEMAJI pristup ke zdrojovým souborům projektu a potrebuji od nuly vytvorit nový doplněk `.newblk` pro ESP IDE.

---

## 1) Co je add-on v ESP IDE

Add-on je textovy soubor s priponou `.newblk`.

Obsahuje 2 casti oddelene JEDNIM delimiterem:

1. JavaScript cast (definice bloku + Python generatoru + pripadne callbacky)
2. XML fragment toolboxu (kategorie, bloky, tlacitka)

Delimiter je presne:

`<!toolbox!>`

Bez nej je soubor nevalidni a ESP IDE ho odmítne.

---

## 2) Jak ESP IDE nacita `.newblk` (realne chovani loaderu)

V `index.html` je import `.newblk` implementovan takto:

- kontrola: `raw.includes("<!toolbox!>")`
- split: `const [codeJS, toolboxXML=""] = raw.split("<!toolbox!>")`
- ulozeni do `extensions[baseName] = { js, xml, enabled, pin_defaults }`

Dulezite dusledky:

1. Loader pouziva `split("<!toolbox!>")`, ale bere jen prvni 2 casti.
2. Pokud je delimiter v souboru vicekrat, dalsi casti se zahodi.
3. Delimiter v komentarich/stringu muze rozbit parser.
4. Nazev extension je odvozen z NAZVU SOUBORU (`baseName`), ne z metadata `id`.

Proto je nutne drzet pravidlo: delimiter presne 1x.

---

## 3) Blockly verze a kompatibilita

ESP IDE bezi na Blockly:

- `Blockly.VERSION = "6.20210701.0"`

Kompatibilni styl definic:

- `Blockly.Blocks['my_type'] = { init: function() { ... } }`
- `Blockly.Python['my_type'] = function(block) { ... }`

Generovani MicroPythonu:

- statement blok vraci `string + "\\n"`
- value blok vraci `[code, Blockly.Python.ORDER_ATOMIC]`

---

## 4) Minimalni format souboru `.newblk`

### 4.1 Struktura

1. (Volitelne) metadata koment (JSONC-like) na zacatku
2. JS cast
3. delimiter `<!toolbox!>`
4. XML toolbox fragment (bez `<xml>...</xml>`)

### 4.2 Dulezita pravidla

- Nepouzivat delimiter nikde jinde.
- Kazdy `<block type="...">` v XML musi mit definici v JS.
- U bloku, ktere generuji kod, musi byt generator `Blockly.Python[...]`.
- JS cast se spousti pres `eval(jsSrc)`, musi byt runtime-valid.

---

## 5) Metadata hlavicka (doporučeno)

Loader umi nacist metadata z komentare `/* { ... } */` a z nich `pin_defaults`.

Podporovane jsou:

- `//` komentare v JSON (JSONC-like)
- trailing commas (odstranuji se parserem)

Doporucena sablona:

```js
/*
{
  "id": "my_addon_id",
  "name": "Muj addon",
  "description": "Co addon dela",
  "version": "1.0.0",
  "author": "Autor",
  "tags": ["sensor", "i2c"],
  "screenshots": ["preview.png"],
  "changelog": "v1.0.0 - prvni verze",
  "toolbox_mode": "addon_only",
  "pin_defaults": {
    "default": { "sda": 21, "scl": 22 },
    "ESP32C3": { "sda": 8, "scl": 9 },
    "ESP32S3": { "sda": 8, "scl": 9 },
    "RP2040": { "sda": 4, "scl": 5 }
  }
}
*/
```

Poznamky:

- `pin_defaults` lze i jako `by_processor` mapa.
- Processor key je case-insensitive fallback.
- Kdyz chybi konkretni processor, bere se `default`.
- `toolbox_mode: "addon_only"` prepne IDE do rezimu "jen bloky z doplnku".
- Alias: `toolbox_only: true`.

---

## 6) API dostupne v JS kodu doplňku

Add-on JS se evalnuje v IDE a ma pristup k globalnim objektum/funkcim.
Prakticky pouzitelne:

- `Blockly`
- `demoWorkspace` (Blockly workspace)
- `Swal` (SweetAlert2)
- `isEditorConnected()`
- `mp()` -> aktivni transport (USB/BLE)
- `delay(ms)`
- `term` (terminal output)

### 6.1 Nahrani souboru do zarizeni

Primy upload stringu:

```js
await mp().sendFile("lib/moje_knihovna.py", pyCodeString, false);
```

Upload souboru ze serveru:

```js
await sendFileToDevice("lib_ESP32/moje.py", "/lib");
```

Pozor:

- Pred uploadem kontroluj `isEditorConnected()`.
- Bezne se pouziva `mp().mute_terminal = true/false` pro vypnutí zobrazování dat v terminálu (komunikace na pozadí).
- Po uploadu je vhodne poslat `await mp().sendData('\r\n')`.

---

## 7) Blockly button v toolboxu (callbackKey)

Pokud v XML pouzijes:

```xml
<button text="Nahrat knihovnu" callbackKey="upload_lib_file_myaddon"></button>
```

MUSI existovat JS registrace:

```js
demoWorkspace.registerButtonCallback("upload_lib_file_myaddon", async function(button) {
  // ...
});
```

Jmeno callbacku se musi shodovat 1:1.

---

## 8) Pin defaults mapovani (jak funguje)

ESP IDE umi automaticky prepsat default piny v XML addonu podle procesoru.

Podporovane rezimy:

1. Preferovany (role marker):

```xml
<field name="NUM" data-pin-role="sda">21</field>
```

2. Fallback podle jmena value:

```xml
<value name="sda">
  <shadow type="math_number"><field name="NUM">21</field></shadow>
</value>
```

Doporuceni:

- Pouzivej `data-pin-role`.
- Jmena roli (pinu) drzet lowercase (`sda`, `scl`, `tx`, `rx`, ...).

---

## 9) Jak se add-ony ukladaji a aktivuji v IDE

Import `.newblk` souboru sam o sobe jen nacte extension do manageru.

Aby se propsal do toolboxu, je potreba ulozit vyber extension:

- tlacitko `Save changes` ve `Extensions manager`
- vola `applyExtensionSelection()`
- to zavola `integrateExtensions(agg_js, agg_xml)`
- JS addonu se `eval` spusti
- XML addonu se pripoji do toolboxu

Perzistence v localStorage:

- `extensions` (strukturovana data vsech extension)
- `new_blocks_js` (sloucene JS)
- `new_blocks_xml` (sloucene XML)

---

## 10) Sdileni projektu `.blk/.xml` s extension payload

ESP IDE umi exportovat Blockly projekt tak, ze dovnitr vlozi payload extension (base64 mezi komentari):

- `<!--ESPIDE_EXTENSIONS_BEGIN-->`
- `<!--ESPIDE_EXTENSIONS_END-->`

Pri importu projektu IDE umi:

1. z payloadu prepnout processor,
2. nacist potrebne extension,
3. teprve pak nacist workspace XML.

Diky tomu je projekt prenositelny i s add-ony.

---

## 11) Nejbeznejsi chyby

1. Chybi delimiter nebo je vicekrat.
2. XML cast obsahuje `<xml>...</xml>` wrapper (ma byt jen fragment).
3. V XML je block type, ktery neni definovan v JS.
4. Chybi Python generator k bloku, ktery ma generovat kod.
5. `callbackKey` v XML bez odpovidajiciho `registerButtonCallback`.
6. Typy bloku se skladaji dynamicky a regex je nezachyti.
7. V JS je syntax/runtime chyba, `eval` spadne a toolbox se neprida.

---

## 12) Doporuceny naming convention

Pouzij konzistentni prefix addonu, napr. `aht_`, `filt_`, `oled_`:

- `filt_init_ema`
- `filt_init_sma`
- `filt_process`

Stejne pro pomocne symboly:

- `function filt_addLibrary() { ... }`
- `Blockly.Python.definitions_['filt_library'] = ...`

---

## 13) Priklad A: Minimalni validni `.newblk`

```text
/*
{
  "id": "demo_minimal",
  "name": "Demo Minimal",
  "description": "Nejmensi funkcni addon",
  "version": "1.0.0",
  "author": "ESP IDE User"
}
*/

Blockly.Blocks['demo_hello'] = {
  init: function() {
    this.appendDummyInput().appendField('hello hodnota');
    this.setOutput(true, 'Number');
    this.setColour('#3f51b5');
    this.setTooltip('Vrati cislo 42.');
    this.setHelpUrl('');
  }
};

Blockly.Python['demo_hello'] = function(block) {
  return ['42', Blockly.Python.ORDER_ATOMIC];
};

<!toolbox!>

<category name="Demo" colour="#3f51b5">
  <block type="demo_hello"></block>
</category>
```

---

## 14) Priklad B: Add-on s upload tlacitkem knihovny do /lib

```text
/*
{
  "id": "demo_with_upload",
  "name": "Demo Upload",
  "description": "Ukazuje button callback a upload knihovny",
  "version": "1.0.0",
  "author": "ESP IDE User"
}
*/

var demo_upload_lib_py = `
class DemoLib:
    def hello(self):
        return 123
`;

demoWorkspace.registerButtonCallback("upload_lib_file_demo_upload", async function(button) {
  if (!isEditorConnected()) {
    Swal.fire("Chyba", "Zarizeni neni pripojeno.", "error");
    return;
  }

  try {
    mp().mute_terminal = true;
    term.writeln("Nahravam soubor: demo_lib.py");
    await delay(50);

    await mp().sendFile("lib/demo_lib.py", demo_upload_lib_py, false);
    await delay(250);
    await mp().sendData('\r\n');
    await delay(250);
    mp().mute_terminal = false;

    Swal.fire("Hotovo", "Knihovna byla nahrana.", "success");
  } catch (e) {
    try { mp().mute_terminal = false; } catch (_) {}
    Swal.fire("Chyba", String(e && e.message || e), "error");
  }
});

Blockly.Blocks['demo_use_lib'] = {
  init: function() {
    this.appendDummyInput().appendField('Demo knihovna hello');
    this.setOutput(true, 'Number');
    this.setColour('#00897b');
    this.setTooltip('Vrati hodnotu z knihovny demo_lib.py');
    this.setHelpUrl('');
  }
};

Blockly.Python['demo_use_lib'] = function(block) {
  Blockly.Python.definitions_['import_demo_lib'] = 'import demo_lib';
  Blockly.Python.definitions_['init_demo_lib_obj'] = 'demo_lib_obj = demo_lib.DemoLib()';
  return ['demo_lib_obj.hello()', Blockly.Python.ORDER_ATOMIC];
};

<!toolbox!>

<category name="Demo Upload" colour="#00897b">
  <label text="Nejdrive nahraj knihovnu do /lib"></label>
  <button text="Nahrat knihovnu" callbackKey="upload_lib_file_demo_upload"></button>
  <block type="demo_use_lib"></block>
</category>
```

---

## 15) Priklad C: Add-on s pin_defaults

```text
/*
{
  "id": "demo_pin_defaults",
  "name": "Demo PIN defaults",
  "description": "Ukazka data-pin-role mapovani",
  "version": "1.0.0",
  "author": "ESP IDE User",
  "pin_defaults": {
    "default": { "sda": 21, "scl": 22 },
    "ESP32C3": { "sda": 8, "scl": 9 },
    "ESP32S3": { "sda": 8, "scl": 9 },
    "RP2040": { "sda": 4, "scl": 5 }
  }
}
*/

Blockly.Blocks['demo_i2c_init'] = {
  init: function() {
    this.appendDummyInput().appendField('I2C init');
    this.appendValueInput('sda').setCheck('Number').appendField('SDA');
    this.appendValueInput('scl').setCheck('Number').appendField('SCL');
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour('#0097a7');
    this.setTooltip('Vytvori SoftI2C.');
    this.setHelpUrl('');
  }
};

Blockly.Python['demo_i2c_init'] = function(block) {
  Blockly.Python.definitions_['import_pin'] = 'from machine import Pin';
  Blockly.Python.definitions_['import_softi2c'] = 'from machine import SoftI2C';
  var sda = Blockly.Python.valueToCode(block, 'sda', Blockly.Python.ORDER_ATOMIC) || '21';
  var scl = Blockly.Python.valueToCode(block, 'scl', Blockly.Python.ORDER_ATOMIC) || '22';
  return 'i2c = SoftI2C(sda=Pin(' + sda + '), scl=Pin(' + scl + '), freq=400000)\\n';
};

<!toolbox!>

<category name="Demo I2C" colour="#0097a7">
  <block type="demo_i2c_init">
    <value name="sda"><shadow type="math_number"><field name="NUM" data-pin-role="sda">21</field></shadow></value>
    <value name="scl"><shadow type="math_number"><field name="NUM" data-pin-role="scl">22</field></shadow></value>
  </block>
</category>
```

---

## 16) Univerzalni "MEGA" prompt pro AI (dopln vsechny placeholdery)

Nasledujici prompt je navrzen tak, aby fungoval i pro AI bez znalosti ESP IDE. Je zamerne self-contained a obsahuje i technicke detaily, ktere by jinak byly roztrousene jen v dokumentaci:

```text
Jsi senior vyvojar doplnku pro ESP IDE (Blockly 6.20210701.0 + MicroPython).

CIL:
Vytvor 1 kompletni soubor OUTPUT_FILENAME.newblk, ktery je primo importovatelny v ESP IDE.

CO JE SOUBOR .newblk:
- .newblk je textovy add-on soubor pro ESP IDE.
- V jednom souboru kombinuje: metadata, JavaScript definice bloku, Blockly.Python generatory a XML toolbox fragment.
- Soubor musi obsahovat presne jeden delimiter:
  <!toolbox!>
- Realny loader dela kontrolu raw.includes("<!toolbox!>") a pak split raw.split("<!toolbox!>").
- Loader si vezme jen prvni 2 casti: [JS, XML]. Pokud je delimiter vicekrat, dalsi casti se ztrati.
- Delimiter proto nepouzivej nikde jinde, ani v komentari, ani ve stringu.
- Nazev extension v IDE je odvozen z nazvu souboru (baseName), ne z metadata "id".
- Po importu se add-on jen nacte do Extensions manageru. Aby se projevil v toolboxu, uzivatel musi kliknout na Save changes.

BLOCKLY A GENERATORY:
- Blockly verze je 6.20210701.0.
- Bloky definuj pouze stylem Blockly.Blocks['literal_type'] = { init: function() { ... } }.
- Python generatory definuj pouze stylem Blockly.Python['literal_type'] = function(block) { ... }.
- Nepouzivej dynamicky skladane nazvy block type. IDE je detekuje regexem z JS, takze pouzivej explicitni string literal.
- Statement blok vracej jako string s koncovym \n.
- Value blok vracej jako [code, Blockly.Python.ORDER_ATOMIC], pripadne jiny vedome zvoleny Blockly.Python.ORDER_*.
- Importy a pomocny Python kod vkladej do Blockly.Python.definitions_.
- Kazdy <block type="..."> v XML musi mit odpovidajici Blockly.Blocks['...'] v JS.
- Kazdy blok, ktery generuje MicroPython, musi mit odpovidajici Blockly.Python['...'].
- JS cast se spousti pres eval(jsSrc), takze nesmi obsahovat syntax chybu ani runtime chybu pri nacitani.

METADATA HLAVICKA:
- Na zacatek souboru dej blokovy komentar ve tvaru:
  /*
  {
    ...
  }
  */
- Parser umi JSONC-like format: toleruje // komentare a trailing commas. I tak pis metadata co nejbliz validnimu JSON.
- Vypln minimalne:
  id, name, description, version, author
- Doporucene polozky:
  tags, screenshots, changelog, pin_defaults, toolbox_mode
- id musi byt stabilni, unikatni, bez mezer a bez diakritiky, idealne lowercase ASCII.
- Pokud jde o novou verzi stejneho add-onu, zachovej stejne id a men jen version + changelog.

VOLITELNE REZIMY TOOLBOXU:
- Pokud ma add-on fungovat jako samostatna sada bloku, muzes pouzit:
  "toolbox_mode": "addon_only"
- Podporovany alias je i:
  "toolbox_only": true
- Loader umi rozpoznat i aliasy jako addon_only, toolbox_only nebo exclusive, ale pro vystup preferuj presne "toolbox_mode": "addon_only" nebo "toolbox_only": true.
- Tento rezim pouzij jen kdyz je to opravdu zamysleny samostatny toolbox. Pro bezny doplnek ho nech vypnuty.

PIN_DEFAULTS:
- Pokud add-on pracuje s piny, pridej do metadat pin_defaults.
- Podporovany format je bud primo mapa procesoru:
  "pin_defaults": {
    "default": { ... },
    "ESP32": { ... },
    "ESP32C3": { ... },
    "ESP32S3": { ... },
    "RP2040": { ... }
  }
- Nebo varianta s obalem by_processor:
  "pin_defaults": {
    "by_processor": {
      "default": { ... },
      "ESP32": { ... },
      "ESP32C3": { ... },
      "ESP32S3": { ... },
      "RP2040": { ... }
    }
  }
- Vnitrni mapy musi mit role pinu jako lowercase klice bez mezer.
- Hodnoty pinu musi byt cisla.
- IDE hleda nejdriv presnou shodu procesoru, pak case-insensitive shodu, a nakonec fallback default nebo DEFAULT.
- Proto je velmi vhodne vzdy vyplnit default.
- Drz naprosto stejne nazvy roli v pin_defaults i v XML.
- Bezne role jsou napriklad: i2c_sda, i2c_scl, miso, mosi, sck, cs, rx, tx, sda, scl.

XML TOOLBOX FRAGMENT:
- Za delimiterem musi byt XML fragment bez <xml>...</xml> wrapperu.
- Pouzivej dobre formovane XML.
- Bezne elementy jsou: <category>, <block>, <label>, <button>, <value>, <shadow>, <field>.
- Pro vychozi hodnoty pouzivej shadow bloky, typicky math_number.
- Vystup musi obsahovat alespon 1 kategorii.
- Typy v XML musi 1:1 odpovidat definicim v JS.
- Texty category, label, button a tooltipy prizpusob UI_LANGUAGE a AUDIENCE.

PINY V XML:
- Preferovany zpusob mapovani pinu je oznaceni konkretniho numeric field atributem data-pin-role:
  <field name="NUM" data-pin-role="i2c_sda">21</field>
- Fallback kompatibilni heuristika je value node se stejnym jmenem role:
  <value name="i2c_sda">
    <shadow type="math_number">
      <field name="NUM">21</field>
    </shadow>
  </value>
- Nejbezpecnejsi je pouzit konzistentne value name i data-pin-role.
- Pokud add-on pouziva pin_defaults, oznac vsechna relevantni pole atributem data-pin-role.

TOOLBOX BUTTON CALLBACKY:
- Pokud v XML pouzijes:
  <button text="..." callbackKey="nejaky_klic"></button>
  musi v JS existovat presne:
  demoWorkspace.registerButtonCallback("nejaky_klic", async function(button) { ... });
- callbackKey se musi shodovat 1:1.
- Pouzivej unikatni callbacky s prefixem add-onu, napriklad upload_lib_file_TYPE_PREFIX.
- Pokud je v XML button bez odpovidajici registrace, je to chyba.

API DOSTUPNE V JS DOPLNKU:
- Blockly
- demoWorkspace
- Swal
- isEditorConnected()
- mp()
- delay(ms)
- term
- sendFileToDevice(fileUrl, targetFolder)
- JS kod nesmi prepisovat globalni IDE objekty.

KDY POUZIT IMPORTY VS. UPLOAD KNIHOVNY:
- Kdyz je pomocny Python kod kratky nebo jednorazovy, vloz ho do Blockly.Python.definitions_.
- Kdyz je kod delsi, znovupouzitelny nebo ma byt ulozen v /lib/*.py, vytvor button + callback a nahraj knihovnu do zarizeni.
- Pri upload callbacku dodrz tento styl:
  1) over isEditorConnected()
  2) nastav mp().mute_terminal = true
  3) vypis informaci do term
  4) nahraj soubor pres mp().sendFile("lib/xxx.py", pyCodeString, false) nebo sendFileToDevice("server_path.py", "/lib")
  5) po uploadu posli await mp().sendData('\r\n')
  6) v try/catch vzdy obnov mp().mute_terminal = false i pri chybe
  7) uzivatelskou chybu hlas pres Swal.fire(...)

DOPORUCENY NAMING:
- Vsechny block type, callbacky, helpery a Python definitions pojmenuj konzistentnim prefixem TYPE_PREFIX.
- Priklady:
  TYPE_PREFIX_init
  TYPE_PREFIX_read
  upload_lib_file_TYPE_PREFIX
  Blockly.Python.definitions_['import_TYPE_PREFIX']

TEXTY A UX:
- Nazvy bloku a tooltipy prizpusob publiku AUDIENCE.
- Pro deti a zacatecniky pouzivej jednoduche vety, mene technickeho slangu a defaulty, ktere fungují hned.
- I pro pokrocilejsi publikum pis kratke a srozumitelne texty.
- Nepridavej zbytecne prepinace a dropdowny, pokud nejsou nutne.

VSTUPNI PARAMETRY:
- ADDON_NAME: {{ADDON_NAME}}
- ADDON_ID: {{ADDON_ID}}
- TYPE_PREFIX: {{TYPE_PREFIX}}
- DESCRIPTION: {{DESCRIPTION}}
- AUTHOR: {{AUTHOR}}
- TARGET_BOARDS: {{TARGET_BOARDS}}
- UI_LANGUAGE: {{UI_LANGUAGE}}
- AUDIENCE: {{AUDIENCE}}
- NEED_UPLOAD_BUTTON: {{YES_NO}}
- TOOLBOX_MODE: {{NORMAL_OR_ADDON_ONLY}}
- OUTPUT_FILENAME: {{OUTPUT_FILENAME}}.newblk
- OUTPUT_PATH: {{OUTPUT_PATH}}

POVINNA STRUKTURA VYSTUPU:
1) Metadata hlavicka v blokovem komentari
2) JavaScript cast:
   - helper funkce
   - Blockly.Blocks['...']
   - Blockly.Python['...']
   - pripadne demoWorkspace.registerButtonCallback(...)
3) Presne jeden delimiter
   <!toolbox!>
4) XML toolbox fragment bez <xml> rootu

POVINNA KOSTRA SOUBORU:
/*
{
  "id": "ADDON_ID",
  "name": "ADDON_NAME",
  "description": "DESCRIPTION",
  "version": "1.0.0",
  "author": "AUTHOR",
  "tags": ["TYPE_PREFIX"],
  "screenshots": [],
  "changelog": "v1.0.0 - initial version"
}
*/

... JavaScript cast ...

<!toolbox!>

<category name="ADDON_NAME" colour="#00979d">
  ...
</category>

LOGIKA ROZHODNUTI:
- Kdyz NEED_UPLOAD_BUTTON = YES, vytvor funkcni <button> + registerButtonCallback + upload flow.
- Kdyz add-on potrebuje ruzne defaultni piny podle TARGET_BOARDS, vypln pin_defaults a pouzij data-pin-role.
- Kdyz ma add-on fungovat jako samostatna sada bloku, nastav TOOLBOX_MODE na addon_only. Jinak toolbox_mode nepouzivej.
- Kdyz blok vraci hodnotu, udelej output block. Kdyz provadi akci, udelej statement block.
- Kdyz je potreba knihovna v /lib, generator ma vygenerovat import pouzivajici tento soubor.

NEJCASTEJSI CHYBY, KTERYM SE MUSIS VYHNOUT:
1) Delimiter <!toolbox!> chybi nebo je vicekrat.
2) Delimiter je uvnitr stringu nebo komentare.
3) XML cast obsahuje <xml> root.
4) V XML je block type, ktery neni definovan v JS.
5) Blok generuje kod, ale chybi Blockly.Python.
6) callbackKey v XML neodpovida registerButtonCallback.
7) id koliduje s jinym add-onem nebo obsahuje mezery/diakritiku.
8) pin_defaults role se neshoduji s data-pin-role.
9) Typy bloku jsou skladane dynamicky a loader je regexem nezachyti.
10) JS ma syntax chybu nebo runtime chybu pri eval.
11) Uzivatel po importu musi kliknout na Save changes; proto add-on navrhni tak, aby byl po aktivaci ihned pouzitelny.

POVINNY SELF-CHECK PRED ODEVZDANIM:
1) Soubor ma priponu .newblk a obsahuje presne 1x <!toolbox!>.
2) Metadata jsou na zacatku v blokovem komentari a jsou co nejbliz validnimu JSON.
3) Kazdy <block type="..."> z XML existuje v Blockly.Blocks['...'].
4) Kazdy blok, ktery ma generovat MicroPython, ma Blockly.Python['...'].
5) XML fragment nema <xml> wrapper.
6) Pokud je button, callbackKey == registerButtonCallback key.
7) Pokud jsou piny, role v pin_defaults presne odpovidaji data-pin-role a/nebo value name.
8) Block types jsou explicitni string literal, ne dynamicky skladane.
9) Statement generatory konci \n.
10) Value generatory vraceji [code, Blockly.Python.ORDER_ATOMIC] nebo jiny vedome zvoleny ORDER.
11) JS je eval-safe a neprepise globalni IDE objekty.
12) Pokud je upload callback, try/catch vraci mp().mute_terminal do false i pri chybe.

VYSTUP:
- Pokud je zadana OUTPUT_PATH, priprav soubor pro ulozeni do OUTPUT_PATH/OUTPUT_FILENAME.newblk.
- Vrat pouze finalni RAW obsah .newblk souboru.
- Bez markdownu.
- Bez vysvetleni okolo.
- Bez dalsich komentaru mimo obsah souboru.
```

---

## 17) Kratka operational check-list (pro cloveka)

Pred importem add-onu rychle over:

1. Soubor ma priponu `.newblk`.
2. Obsahuje presne 1x `<!toolbox!>`.
3. XML cast nema `<xml>` wrapper.
4. Vsechny `type` z XML existuji v `Blockly.Blocks[...]`.
5. Vsechny kodove bloky maji `Blockly.Python[...]`.
6. Pokud je v XML `<button callbackKey>`, callback je registrovany.
7. Nejsou unclosed stringy/zavorky.

---

## 18) Poznamka k detskym/zakovskym addonum

Pro cilovku ZS doporuceno:

- 1 koncept = 1 blok (mene prepinacu, mene dropdownu)
- vysvetleni primo v nazvu bloku
- tooltip jako jednoducha veta
- default hodnoty "ktere funguji hned"
- kratke texty bez technickeho slangu

Priklad:

- misto: `alpha`
- pouzij: `alpha (0 = hodne hladke, 1 = rychla reakce)`

---

## 19) Doplnujici tipy pro robustnost

- V generatoru radeji osetri fallbacky (`|| '0'`).
- U statement generatoru vzdy ukoncuj radek `\n`.
- Nepouzivej stejne nazvy pro block type a lokalni JS promenne.
- Pro knihovny v `/lib` drz kratke ASCII nazvy souboru.
- Pri upload callbacku delej `try/catch` a obnov `mp().mute_terminal` i pri chybe.

---

## 20) Konec dokumentu

Tento dokument je navrzen jako kompletni referencni manual i prompt template.
Je mozne jej primo zkopirovat do jine AI jako jedine zadani.
