# Lucarne

Interfaces pour petits écrans SPI (ST7789, ST7735S) sur Arduino et ESP32. Dessinez dans Studio, exportez du C++, flashez.

UIs for small SPI displays (ST7789, ST7735S) on Arduino and ESP32. Design in Studio, export C++, flash.

## En bref

## In short

1. Installer la lib Install the library Copiez Lucarne dans `Arduino/libraries`. Copy Lucarne to `Arduino/libraries`.
2. Ouvrir Studio Open Studio `editor/index.html` — bientôt aussi en ligne. `editor/index.html` — hosted version coming.
3. Exporter & flasher Export & flash Export .h → copier à côté du .ino → compiler. Export .h → copy next to .ino → build.

# Installation

Librairie firmware + éditeur web (aucun npm requis).

Firmware library + web editor (no npm required).

### Arduino IDE

Dossier du repo → `Documents/Arduino/libraries/Lucarne`

Repo folder → `Documents/Arduino/libraries/Lucarne`

### PlatformIO

`lib/Lucarne/` ou or `lib_deps`

### Lucarne Studio

Servez `editor/` (Live Server, `python -m http.server`…) et ouvrez `index.html`. Le projet se sauvegarde dans le navigateur ; Save / Load pour un fichier `.lucarne.json`.

Serve `editor/` (Live Server, `python -m http.server`…) and open `index.html`. Project auto-saves in the browser; Save / Load for a `.lucarne.json` file.

## Sans Studio (code direct)

## Without Studio (code only)

    #include <Lucarne.h>
    using namespace lucarne;
    ST7789 display;

    void setup() {
      DisplayPins pins;
      pins.cs = 1; pins.dc = 2; pins.rst = 3;
      pins.mosi = 4; pins.sclk = 5;
      DisplayOptions opt;
      opt.panelWidth = 240; opt.panelHeight = 280;
      opt.spiMode = 3; opt.invert = true;
      BufferOptions buf; buf.mode = BufferMode::Full;
      display.begin(pins, opt, buf);
      display.fillScreen(0);
      display.print("Hello");
      display.display();
    }

`BufferMode::Full` = framebuffer en RAM, transitions animées possibles. None = dessin direct, pas d'animation.
`BufferMode::Full` = RAM framebuffer, animated transitions. None = direct draw, no animation.

# Lucarne Studio

Éditeur visuel : blueprint → designer → simulate → export.

Visual editor: blueprint → designer → simulate → export.

Vue d'ensemble : blueprint, réglages écran et inspecteur projet.Overview: blueprint, display settings and project inspector.

1. Blueprint Ajoutez des écrans (+ Screen). Reliez les entrées de menu d'un écran à un autre en tirant un lien. Double-clic = ouvrir le designer. Add screens (+ Screen). Drag menu item links between screens. Double-click = open designer.
2. Designer Placez widgets (palette à gauche), déplacez, redimensionnez. Templates prêts à l'emploi. Calques = ordre d'affichage. Place widgets (left palette), move, resize. Ready-made templates. Layers = draw order.
3. Onglets droits Right tabs Theme couleurs · Fonts polices · Assets images/icônes · Data clés (temp, wifi…) Theme colors · Fonts · Assets images/icons · Data keys (temp, wifi…)
4. Simulate Flèches ou pad = menu. Clic sur boutons/switches. Teste les transitions. Arrows or pad = menu. Click buttons/switches. Tests transitions.

## Barre du haut

## Top bar

Élément Item | Rôle Role
--- | ---
Device | Modèle d'écran et résolution (240×280, 128×128…)Panel preset and resolution (240×280, 128×128…)
Rotation | Orientation logique 0° à 270°Logical orientation 0° to 270°
Live | Connexion USB pour aperçu sur carte réelle USB connection for on-device preview
Export .h | Génère les headers C++ du projet Generates project C++ headers
Save / Load | Fichier projet `.lucarne.json` Project file `.lucarne.json`

Blueprint : écrans, liens de menu et écran START.Blueprint: screens, menu links and START screen.
Designer : palette widgets, canvas et calques.Designer: widget palette, canvas and layers.

# Export Arduino

# Arduino export

