diff --git a/Makefile b/Makefile
index cc274e3..7784507 100644
--- a/Makefile
+++ b/Makefile
@@ -37,13 +37,16 @@ UPSILON_GAMES = crossyroad numdrive blockblast portal tetris chess flappybird pa
 
 # NumPlay and its discreet versions: the same app, with another name and icon
 # on the calculator's home screen. Each one is a release file.
-VARIANTS = NumPlay NumPlay-Invisible NumPlay-Matrices
+VARIANTS = NumPlay NumPlay-Invisible NumPlay-Matrices NumPlay-Tableur
 NAME_NumPlay = "Calcade"
 ICON_NumPlay = launcher/assets/icon.png
 NAME_NumPlay-Invisible = " "
 ICON_NumPlay-Invisible = launcher/assets/icon-invisible.png
 NAME_NumPlay-Matrices = "Matrices"
 ICON_NumPlay-Matrices = launcher/assets/icon-matrices.png
+# Calcade, 23 octobre 2026 : l'appli déguisée en tableur (NP_VARIANTE=1)
+NAME_NumPlay-Tableur = "Tableur"
+ICON_NumPlay-Tableur = launcher/assets/icon-tableur.png
 
 EADK_CFLAGS := $(shell $(NWLINK) eadk-cflags-device)
 EADK_SIM_CFLAGS := $(shell $(NWLINK) eadk-cflags-simulator)
