# 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 Headers + Files (SD) → copier à côté du .ino → compiler. Export Headers + Files (SD) → 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/` ouor `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 · Hardware broches SPI/SD/entrées · Assets images/icônes · Data clés (temp, wifi…) Theme colors · Fonts · Hardware SPI/SD/input pins · 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émentItem | RôleRole
--- | ---
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éelleUSB connection for on-device preview
Export .h | Génère les headers C++ du projetGenerates 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 et `Projet_setup.h` (broches, SD). Copiez les binaires SD sur la carte.

Studio generates the UI and `Projet_setup.h` (pins, SD). Copy SD binaries to the card.

1. Export dans Studio → onglets Headers et Files (SD). in Studio → Headers and Files (SD) tabs.
2. Headers : `Projet.h`, `Projet_setup.h`, éventuellement `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h` à côté du .ino.Headers: `Projet.h`, `Projet_setup.h`, optional `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h` next to .ino.
3. Files (SD) : copiez `assets/*.rgb565` sur carte FAT32 (voir `SD_MANIFEST.txt`).Files (SD): copy `assets/*.rgb565` to FAT32 card (see `SD_MANIFEST.txt`).
4. Broches SPI / SD : onglet Studio Hardware → réglages dans `Projet_setup.h`.SPI / SD pins: Studio Hardware tab → settings in `Projet_setup.h`.

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

    void setup() {
      BufferOptions buffer;
      buffer.mode = BufferMode::Full;
      projet::initSpiBus();
      display.begin(projet::displayPins(), projet::displayOptions(), buffer, &SPI);
      projet::mountSdCard();
      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)

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

Studio Hardware tab → Navigation input: 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 : onglets Headers et Files (SD), copie ou téléchargement.Export: Headers and Files (SD) tabs, copy or download.

# 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

Flash (pixels embarqués) ou SD (`ImageStorage::Sd`, fichier `.rgb565`).

Flash (embedded pixels) or SD (`ImageStorage::Sd`, `.rgb565` file).

    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, carte SD optionnelle, entrées navigation.

SPI display, optional SD card, navigation inputs.

Configurez broches SPI, SD et entrées dans Studio → onglet Hardware. L'export génère `Projet_setup.h`.
Set SPI, SD and input pins in Studio → Hardware tab. Export generates `Projet_setup.h`.

## Écran SPI

## SPI display

Signal | Pin
--- | ---
SCLK | `pins.sclk`
MOSI | `pins.mosi`
MISO | `pins.miso` (SD)
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.

## Carte SD (images)

## SD card (images)

Bus SPI partagé : MOSI, MISO, SCLK communs ; CS séparés pour écran et SD. Montez la SD avant `ui.begin()`. Copiez les fichiers export Files (SD) sur la carte (FAT32).

Shared SPI bus: common MOSI, MISO, SCLK; separate CS for display and SD. Mount SD before `ui.begin()`. Copy Files (SD) export onto the card (FAT32).

    projet::initSpiBus();
    display.begin(projet::displayPins(), projet::displayOptions(), buffer, &SPI);
    projet::mountSdCard();

## 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. FlasherFlash `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. ConnecterConnect
   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 SimulateDesigner 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 | UsagePurpose
--- | ---
`HelloLucarne` | Gfx bas niveau, sans UI runtimeLow-level Gfx, no UI runtime
`LucarneUI` | Dashboard Metric/Bar et liaison de donnéesDashboard Metric/Bar and data binding
`LucarneMenu` | Menus multi-écrans, transitions, callbacksMulti-screen menus, transitions, callbacks
`LucarnePreview` | Récepteur Live Preview USBUSB Live Preview receiver
`LucarneDiag` | Test plein écran rouge/vert/bleuFull-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?

Headers : `Projet.h`, `Projet_setup.h`, et si besoin `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h`. Files (SD) : `assets/*.rgb565` + `SD_MANIFEST.txt`.

Headers: `Projet.h`, `Projet_setup.h`, and when needed `Projet_fonts.h`, `Projet_images.h`, `Projet_icons.h`. Files (SD): `assets/*.rgb565` + `SD_MANIFEST.txt`.

Où configurer les broches SPI et SD ?Where do I set SPI and SD pins?

Onglet Studio Hardware (bus SPI, écran, SD, entrées). L'export écrit `Projet_setup.h` avec `initSpiBus()`, `displayPins()`, `mountSdCard()`. Vous pouvez surcharger dans le .ino si besoin.

Studio Hardware tab (SPI bus, display, SD, inputs). Export writes `Projet_setup.h` with `initSpiBus()`, `displayPins()`, `mountSdCard()`. Override in your .ino if needed.

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ésInverted 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 pasTransitions 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 valeurMy 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'exportPack 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.

Image SD : écran vide ou carré noirSD image: blank or black square

Vérifiez `mountSdCard()` avant `ui.begin()`, le chemin `source` dans `Projet_images.h`, et que le fichier est bien sur la SD (onglet export Files (SD)). `pins.miso` doit être défini dans Hardware.

Check `mountSdCard()` before `ui.begin()`, the `source` path in `Projet_images.h`, and that the file is on the SD (Files (SD) export tab). Set `pins.miso` in Hardware.

Le Slider ne réagit pas au toucherSlider 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 rienLive 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.