Studio génère le UI ; vous gardez le câblage SPI dans le .ino.

Studio generates the UI; you keep SPI wiring in the .ino.

1. Export .h dans Studio → copier ou télécharger. in Studio → copy or download.
2. Projet.h (+ éventuellement Projet_fonts.h, Projet_images.h, Projet_icons.h) à côté du .ino.Projet.h (+ optional Projet_fonts.h, Projet_images.h, Projet_icons.h) next to .ino.
3. Câblez le display dans `setup()` — l'export ne connaît pas vos broches.Wire the display in `setup()` — export does not know your pins.

    #include <Lucarne.h>
    #include "Projet.h"
    using namespace lucarne;
    ST7789 display;
    UI ui(display);

    void setup() {
      // vos broches SPI ici
      display.begin(pins, options, buffer);
      projet::build(ui);
      projet::attachInput(ui);
      ui.begin();
    }

    void loop() {
      projet::update();
      ui.setFloat("temp", readSensor());
      ui.update();
      switch (ui.pollMenuAction()) {
        case projet::ACTION_OPEN_SETTINGS: break;
      }
    }

## Entrées (menu sur un écran)

## Input (screen with menu)

Inspecteur projet : Buttons (haut/bas/OK/retour), Encoder (A/B/btn), ou Touch → vous appelez `projet::input.feed(x,y,pressed)` au lieu de `projet::update()`.

Project inspector: Buttons (up/down/OK/back), Encoder (A/B/btn), or Touch → call `projet::input.feed(x,y,pressed)` instead of `projet::update()`.

## Callbacks menu / bouton

## Menu / button callbacks

Dans Studio, action « Callback » + un ID → constante `projet::ACTION_MON_ID` dans Projet.h. Lisez-la dans `loop()` avec `ui.pollMenuAction()`.

In Studio, action « Callback » + an ID → `projet::ACTION_MY_ID` in Projet.h. Read it in `loop()` with `ui.pollMenuAction()`.

Après chaque changement dans Studio : régénérez les .h. Votre .ino ne change pas.
After each Studio change: regenerate .h files. Your .ino stays the same.
Export .h : aperçu, copie ou téléchargement des headers.Export .h: preview, copy or download headers.

# Widgets

Ajoutez-les dans le Designer ou en C++. Liez les valeurs via l'onglet Data (`ui.setFloat("temp", …)`).

Add in Designer or C++. Bind values via Data tab (`ui.setFloat("temp", …)`).

Label

Texte fixe.

Static text.

    Label(x, y, "Hello", TextAlign::Center);

Metric

Étiquette + valeur (float/int/bool/string).

Label + live value.

    Metric(x,y,w,h, "Temp", "temp", "C");

Bar

    Bar(x,y,w,h, "level", 0, 100);

Icon

Réf. string : `"wifi"`, `"tabler:settings"`, `"c:myicon"`

String ref: `"wifi"`, `"tabler:settings"`, `"c:myicon"`

    Icon(x, y, "chart", 1);

Image

    Image(x,y,w,h, &Img_photo);

Menu

Navigation ou callback. Jusqu'à 16 items.

Navigate or callback. Up to 16 items.

    menu.addItem("Home", "home", &screen);
    menu.addCallbackItem("Off", "power", ACTION_ID);

Button

Touch : navigation ou callback.

Touch: navigate or callback.

    Button(x,y,w,h, "Start");
    btn.setNavigate(&screen);
    btn.setCallback(ACTION_ID);

Switch

Clé bool, touch pour basculer.

Bool key, touch to toggle.

    Switch(x,y,w,h, "Wi-Fi", "wifi");

Slider

Affiche une valeur float (pas de drag firmware).

Shows float value (no firmware drag).

    Slider(x,y,w,h, "brightness", 0, 100);

Chart

Courbe, 2 à 8 clés float.

Sparkline, 2–8 float keys.

    chart.setKey(0, "temp");
    chart.setKey(1, "hum");

Gauge

    Gauge(x,y,w,h, "Speed", "speed", 0, 100);

List

Liste statique (12 items max).

Static list (12 items max).

    list.addItem("Settings");

## Icônes intégrées

## Built-in icons

