diff --git a/publish/build_scorm_package.py b/publish/build_scorm_package.py
index 76c9cb32..5ada3bb5 100644
--- a/publish/build_scorm_package.py
+++ b/publish/build_scorm_package.py
@@ -67,9 +67,21 @@ def _relativize_absolute_urls(html, slug):
ailleurs que dans une URL réellement générée par le moteur. Sans ce
correctif, un index.html ouvert en local (file://) échouait à charger
icônes/sprites/fichiers envoyés (CORS bloque une requête absolue vers
- file:///static/... — "la requête CORS n'utilise pas HTTP")."""
+ file:///static/... — "la requête CORS n'utilise pas HTTP").
+
+ Cas particulier des icônes (render_icone.py) : leur URL est posée dans
+ un style INLINE (--icon-url), mais CONSUMÉE par `mask-image:
+ var(--icon-url)` dans static/style.css (voir .icon-svg) — une URL
+ relative dans une PROPRIÉTÉ PERSONNALISÉE CSS se résout par rapport à
+ la feuille de style où le var() est UTILISÉ, pas où elle est définie
+ (piège CSS connu). "icons/x.svg" (juste "/static/" retiré, sans le
+ garder) reste donc correct une fois résolu depuis static/style.css,
+ alors que "static/icons/x.svg" y redevient "static/static/icons/x.svg"
+ (bug signalé — CORS bloqué sur ce chemin doublé). Traité EN PREMIER,
+ plus spécifique que le remplacement générique juste après."""
return (
html.replace(f"/game/{slug}/uploads/", "uploads/")
+ .replace("/static/icons/", "icons/")
.replace("/static/", "static/")
)
diff --git a/static/js/play/offline/__tests__/render-special-widgets.test.js b/static/js/play/offline/__tests__/render-special-widgets.test.js
index 55872594..ac04a7ed 100644
--- a/static/js/play/offline/__tests__/render-special-widgets.test.js
+++ b/static/js/play/offline/__tests__/render-special-widgets.test.js
@@ -55,7 +55,7 @@ test('icône — repli sur "star" si _icon_slug absent', () => {
const html = forgeRenderElementHtml(el, baseGameData(), {}, {});
// le style entier passe par forgeHtmlEscape (comme html.escape() côté
// serveur) : l'apostrophe de url('...') devient '.
- assert.ok(html.includes("--icon-url:url('static/icons/star.svg')"));
+ assert.ok(html.includes("--icon-url:url('icons/star.svg')"));
});
test('onglets — un panneau actif, les autres masqués', () => {
diff --git a/static/js/play/offline/render-special-widgets.js b/static/js/play/offline/render-special-widgets.js
index e82f5762..d2c54cea 100644
--- a/static/js/play/offline/render-special-widgets.js
+++ b/static/js/play/offline/render-special-widgets.js
@@ -73,13 +73,17 @@ function forgeRenderIcone(el, meta, gameData, childrenMap, ctx, parentFlexDirect
var existingClass = attrs.class || "";
delete attrs.class;
attrs.class = (existingClass + " icon-svg").trim();
- // Chemin RELATIF (jamais "/static/...") : ce fichier ne s'exécute que
- // dans le paquet exporté (window.FORGE_OFFLINE, voir render-element.js),
- // ouvert en local (file://) sans racine de serveur — un chemin absolu y
- // déclenche un blocage CORS ("la requête CORS n'utilise pas HTTP"),
- // exactement le bug qui affectait aussi le rendu initial côté serveur
- // (voir _relativize_absolute_urls dans publish/build_scorm_package.py).
- var iconUrl = "static/icons/" + iconSlug + ".svg";
+ // Chemin RELATIF, et surtout PAS préfixé "static/" : cette URL est
+ // posée dans --icon-url (style inline) mais CONSOMMÉE par `mask-image:
+ // var(--icon-url)` dans static/style.css (voir .icon-svg) — une URL
+ // relative dans une propriété personnalisée CSS se résout par rapport à
+ // LA FEUILLE DE STYLE où le var() est utilisé (static/style.css), pas
+ // où elle est définie (piège CSS connu) : "static/icons/x.svg" y
+ // redeviendrait "static/static/icons/x.svg" (404/CORS bloqué — bug
+ // signalé). "icons/x.svg" est correct une fois résolu depuis
+ // static/style.css (voir aussi _relativize_absolute_urls dans
+ // publish/build_scorm_package.py, même correctif côté rendu initial).
+ var iconUrl = "icons/" + iconSlug + ".svg";
var style = forgeStyleString(el, parentFlexDirection, el.widget) + " --icon-url:url('" + iconUrl + "');";
return "";
}
diff --git a/tests/test_export_scorm.py b/tests/test_export_scorm.py
index 52874d8d..a9f2f51c 100644
--- a/tests/test_export_scorm.py
+++ b/tests/test_export_scorm.py
@@ -56,9 +56,16 @@ def test_export_scorm_icon_widget_uses_a_relative_url(client, game):
part de la racine du serveur Flask) — jamais réécrit par le refactor
asset_url de templates/play.html (celui-ci ne touche que les