diff --git a/launcher/assets/icon-tableur.png b/launcher/assets/icon-tableur.png
new file mode 100644
index 0000000000000000000000000000000000000000..286051c9b8f886e3a3e33efe4120dabd0eca7156
GIT binary patch
literal 325
zcmV-L0lNN)P)<h;3K|Lk000e1NJLTq001`t001}$1^@s6S&d+m0003DNkl<Zc%1E;
zJr2S!3`U)ZdypOO!$P@57Y@KcZb2vR1AA@~rb<<sKco)*tnZDn+vdrQ+)6evMk(R^
zP!8^dFixfvGdVc~sg#_gO&1WwMDqK#tpp^}{o7Iim8FMG7c?;Ytj?S!%<*|uRkbCm
zD@Qq0RLdQD6W_OcF?M-9s`1{Of9}<T>dH|L70RKa`txhERuIOidcE^QGp9Gt`Js6q
z5#_HX<xrs<DwIQoO<ZK7CVu`lpW{9!Ht`-PhYICTp&Tk~;v)PL-yM`gg>tB<mQ&s5
zR9B92sOXlf4Pzn`#>wceoJf6?7LnP<rVHpSJ!~m}NV@;knL`!K?K?Z2K7%kpTPwy7
XZufI;8|F2S00000NkvXXu0mjfk$sHz

literal 0
HcmV?d00001

diff --git a/launcher/src/home.c b/launcher/src/home.c
index 915b04d..581e25d 100644
--- a/launcher/src/home.c
+++ b/launcher/src/home.c
@@ -261,12 +261,15 @@ int np_home(int *selected, bool returning) {
   uint32_t last = np_millis();
   bool dirty = true, bar_dirty = false;
   int result = -3;
+  uint32_t idle_from = np_millis();
   for (;;) {
     uint32_t now = np_millis();
     float dt = NP_MIN((now - last) / 1000.f, 0.05f);
     uint32_t elapsed = now - last;
     last = now;
     uint32_t pressed = ui_poll(&keys);
+    if (keys.held || pressed) idle_from = now;
+    if (result == -3 && now - idle_from > NP_IDLE_QUIT_MS) return -2; /* Calcade : avant la mise en veille */
     if (result == -3) {
       int before = h.sel;
       if (pressed & K_LEFT) h.sel = NP_MAX(h.sel - 1, 0);
diff --git a/launcher/src/main.c b/launcher/src/main.c
index 96d60ff..160e4e4 100644
--- a/launcher/src/main.c
+++ b/launcher/src/main.c
@@ -20,11 +20,13 @@ static bool home_pressed;
 eadk_keyboard_state_t np_keyboard_scan(void) {
   eadk_keyboard_state_t s = eadk_keyboard_scan();
   if (s & ((1ull << eadk_key_home) | (1ull << eadk_key_on_off))) home_pressed = true;
+  if (s & (1ull << eadk_key_on_off)) np_onoff = true;
   return s;
 }
 eadk_event_t np_event_get(int32_t *timeout) {
   eadk_event_t e = eadk_event_get(timeout);
   if (e == 6 || e == 8) home_pressed = true; /* Home, On/Off */
+  if (e == 8) np_onoff = true;
   return e;
 }
 #else
@@ -44,13 +46,20 @@ int main(void) {
   /* started as Matrices (Settings): NumPlay opens only through its secret */
   np_config_t cfg;
   np_config_load(&cfg);
+#if NP_VARIANTE == 1
+  /* Calcade : l'appli « Tableur » ; le code ouvre le vrai Calcade */
+  if (!np_tableur()) return np_session_end();
+#elif NP_VARIANTE == 2
+  /* Calcade : l'appli invisible ouvre directement les jeux */
+#else
   if (cfg.disguise && !np_matrices(&cfg)) return np_session_end();
+#endif
   np_wait_release();
   /* Calcade: this opening is counted in numplay.sys (every 20th sets the "update required" flag),
    * then the studio's intro; with the flag set, NumPlay stays on the update screen (Home quits) */
   bool update_required = cc_launch();
   np_progress_backup();
-  if (!cc_intro()) return np_session_end();
+  if (NP_VARIANTE != 2 && !cc_intro()) return np_session_end();
   if (update_required) {
     cc_update_required();
     return np_session_end();
diff --git a/launcher/src/matrices.c b/launcher/src/matrices.c
index a9b7319..c1acadf 100644
--- a/launcher/src/matrices.c
+++ b/launcher/src/matrices.c
@@ -330,6 +330,7 @@ bool np_matrices(const np_config_t *cfg) {
   uint64_t prev = eadk_keyboard_scan();
   uint32_t repeat_at = 0;
   int code = 0; /* the Konami code's keys pressed so far */
+  uint32_t idle_from = np_millis();
   for (int frame = 0;; frame++) {
     uint64_t k = eadk_keyboard_scan(), hit = k & ~prev;
     if (cfg->secret == NP_SECRET_KONAMI && hit) { /* fresh presses only, not held arrows repeating */
@@ -343,7 +344,10 @@ bool np_matrices(const np_config_t *cfg) {
     else if ((k & arrows) && (int32_t)(now - repeat_at) >= 0) hit |= k & arrows, repeat_at = now + 110;
     prev = k;
 #define HIT(key) ((hit >> (key)) & 1)
+    if (HIT(KEY_ONOFF)) np_onoff = true;
     if (HIT(KEY_HOME) || HIT(KEY_ONOFF)) return false;
+    if (k) idle_from = now;
+    if (now - idle_from > NP_IDLE_QUIT_MS) return false; /* Calcade : avant la mise en veille */
     uint8_t sk = secret_keys[cfg->secret];
     if (sk != 255 && HIT(sk)) return true;
     if (frame % 600 == 0) status_bar(); /* the battery, now and then */
diff --git a/launcher/src/np.h b/launcher/src/np.h
index aba14d6..d86f241 100644
--- a/launcher/src/np.h
+++ b/launcher/src/np.h
@@ -119,6 +119,18 @@ bool np_bg_save(int mode);
    file the NumWorks installer keeps when NumPlay is updated. */
 void np_progress_backup(void);
 void np_storage_heal(void); /* Calcade : efface le cache périmé d'Epsilon */
+/* Calcade, 23 octobre 2026 : les variantes de l'appli (le site choisit à l'installation) :
+ * 0 Calcade, 1 « Tableur » (déguisement, un code ouvre Calcade), 2 invisible (logo blanc, sans nom,
+ * ouvre directement les jeux) */
+#ifndef NP_VARIANTE
+#define NP_VARIANTE 0
+#endif
+/* On/Off appuyé : l'appli se ferme tout de suite (sans attendre qu'on relâche), pour que la
+ * calculatrice s'éteigne sur son écran d'accueil et ne se rallume jamais dans Calcade */
+extern bool np_onoff;
+/* rien touché pendant ce temps dans le menu ou le tableur : l'appli se ferme (avant la mise en veille) */
+#define NP_IDLE_QUIT_MS 120000u
+bool np_tableur(void);
 void np_progress_restore(void); /* only when none of the saves are left */
 /* Matrices, the disguise: true when the secret was used (open NumPlay), false to quit */
 bool np_matrices(const np_config_t *c);
diff --git a/launcher/src/platform.c b/launcher/src/platform.c
index 04df873..c0491f2 100644
--- a/launcher/src/platform.c
+++ b/launcher/src/platform.c
@@ -12,6 +12,7 @@ uint32_t np_keys(void) {
   if (DOWN(eadk_key_ok) || DOWN(eadk_key_exe) || DOWN(eadk_key_five)) out |= K_OK;
   if (DOWN(eadk_key_back)) out |= K_BACK;
   if (DOWN(eadk_key_home) || DOWN(eadk_key_on_off)) out |= K_HOME;
+  if (DOWN(eadk_key_on_off)) np_onoff = true;
   if (DOWN(eadk_key_backspace)) out |= K_BACKSPACE;
 #undef DOWN
   return out;
@@ -40,8 +41,13 @@ void np_fill_screen(int x, int y, int w, int h, color_t c) {
   eadk_display_push_rect_uniform((eadk_rect_t){(uint16_t)x, (uint16_t)y, (uint16_t)w, (uint16_t)h}, c);
 }
 
+bool np_onoff;
 void np_wait_release(void) {
-  while (eadk_keyboard_scan()) eadk_timing_msleep(10);
+  if (np_onoff) return; /* Calcade : On/Off, on sort tout de suite */
+  while (eadk_keyboard_scan()) {
+    if (eadk_keyboard_key_down(eadk_keyboard_scan(), eadk_key_on_off)) { np_onoff = true; return; }
+    eadk_timing_msleep(10);
+  }
 }
 
 /* The arena is the last of NumPlay's RAM: after it, up to _heap_end, the RAM the calculator's
diff --git a/launcher/src/tableur.c b/launcher/src/tableur.c
new file mode 100644
index 0000000..887ce08
--- /dev/null
+++ b/launcher/src/tableur.c
@@ -0,0 +1,247 @@
+/* Calcade, 23 octobre 2026 — fait partie de NumPlay modifié, sous licence GNU GPL v3.
+ * Tableur : le déguisement de l'appli « Tableur » (variante NP_VARIANTE == 1). Un vrai petit tableur,
+ * dessiné comme les applis de la calculatrice : 5 colonnes (A à E), 40 lignes, des nombres à saisir,
+ * et la somme et la moyenne de la colonne en bas. Taper le CODE dans une case (puis OK ou EXE) ouvre
+ * le vrai Calcade. Le code est écrit par le site à l'installation, juste après la marque
+ * « CALCADE-TABLEUR1 » (calculatrice.js) ; sans code : 1234.
+ * Home ou On/Off : on quitte. Rien touché pendant NP_IDLE_QUIT_MS : on quitte aussi (la calculatrice
+ * qui s'éteint toute seule ne doit pas se rallumer dans le tableur, ni dans Calcade). */
+#include <eadk.h>
+#include <string.h>
+#include "np.h"
+#include "sys.h"
+
+#define C_BAR RGB(0xFF, 0xB6, 0x31)
+#define C_BG RGB(0xE7, 0xE7, 0xEF)
+#define C_WHITE 0xFFFF
+#define C_SEL RGB(0xD6, 0xD7, 0xE7)
+#define C_HEAD RGB(0xF5, 0xF5, 0xF8)
+#define C_LINE RGB(0xC6, 0xC3, 0xC6)
+#define C_TEXT 0x0000
+#define C_GRAY RGB(0x94, 0x9A, 0xA5)
+#define C_TAB RGB(0x63, 0x69, 0x73)
+
+#define COLS 5
+#define ROWS 40
+#define VIS 7 /* lignes visibles */
+#define X0 30 /* largeur des numéros de ligne */
+#define CW 58
+#define Y0 40
+#define RH 22
+
+/* la marque et le code, tamponnés par le site */
+typedef struct { char mark[16]; char code[12]; } tb_code_t;
+__attribute__((used, aligned(4))) const volatile tb_code_t np_tableur_code = {
+    {'C', 'A', 'L', 'C', 'A', 'D', 'E', '-', 'T', 'A', 'B', 'L', 'E', 'U', 'R', '1'}, {0}};
+
+enum {
+  KEY_LEFT = 0, KEY_UP = 1, KEY_DOWN = 2, KEY_RIGHT = 3, KEY_OK = 4, KEY_BACK = 5, KEY_HOME = 6, KEY_ONOFF = 8,
+  KEY_TOOLBOX = 16, KEY_BACKSPACE = 17, KEY_MINUS = 46, KEY_DOT = 49, KEY_EXE = 52
+};
+static const int8_t digit_keys[10] = {48, 42, 43, 44, 36, 37, 38, 30, 31, 32};
+
+static struct {
+  float v[ROWS][COLS];
+  uint8_t set[ROWS][COLS];
+  int row, col, top;
+  char edit[12];
+} TB;
+
+static void fill(int x, int y, int w, int h, color_t c) {
+  if (w > 0 && h > 0) eadk_display_push_rect_uniform((eadk_rect_t){x, y, w, h}, c);
+}
+static void text(const char *s, int x, int y, bool big, color_t fg, color_t bg) {
+  np_display_draw_string(s, (eadk_point_t){x, y}, big, fg, bg);
+}
+static int width(const char *s, bool big) { return (int)strlen(s) * (big ? 10 : 7); }
+
+static void fmt(float v, char *o) {
+  bool neg = v < 0;
+  if (neg) v = -v;
+  if (v >= 1e9f) {
+    strcpy(o, neg ? "-1E9+" : "1E9+");
+    return;
+  }
+  uint32_t ip, fp;
+  if (v >= 1e5f) ip = (uint32_t)(v + 0.5f), fp = 0;
+  else {
+    uint32_t s = (uint32_t)(v * 100 + 0.5f);
+    ip = s / 100, fp = s % 100;
+  }
+  if (neg && (ip || fp)) *o++ = '-';
+  char t[12];
+  int n = 0;
+  do t[n++] = (char)('0' + ip % 10);
+  while (ip /= 10);
+  while (n) *o++ = t[--n];
+  if (fp) {
+    *o++ = '.';
+    *o++ = (char)('0' + fp / 10);
+    if (fp % 10) *o++ = (char)('0' + fp % 10);
+  }
+  *o = 0;
+}
+static float parse(const char *s) {
+  float sign = 1, v = 0, scale = 0;
+  if (*s == '-') sign = -1, s++;
+  for (; *s; s++) {
+    if (*s == '.') scale = scale ? scale : 1;
+    else if (*s >= '0' && *s <= '9') {
+      if (scale) scale /= 10, v += (float)(*s - '0') * scale;
+      else v = v * 10 + (float)(*s - '0');
+    }
+  }
+  return sign * v;
+}
+
+/* le code attendu (chiffres seulement) */
+static void code(char out[12]) {
+  int n = 0;
+  for (int i = 0; i < 11; i++) {
+    char c = np_tableur_code.code[i];
+    if (c < '0' || c > '9') break;
+    out[n++] = c;
+  }
+  out[n] = 0;
+  if (n < 3) strcpy(out, "1234");
+}
+
+static void status_bar(void) {
+  fill(0, 0, SCREEN_W, 18, C_BAR);
+  text("rad", 4, 2, false, C_WHITE, C_BAR);
+  text("TABLEUR", 160 - width("TABLEUR", false) / 2, 2, false, C_WHITE, C_BAR);
+  int level = np_battery_level();
+  fill(296, 5, 15, 8, C_WHITE);
+  fill(297, 6, 13, 6, C_BAR);
+  fill(311, 7, 2, 4, C_WHITE);
+  int bars = level < 0 ? 3 : NP_MIN(level, 3);
+  fill(298, 7, bars * 11 / 3, 4, C_WHITE);
+  fill(0, 18, SCREEN_W, 22, C_WHITE);
+  text("Feuille 1", 160 - width("Feuille 1", false) / 2, 22, false, C_TAB, C_WHITE);
+  fill(0, 39, SCREEN_W, 1, C_LINE);
+}
+
+static void cell(int r, int c) {
+  int vr = r - TB.top;
+  if (vr < 0 || vr >= VIS) return;
+  int x = X0 + c * CW, y = Y0 + RH + vr * RH;
+  bool sel = r == TB.row && c == TB.col;
+  color_t bg = sel ? C_SEL : C_WHITE;
+  fill(x, y, CW - 1, RH - 1, bg);
+  char s[14] = "";
+  if (sel && TB.edit[0]) strcpy(s, TB.edit);
+  else if (TB.set[r][c]) fmt(TB.v[r][c], s);
+  if (s[0]) text(s, x + CW - 5 - width(s, false), y + 4, false, C_TEXT, bg);
+  if (sel && TB.edit[0]) fill(x + CW - 4, y + 3, 1, 15, C_TEXT);
+}
+
+static void footer(void) {
+  int y = Y0 + RH + VIS * RH;
+  fill(0, y, SCREEN_W, SCREEN_H - y, C_BG);
+  float s = 0;
+  int n = 0;
+  for (int r = 0; r < ROWS; r++)
+    if (TB.set[r][TB.col]) s += TB.v[r][TB.col], n++;
+  char a[16], b[16], l[48];
+  fmt(s, a);
+  fmt(n ? s / (float)n : 0, b);
+  char col[2] = {(char)('A' + TB.col), 0};
+  strcpy(l, "Somme(");
+  strcat(l, col);
+  strcat(l, ") = ");
+  strcat(l, a);
+  text(l, 6, y + 6, false, C_TEXT, C_BG);
+  strcpy(l, "Moyenne = ");
+  strcat(l, b);
+  text(l, SCREEN_W - 6 - width(l, false), y + 6, false, C_TEXT, C_BG);
+}
+
+static void grid(void) {
+  fill(0, Y0, SCREEN_W, RH, C_HEAD);
+  for (int c = 0; c < COLS; c++) {
+    char h[2] = {(char)('A' + c), 0};
+    text(h, X0 + c * CW + CW / 2 - 3, Y0 + 4, false, C_GRAY, C_HEAD);
+    fill(X0 + c * CW + CW - 1, Y0, 1, RH + VIS * RH, C_LINE);
+  }
+  fill(0, Y0 + RH - 1, SCREEN_W, 1, C_LINE);
+  for (int vr = 0; vr < VIS; vr++) {
+    int y = Y0 + RH + vr * RH;
+    fill(0, y, X0 - 1, RH - 1, C_HEAD);
+    char n[4];
+    int r = TB.top + vr + 1;
+    n[0] = r >= 10 ? (char)('0' + r / 10) : ' ', n[1] = (char)('0' + r % 10), n[2] = 0;
+    text(n, 6, y + 4, false, C_GRAY, C_HEAD);
+    fill(X0 - 1, y, 1, RH, C_LINE);
+    fill(0, y + RH - 1, SCREEN_W, 1, C_LINE);
+    for (int c = 0; c < COLS; c++) cell(TB.top + vr, c);
+  }
+  footer();
+}
+
+/* true : le code a été tapé (ouvrir Calcade) ; false : quitter */
+bool np_tableur(void) {
+  memset(&TB, 0, sizeof TB);
+  char secret[12];
+  code(secret);
+  status_bar();
+  grid();
+  uint64_t prev = eadk_keyboard_scan();
+  uint32_t repeat_at = 0, last_key = np_millis();
+  for (int frame = 0;; frame++) {
+    uint64_t k = eadk_keyboard_scan(), hit = k & ~prev;
+    uint32_t now = np_millis();
+    const uint64_t arrows = 0xF;
+    if (hit & arrows) repeat_at = now + 400;
+    else if ((k & arrows) && (int32_t)(now - repeat_at) >= 0) hit |= k & arrows, repeat_at = now + 110;
+    prev = k;
+    if (k) last_key = now;
+#define HIT(key) ((hit >> (key)) & 1)
+    if (HIT(KEY_ONOFF)) {
+      np_onoff = true;
+      return false;
+    }
+    if (HIT(KEY_HOME)) return false;
+    if (now - last_key > NP_IDLE_QUIT_MS) return false;
+    if (frame % 600 == 0) status_bar();
+    if (!hit) {
+      np_sleep(16);
+      continue;
+    }
+    int r = TB.row, c = TB.col;
+    size_t len = strlen(TB.edit);
+    bool commit = HIT(KEY_OK) || HIT(KEY_EXE);
+    if (HIT(KEY_UP) || HIT(KEY_DOWN) || HIT(KEY_LEFT) || HIT(KEY_RIGHT)) commit = true;
+    if (commit && TB.edit[0]) {
+      if (!strcmp(TB.edit, secret)) return true; /* le code : le vrai Calcade */
+      TB.v[r][c] = parse(TB.edit);
+      TB.set[r][c] = 1;
+      TB.edit[0] = 0;
+      if (HIT(KEY_OK) || HIT(KEY_EXE)) r = NP_MIN(r + 1, ROWS - 1);
+    }
+    if (HIT(KEY_UP)) r = NP_MAX(r - 1, 0);
+    if (HIT(KEY_DOWN)) r = NP_MIN(r + 1, ROWS - 1);
+    if (HIT(KEY_LEFT)) c = NP_MAX(c - 1, 0);
+    if (HIT(KEY_RIGHT)) c = NP_MIN(c + 1, COLS - 1);
+    for (int d = 0; d < 10; d++)
+      if (HIT(digit_keys[d]) && len < 9) TB.edit[len++] = (char)('0' + d), TB.edit[len] = 0;
+    if (HIT(KEY_DOT) && len < 9 && !strchr(TB.edit, '.')) TB.edit[len++] = '.', TB.edit[len] = 0;
+    if (HIT(KEY_MINUS) && len == 0) TB.edit[len++] = '-', TB.edit[len] = 0;
+    if (HIT(KEY_BACKSPACE)) {
+      if (len) TB.edit[--len] = 0;
+      else TB.set[r][c] = 0, TB.v[r][c] = 0;
+    }
+    if (HIT(KEY_BACK) && TB.edit[0]) TB.edit[0] = 0;
+    int top = TB.top;
+    if (r < top) top = r;
+    if (r >= top + VIS) top = r - VIS + 1;
+    int or_ = TB.row, oc = TB.col;
+    TB.row = r, TB.col = c;
+    if (top != TB.top || c != oc) {
+      TB.top = top;
+      grid();
+    } else {
+      cell(or_, oc);
+      cell(r, c);
+    }
+  }
+}
diff --git a/tools/calcade_pack.py b/tools/calcade_pack.py
index 3157dc7..9d177b6 100644
--- a/tools/calcade_pack.py
+++ b/tools/calcade_pack.py
@@ -81,6 +81,10 @@ def main():
     for sous in ("pack", "modules", "gen", "arm", "apps", "sim"):  # (le Makefile ne les crée qu'avec build/)
         os.makedirs(os.path.join(RACINE, B, sous), exist_ok=True)
     cflags = shlex.split(run(shlex.split(a.nwlink) + ["eadk-cflags-device"]).strip().splitlines()[-1])
+    # Calcade, 23 octobre 2026 : VARIANTE=NumPlay-Tableur (1) ou NumPlay-Invisible (2), le cœur déguisé
+    variante = os.environ.get("VARIANTE", "NumPlay")
+    num_variante = {"NumPlay": 0, "NumPlay-Tableur": 1, "NumPlay-Invisible": 2}[variante]
+    cflags += [f"-DNP_VARIANTE={num_variante}"]
     cflags += ["-std=gnu11", f'-DNP_VERSION="{a.version}"', "-DNP_COEUR=1", "-Os", "-Wall",
                "-Wno-unused-parameter", "-fno-math-errno", "-ffunction-sections", "-fdata-sections",
                "-Ilauncher/src"]
@@ -207,17 +211,17 @@ SECTIONS {{
             run(["arm-none-eabi-gcc"] + cflags + ["-flto", "-fno-tree-loop-distribute-patterns", "-Wextra",
                  "-c", f"launcher/src/{f}", "-o", o])
             cœur_obj.append(o)
-    run(["make", "--no-print-directory", f"{B}/variant/NumPlay-name.o", f"{B}/variant/NumPlay-icon.o",
+    run(["make", "--no-print-directory", f"{B}/variant/{variante}-name.o", f"{B}/variant/{variante}-icon.o",
          f"NWLINK={a.nwlink}"])
     # les fonctions du cœur que des mini-jeux appellent : gardées et visibles (eadk_* exclus :
     # ils viennent d'eadk.o, lié par le site)
     garde = sorted(exports | {"np_keyboard_scan", "np_event_get", "np_display_draw_string", "numplay_launcher"})
     open(os.path.join(RACINE, SORTIE, "exports-coeur.txt"), "w").write("\n".join(garde) + "\n")
-    coeur = f"{SORTIE}/NumPlay-coeur.nwa"
+    coeur = f"{SORTIE}/NumPlay-coeur.nwa" if variante == "NumPlay" else f"{SORTIE}/NumPlay-coeur-{variante.split('-')[1].lower()}.nwa"
     run(["arm-none-eabi-gcc"] + cflags + ["-flto", "-nostartfiles", "--specs=nano.specs", "-Wl,--relocatable",
          "-Wl,--gc-sections", "-Wl,-e,main", "-Wl,-u,eadk_app_name", "-Wl,-u,eadk_app_icon",
          "-Wl,-u,eadk_api_level", "-flinker-output=nolto-rel"] + [f"-Wl,-u,{s}" for s in garde] + cœur_obj +
-        [f"{B}/variant/NumPlay-name.o", f"{B}/variant/NumPlay-icon.o", "-lm", "-lgcc", "-o", coeur])
+        [f"{B}/variant/{variante}-name.o", f"{B}/variant/{variante}-icon.o", "-lm", "-lgcc", "-o", coeur])
     run(["arm-none-eabi-strip", "--strip-unneeded", "--remove-section=.ARM.exidx*", "--remove-section=.rel.ARM.exidx*",
          "--remove-section=.comment", coeur])
     defini = run(["arm-none-eabi-nm", "-g", "--defined-only", coeur])