`home settings wifi bluetooth battery thermo drop fan bell chart power sun lock check cross arrow_up arrow_down arrow_left arrow_right play pause plus minus`

Assets → icônes : packs Streamline, Tabler, recherche et export embarqué.Assets → icons: Streamline, Tabler packs, search and embedded export.

## Transitions

`SlideLeft, Fade, Push…` — nécessitent `BufferMode::Full`. `back()` inverse les slides. Splash : écran START + durée dans l'inspecteur nœud.

`SlideLeft, Fade, Push…` — need `BufferMode::Full`. `back()` reverses slides. Splash: START screen + duration in node inspector.

# Câblage

# Wiring

Écran SPI + entrées optionnelles.

SPI display + optional inputs.

## Écran SPI

## SPI display

Signal | Pin
--- | ---
SCLK | `pins.sclk`
MOSI | `pins.mosi`
CS / DC / RST | `pins.cs, dc, rst`
Backlight | `pins.bl` (-1 si fixe)

    options.spiMode = 3;    // souvent requis ST7789
    options.invert = true;  // couleurs correctes

Écran noir ? Essayez spiMode 3. Couleurs bizarres ? invert ou ColorOrder RGB/BGR.
Black screen? Try spiMode 3. Wrong colors? invert or ColorOrder RGB/BGR.

## Boutons

## Buttons

Vers GND, pull-up interne. Haut/bas = menu, OK = valider, retour = back.

To GND, internal pull-up. Up/down = menu, OK = select, back = back.

## Encodeur

## Encoder

Tourner = haut/bas. Clic court = OK. Clic long = back.

Rotate = up/down. Short click = OK. Long press = back.

## Tactile

## Touch

Votre pilote appelle `touch.feed(x, y, pressed)`. Menu = sélection ; hors menu = boutons/switches.

Your driver calls `touch.feed(x, y, pressed)`. Menu = select; elsewhere = buttons/switches.

# Live Preview

Voir le design sur la vraie carte en USB — sans reflasher à chaque changement de widget.

See the design on real hardware over USB — no reflash per widget change.

1. Flasher Flash `examples/LucarnePreview/LucarnePreview.ino` — ESP32-S3 : USB CDC On Boot activé. Pas de Serial.print. — ESP32-S3: USB CDC On Boot on. No Serial.print.
2. Connecter Connect
   Chrome/Edge : bouton Live dans la barre du haut → choisir le port. Fermez le moniteur série Arduino. Chrome/Edge: Live button in the top bar → pick the port. Close the Arduino serial monitor.
3. Designer ou Simulate Designer or Simulate = ce qui s'affiche sur l'écran. = what appears on the panel.

# Polices & exemples

# Fonts & examples

## Polices

## Fonts

Inclus : `LucarneFontBody` et `LucarneFontTitle` (Fira Sans, anti-aliasé). Studio → Fonts : Google ou TTF → assigner dans Theme → export `Projet_fonts.h`.

Included: `LucarneFontBody` and `LucarneFontTitle` (Fira Sans, anti-aliased). Studio → Fonts: Google or TTF → assign in Theme → exports `Projet_fonts.h`.

Onglet Theme : palette, radius/padding et polices body/title.Theme tab: palette, radius/padding and body/title fonts.

## Exemples Arduino

## Arduino examples

Sketch | Usage Purpose
--- | ---
`HelloLucarne` | Gfx bas niveau, sans UI runtime Low-level Gfx, no UI runtime
`LucarneUI` | Dashboard Metric/Bar et liaison de données Dashboard Metric/Bar and data binding
`LucarneMenu` | Menus multi-écrans, transitions, callbacks Multi-screen menus, transitions, callbacks
`LucarnePreview` | Récepteur Live Preview USB USB Live Preview receiver
`LucarneDiag` | Test plein écran rouge/vert/bleu Full-screen red/green/blue test

# API

Référence C++ Lucarne : namespace `lucarne`, classes UI/display, widgets, export `projet`.

Lucarne C++ reference: `lucarne` namespace, UI/display classes, widgets, `projet` export.

## Namespace lucarne

## lucarne namespace

`namespace lucarne`

Toute la bibliothèque vit dans ce namespace. Dans un croquis : `using namespace lucarne;` ou préfixer `lucarne::`.

The whole library lives in this namespace. In a sketch: `using namespace lucarne;` or prefix `lucarne::`.

`uint16_t color565(r, g, b)`

Convertit RGB 8 bits en couleur 565 pour l'affichage.

Converts 8-bit RGB to 565 display color.

`BufferMode::Full` / `BufferMode::None`

Full : framebuffer en RAM, transitions animées. None : dessin direct, pas d'animation.

Full: RAM framebuffer, animated transitions. None: direct draw, no animation.

`Transition`

Enum : `None, SlideLeft, SlideRight, SlideUp, SlideDown, Fade, Push, Cover, Inherit`. Passé à `UI::navigate` ou défini par défaut via `setTransition`.

Enum: `None, SlideLeft, SlideRight, SlideUp, SlideDown, Fade, Push, Cover, Inherit`. Passed to `UI::navigate` or default via `setTransition`.

## Classe UI

## UI class

`class UI`

Moteur de navigation, rendu des écrans, store de données, menus et transitions. Constructeur : `UI(Display &display)`.

Navigation engine, screen rendering, data store, menus and transitions. Constructor: `UI(Display &display)`.

`void UI::begin()`

Initialise l'UI après `projet::build` et le câblage display. Affiche l'écran START ou le premier écran.

Initializes UI after `projet::build` and display wiring. Shows START screen or first screen.

`void UI::update()`

Rafraîchit l'affichage si nécessaire (widgets liés au store, splash, transition).

Refreshes display when needed (store-bound widgets, splash, transition).

`void UI::setFloat(const char *key, float v)`

Met à jour une clé float du store (Metric, Bar, Chart, Gauge, Slider…). Clé définie dans Studio → onglet Data.

Updates a float store key (Metric, Bar, Chart, Gauge, Slider…). Key defined in Studio → Data tab.

`void UI::setInt / setBool / setString`

Autres types pour le même store : entier, booléen, chaîne (24 car. max).

Other store types: integer, boolean, string (24 char max).

`uint8_t UI::pollMenuAction()`

Retourne l'ID callback du dernier item menu/bouton touch (0 si aucun). Constantes `projet::ACTION_*` générées par Studio.

Returns callback ID from last menu/touch button item (0 if none). `projet::ACTION_*` constants generated by Studio.

`void UI::show(Screen *screen)`

Remplace l'écran courant sans empiler (pas de retour arrière).

Replaces current screen without stack (no back navigation).

`void UI::navigate(Screen *, Transition)`

Change d'écran avec transition. Empile l'écran précédent pour `back()`.

Changes screen with transition. Pushes previous screen for `back()`.

`void UI::back()`

Revient à l'écran empilé. Inverse les transitions slide si configurées.

Returns to stacked screen. Reverses slide transitions when configured.

`void UI::next() / prev() / select()`

Contrôle menu actif : item suivant, précédent, validation. Utilisé par les entrées boutons/encodeur.

Active menu control: next item, previous, confirm. Used by button/encoder inputs.

`void UI::activateAt(int16_t x, int16_t y)`

Simule un touch aux coordonnées : sélection menu ou activation Button/Switch.

Simulates touch at coordinates: menu select or Button/Switch activation.

`void UI::setTheme(const Theme &)`

Applique couleurs et polices du thème exporté.

Applies exported theme colors and fonts.

`void UI::setTransition(Transition, uint16_t ms)`

Transition par défaut et durée (ms) entre écrans.

Default transition and duration (ms) between screens.

`void UI::setSplash(Screen *, uint16_t ms, bool progress)`

Écran splash au démarrage avec durée et barre de progression optionnelle.

Splash screen at boot with duration and optional progress bar.

## Display

`class Display` · `ST7789` · `ST7735S`

Pilote SPI + primitives Gfx. Instanciez `ST7789` ou `ST7735S` selon votre panneau.

SPI driver + Gfx primitives. Instantiate `ST7789` or `ST7735S` for your panel.

`bool Display::begin(pins, options, buffer, spi)`

Initialise SPI, panneau et buffer. À appeler dans `setup()` avec vos broches.

Initializes SPI, panel and buffer. Call in `setup()` with your pins.

`void Display::display()`

Envoie le framebuffer vers l'écran (mode buffer) ou flush les dirty regions.

Pushes framebuffer to panel (buffer mode) or flushes dirty regions.

`void Display::setRotation(uint8_t r)`

Rotation logique 0–3 (0°, 90°, 180°, 270°).

Logical rotation 0–3 (0°, 90°, 180°, 270°).

## Store & Screen

`class Store`

32 clés max, types float/int/bool/string. Accès direct via `ui.store()` si besoin.

32 keys max, float/int/bool/string types. Direct access via `ui.store()` if needed.

`class Screen`

Conteneur de widgets. `add(Widget *)`, `draw()`. Généré par l'export Studio (`projet::screen_*`).

Widget container. `add(Widget *)`, `draw()`. Generated by Studio export (`projet::screen_*`).

`class Widget`

Base abstraite : position, taille, `draw(Gfx, Theme, Store)`. Sous-classes Label, Metric, Menu…

Abstract base: position, size, `draw(Gfx, Theme, Store)`. Subclasses Label, Metric, Menu…

## Export projet

## projet export

`namespace projet`

Code généré dans `Projet.h` : écrans, widgets, constantes ACTION_*, helpers d'entrée.

Generated code in `Projet.h`: screens, widgets, ACTION_* constants, input helpers.

`void projet::build(UI &ui)`

Construit tous les écrans/widgets et les enregistre dans l'UI. Appeler une fois dans `setup()`.

Builds all screens/widgets and registers them in UI. Call once in `setup()`.

`void projet::attachInput(UI &ui)`

Lie l'entrée configurée dans Studio (boutons, encodeur ou touch) à l'UI.

Attaches input configured in Studio (buttons, encoder or touch) to UI.

`void projet::update()`

Lit boutons/encodeur et met à jour l'UI. À appeler dans `loop()` (mode boutons/encodeur).

Reads buttons/encoder and updates UI. Call in `loop()` (button/encoder mode).

`projet::input.feed(x, y, pressed)`

Mode touch : votre pilote tactile appelle cette fonction au lieu de `projet::update()`.

Touch mode: your touch driver calls this instead of `projet::update()`.

## Entrées

## Input

`ButtonInput` · `EncoderInput` · `TouchInput`

ButtonInput : `begin(up, down, ok, back)`, `update()`. EncoderInput : pins A/B/btn. TouchInput : `feed(x,y,pressed)`.

ButtonInput: `begin(up, down, ok, back)`, `update()`. EncoderInput: A/B/btn pins. TouchInput: `feed(x,y,pressed)`.

`void TouchInput::feed(int16_t x, int16_t y, bool pressed)`

Transmet un événement tactile à l'UI (down/up). Coordonnées en pixels logiques.

Forwards touch event to UI (down/up). Coordinates in logical pixels.

## Widgets

`Label · Metric · Bar · Icon · Image · Menu · Button · Switch · Slider · Chart · Gauge · List`

Constructeurs C++ exportés. Voir page Widgets pour exemples. Menu : `addItem`, `addCallbackItem`. Button : `setNavigate`, `setCallback`.

Exported C++ constructors. See Widgets page for examples. Menu: `addItem`, `addCallbackItem`. Button: `setNavigate`, `setCallback`.

`Label(x, y, text, TextAlign)`

Texte statique.

Static text.

`Metric(x, y, w, h, label, key, unit)`

Valeur live liée à une clé store.

Live value bound to store key.

`Menu`

Navigation ou callbacks, 16 items max.

Navigation or callbacks, 16 items max.

## Icônes

## Icons

`setIconLookups · drawIconRef`

`setIconLookups(rowsFn, imageFn)` enregistre les lookups exportés. `drawIconRef` dessine une icône par ref string (`"wifi"`, `"tabler:…"`).

`setIconLookups(rowsFn, imageFn)` registers exported lookups. `drawIconRef` draws icon by string ref (`"wifi"`, `"tabler:…"`).

`void setIconLookups(IconRowsLookup, IconImageLookup)`

Appelé dans `projet::build` pour lier les assets icônes.

Called in `projet::build` to wire icon assets.

## Arduino (hors Lucarne)

## Arduino (not Lucarne)

`void setup()`

Point d'entrée Arduino : initialisation une fois au démarrage. Câblage SPI, `display.begin`, `projet::build`, `ui.begin`.

Arduino entry point: one-time init at boot. SPI wiring, `display.begin`, `projet::build`, `ui.begin`.

`void loop()`

Boucle Arduino : `projet::update`, mise à jour des données (`ui.setFloat`…), `ui.update`, callbacks menu.

Arduino loop: `projet::update`, data updates (`ui.setFloat`…), `ui.update`, menu callbacks.

# FAQ & remerciements

# FAQ & acknowledgements

Réponses aux questions fréquentes et crédits des ressources utilisées.

Answers to common questions and credits for bundled resources.

### Général

### General

Lucarne remplace-t-il LVGL ?Does Lucarne replace LVGL?

Non. Lucarne cible les petits écrans SPI avec un flux design → export C++ statique, léger en RAM, sans moteur de rendu lourd sur la carte. LVGL reste plus adapté aux UIs complexes multi-couches avec beaucoup de widgets dynamiques.

No. Lucarne targets small SPI panels with a design → static C++ export flow, light on RAM, without a heavy on-device renderer. LVGL remains better for complex multi-layer UIs with many dynamic widgets.

Faut-il Internet pour utiliser Studio ?Do I need Internet for Studio?

Non pour l'édition de base. Internet sert surtout à charger des polices Google Fonts et les icônes Tabler si elles ne sont pas embarquées. Les packs Streamline/Glyphs inclus fonctionnent hors ligne.

No for basic editing. Internet is mainly for Google Fonts and Tabler icons when not embedded. Bundled Streamline/Glyphs packs work offline.

Où est sauvegardé mon projet ?Where is my project saved?

Dans le stockage local du navigateur (`localStorage`). Utilisez Save pour un fichier `.lucarne.json` portable. Effacer les données du site supprime le projet non exporté.

In browser `localStorage`. Use Save for a portable `.lucarne.json` file. Clearing site data deletes an unexported project.

### Studio & export

Dois-je re-exporter après chaque modification ?Must I re-export after every change?

Oui pour le firmware final. Live Preview affiche le design sans reflasher `Projet.h`. Dès que vous voulez le UI sur la carte dans votre app, régénérez les headers et recompilez.

Yes for final firmware. Live Preview shows the design without reflashing `Projet.h`. Once you want the UI in your app on device, regenerate headers and rebuild.

Quels fichiers l'export produit-il ?What files does export produce?

`Projet.h` toujours. En plus si nécessaire : `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h`, et binaires `assets/*.rgb565` pour images SD.

`Projet.h` always. Additionally when needed: `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h`, and `assets/*.rgb565` binaries for SD images.

Pourquoi l'export ne configure pas mes broches SPI ?Why doesn't export set my SPI pins?

Chaque carte a un câblage différent. Vous gardez `DisplayPins` et `display.begin()` dans votre `.ino`. L'export ne connaît que le UI (écrans, widgets, thème, entrées).

Every board wires differently. You keep `DisplayPins` and `display.begin()` in your `.ino`. Export only knows UI (screens, widgets, theme, input).

Comment fonctionnent les callbacks menu/bouton ?How do menu/button callbacks work?

Dans Studio, choisissez l'action Callback et un ID (ex. `open_settings`). L'export crée `projet::ACTION_OPEN_SETTINGS`. Dans `loop()`, lisez `ui.pollMenuAction()` dans un `switch` — une seule action consommée par appel.

In Studio, set action Callback and an ID (e.g. `open_settings`). Export creates `projet::ACTION_OPEN_SETTINGS`. In `loop()`, read `ui.pollMenuAction()` in a `switch` — one action consumed per call.

### Affichage & matériel

### Display & hardware

Écran noir, rétroéclairage allumé Black screen, backlight on

Testez `options.spiMode = 3` (fréquent sur ST7789). Vérifiez MOSI/SCLK/CS/DC/RST. Lancez `LucarneDiag` pour valider le panneau.

Try `options.spiMode = 3` (common on ST7789). Check MOSI/SCLK/CS/DC/RST. Run `LucarneDiag` to validate the panel.

Couleurs inversées ou rouge/bleu permutés Inverted or red/blue swapped colors

Basculez `options.invert` et/ou `options.colorOrder` (RGB vs BGR). Mêmes réglages que dans vos autres croquis qui fonctionnent.

Toggle `options.invert` and/or `options.colorOrder` (RGB vs BGR). Match settings from sketches that already work.

Bande de bruit en bas (240×280)Garbage band at bottom (240×280)

Le ST7789 240×280 utilise un offset vertical. Lucarne l'applique par défaut ; sur module exotique, ajustez `rowStart` / `colStart` dans `DisplayOptions`.

ST7789 240×280 uses a vertical offset. Lucarne applies it by default; on exotic modules, tune `rowStart` / `colStart` in `DisplayOptions`.

Les transitions ne s'animent pas Transitions don't animate

Il faut `BufferMode::Full` et assez de RAM pour deux snapshots temporaires. En `BufferMode::None`, les changements d'écran sont instantanés.

You need `BufferMode::Full` and enough RAM for two temporary snapshots. With `BufferMode::None`, screen changes are instant.

### Données, widgets, icônes

### Data, widgets, icons

Ma Metric affiche toujours la même valeur My Metric always shows the same value

Vérifiez que la clé dans l'onglet Data correspond au widget, et que vous appelez `ui.setFloat("ma_cle", valeur)` (ou int/bool/string) puis `ui.update()` dans `loop()`.

Check the Data tab key matches the widget, and call `ui.setFloat("my_key", value)` (or int/bool/string) then `ui.update()` in `loop()`.

Icône pack absente à l'export Pack icon missing in export

Seules les icônes réellement utilisées dans le projet sont exportées. Ouvrez le projet avec les packs chargés (serveur local sur `editor/`) avant d'exporter.

Only icons actually used in the project are exported. Open the project with packs loaded (local server on `editor/`) before exporting.

Le Slider ne réagit pas au toucher Slider doesn't respond to touch

Normal : le Slider est affichage seul. Mettez à jour la clé depuis votre code ou un autre contrôle. Le drag tactile n'est pas implémenté côté firmware.

Expected: Slider is display-only. Update the key from your code or another control. Touch drag is not implemented in firmware.

### Live Preview

Le bouton Live ne fait rien Live button does nothing

Utilisez Chrome ou Edge (Web Serial). Fermez le moniteur série de l'IDE Arduino. Flashez `LucarnePreview.ino` avec USB CDC activé sur ESP32-S3.

Use Chrome or Edge (Web Serial). Close the Arduino IDE serial monitor. Flash `LucarnePreview.ino` with USB CDC enabled on ESP32-S3.

Live vs firmware exporté Live vs exported firmware

Live envoie des images calculées par Studio. Votre app avec `Projet.h` exécute le vrai runtime UI sur la carte. Utilisez Live pour itérer visuellement, puis exportez pour le produit final.

Live sends frames rendered by Studio. Your app with `Projet.h` runs the real UI runtime on device. Use Live to iterate visually, then export for production.

## Remerciements & licences

## Acknowledgements & licenses

- Fira Sans Police par défaut (corps et titre). SIL Open Font License 1.1 — Mozilla Foundation. Default body and title font. SIL Open Font License 1.1 — Mozilla Foundation.
- Tabler Icons Pack d'icônes optionnel dans Studio. MIT License — Tabler. Optional icon pack in Studio. MIT License — Tabler.
- Streamline & Glyphs packs Icônes couleur 32×32 embarquées dans l'éditeur. Voir les licences des packs respectifs dans le dépôt distributeur. 32×32 color icons embedded in the editor. See respective pack licenses in the distribution repo.
- Arduino & ESP32 Toolchains et cores utilisés pour compiler les exemples — non inclus dans Lucarne. Toolchains and cores used to build examples — not bundled with Lucarne.

Lucarne est un projet open source. Contributions et retours bienvenus sur le dépôt GitHub.

Lucarne is an open source project. Contributions and feedback welcome on the GitHub repository.