Thème Keycloak : faire apparaître la constellation (attendre le DOM)

Keycloak injecte le script dans <head> → il tournait avant que <body>
existe (insertBefore plantait) → pas de canvas. Corrigé : init différé à
DOMContentLoaded + repli taille sur window.innerWidth/Height. Dégradé aurore
posé aussi sur body (repli si le canvas échoue). Script copié côté account.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-04 09:44:42 -04:00
parent e12c40e00c
commit 0419114755
3 changed files with 167 additions and 155 deletions

View file

@ -1,10 +1,13 @@
/* Alliance Boréale champ d'étoiles + constellation, adapté au login Keycloak. /* Alliance Boréale champ d'étoiles + constellation, adapté au login Keycloak.
Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Keycloak
Keycloak n'a pas de <canvas>). Respecte prefers-reduced-motion. n'a pas de <canvas>). Attend le DOM (le script est injecté dans <head>).
Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */ Respecte prefers-reduced-motion. Métaphore : chaque artisan est une étoile ;
reliés, ils forment la constellation. */
(function () { (function () {
"use strict"; "use strict";
if (document.querySelector(".ab-sky")) return;
function init() {
if (!document.body || document.querySelector(".ab-sky")) return;
var sky = document.createElement("div"); var sky = document.createElement("div");
sky.className = "ab-sky"; sky.className = "ab-sky";
@ -24,8 +27,8 @@
var LINK_DIST = 130; var LINK_DIST = 130;
function resize() { function resize() {
w = canvas.clientWidth; w = canvas.clientWidth || window.innerWidth;
h = canvas.clientHeight; h = canvas.clientHeight || window.innerHeight;
canvas.width = w * dpr; canvas.width = w * dpr;
canvas.height = h * dpr; canvas.height = h * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
@ -38,11 +41,9 @@
stars = []; stars = [];
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
stars.push({ stars.push({
x: Math.random() * w, x: Math.random() * w, y: Math.random() * h,
y: Math.random() * h,
r: Math.random() * 1.3 + 0.4, r: Math.random() * 1.3 + 0.4,
vx: (Math.random() - 0.5) * 0.12, vx: (Math.random() - 0.5) * 0.12, vy: (Math.random() - 0.5) * 0.12,
vy: (Math.random() - 0.5) * 0.12,
tw: Math.random() * Math.PI * 2 tw: Math.random() * Math.PI * 2
}); });
} }
@ -52,12 +53,10 @@
ctx.clearRect(0, 0, w, h); ctx.clearRect(0, 0, w, h);
for (var i = 0; i < stars.length; i++) { for (var i = 0; i < stars.length; i++) {
for (var j = i + 1; j < stars.length; j++) { for (var j = i + 1; j < stars.length; j++) {
var dx = stars[i].x - stars[j].x; var dx = stars[i].x - stars[j].x, dy = stars[i].y - stars[j].y;
var dy = stars[i].y - stars[j].y;
var d = Math.sqrt(dx * dx + dy * dy); var d = Math.sqrt(dx * dx + dy * dy);
if (d < LINK_DIST) { if (d < LINK_DIST) {
var a = (1 - d / LINK_DIST) * 0.22; ctx.strokeStyle = "rgba(120, 200, 255," + (1 - d / LINK_DIST) * 0.22 + ")";
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(stars[i].x, stars[i].y); ctx.moveTo(stars[i].x, stars[i].y);
@ -69,17 +68,15 @@
for (var k = 0; k < stars.length; k++) { for (var k = 0; k < stars.length; k++) {
var s = stars[k]; var s = stars[k];
s.tw += 0.02; s.tw += 0.02;
var glow = 0.6 + Math.sin(s.tw) * 0.4;
ctx.beginPath(); ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2); ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
ctx.fillStyle = "rgba(255,255,255," + glow + ")"; ctx.fillStyle = "rgba(255,255,255," + (0.6 + Math.sin(s.tw) * 0.4) + ")";
ctx.shadowColor = "rgba(160,220,255,0.9)"; ctx.shadowColor = "rgba(160,220,255,0.9)";
ctx.shadowBlur = 6; ctx.shadowBlur = 6;
ctx.fill(); ctx.fill();
ctx.shadowBlur = 0; ctx.shadowBlur = 0;
if (!reduce) { if (!reduce) {
s.x += s.vx; s.x += s.vx; s.y += s.vy;
s.y += s.vy;
if (s.x < 0 || s.x > w) s.vx *= -1; if (s.x < 0 || s.x > w) s.vx *= -1;
if (s.y < 0 || s.y > h) s.vy *= -1; if (s.y < 0 || s.y > h) s.vy *= -1;
} }
@ -90,4 +87,11 @@
window.addEventListener("resize", resize); window.addEventListener("resize", resize);
resize(); resize();
draw(); draw();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})(); })();

View file

@ -22,7 +22,11 @@ html, body {
height: 100%; height: 100%;
font-family: var(--font); font-family: var(--font);
color: var(--ink); color: var(--ink);
background: #05060f !important; /* Dégradé aurore en repli (visible même si le canvas ne se crée pas). */
background:
radial-gradient(1200px 700px at 80% -10%, #131a44 0%, transparent 60%),
radial-gradient(900px 600px at 10% 0%, #0e1640 0%, transparent 55%),
linear-gradient(180deg, var(--bg-2) 0%, var(--bg) 70%) fixed !important;
} }
.login-pf-page, .login-pf-page,
body .login-pf-page { body .login-pf-page {

View file

@ -1,10 +1,13 @@
/* Alliance Boréale champ d'étoiles + constellation, adapté au login Keycloak. /* Alliance Boréale champ d'étoiles + constellation, adapté au login Keycloak.
Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Keycloak
Keycloak n'a pas de <canvas>). Respecte prefers-reduced-motion. n'a pas de <canvas>). Attend le DOM (le script est injecté dans <head>).
Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */ Respecte prefers-reduced-motion. Métaphore : chaque artisan est une étoile ;
reliés, ils forment la constellation. */
(function () { (function () {
"use strict"; "use strict";
if (document.querySelector(".ab-sky")) return;
function init() {
if (!document.body || document.querySelector(".ab-sky")) return;
var sky = document.createElement("div"); var sky = document.createElement("div");
sky.className = "ab-sky"; sky.className = "ab-sky";
@ -24,8 +27,8 @@
var LINK_DIST = 130; var LINK_DIST = 130;
function resize() { function resize() {
w = canvas.clientWidth; w = canvas.clientWidth || window.innerWidth;
h = canvas.clientHeight; h = canvas.clientHeight || window.innerHeight;
canvas.width = w * dpr; canvas.width = w * dpr;
canvas.height = h * dpr; canvas.height = h * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0); ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
@ -38,11 +41,9 @@
stars = []; stars = [];
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
stars.push({ stars.push({
x: Math.random() * w, x: Math.random() * w, y: Math.random() * h,
y: Math.random() * h,
r: Math.random() * 1.3 + 0.4, r: Math.random() * 1.3 + 0.4,
vx: (Math.random() - 0.5) * 0.12, vx: (Math.random() - 0.5) * 0.12, vy: (Math.random() - 0.5) * 0.12,
vy: (Math.random() - 0.5) * 0.12,
tw: Math.random() * Math.PI * 2 tw: Math.random() * Math.PI * 2
}); });
} }
@ -52,12 +53,10 @@
ctx.clearRect(0, 0, w, h); ctx.clearRect(0, 0, w, h);
for (var i = 0; i < stars.length; i++) { for (var i = 0; i < stars.length; i++) {
for (var j = i + 1; j < stars.length; j++) { for (var j = i + 1; j < stars.length; j++) {
var dx = stars[i].x - stars[j].x; var dx = stars[i].x - stars[j].x, dy = stars[i].y - stars[j].y;
var dy = stars[i].y - stars[j].y;
var d = Math.sqrt(dx * dx + dy * dy); var d = Math.sqrt(dx * dx + dy * dy);
if (d < LINK_DIST) { if (d < LINK_DIST) {
var a = (1 - d / LINK_DIST) * 0.22; ctx.strokeStyle = "rgba(120, 200, 255," + (1 - d / LINK_DIST) * 0.22 + ")";
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
ctx.lineWidth = 1; ctx.lineWidth = 1;
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(stars[i].x, stars[i].y); ctx.moveTo(stars[i].x, stars[i].y);
@ -69,17 +68,15 @@
for (var k = 0; k < stars.length; k++) { for (var k = 0; k < stars.length; k++) {
var s = stars[k]; var s = stars[k];
s.tw += 0.02; s.tw += 0.02;
var glow = 0.6 + Math.sin(s.tw) * 0.4;
ctx.beginPath(); ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2); ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
ctx.fillStyle = "rgba(255,255,255," + glow + ")"; ctx.fillStyle = "rgba(255,255,255," + (0.6 + Math.sin(s.tw) * 0.4) + ")";
ctx.shadowColor = "rgba(160,220,255,0.9)"; ctx.shadowColor = "rgba(160,220,255,0.9)";
ctx.shadowBlur = 6; ctx.shadowBlur = 6;
ctx.fill(); ctx.fill();
ctx.shadowBlur = 0; ctx.shadowBlur = 0;
if (!reduce) { if (!reduce) {
s.x += s.vx; s.x += s.vx; s.y += s.vy;
s.y += s.vy;
if (s.x < 0 || s.x > w) s.vx *= -1; if (s.x < 0 || s.x > w) s.vx *= -1;
if (s.y < 0 || s.y > h) s.vy *= -1; if (s.y < 0 || s.y > h) s.vy *= -1;
} }
@ -90,4 +87,11 @@
window.addEventListener("resize", resize); window.addEventListener("resize", resize);
resize(); resize();
draw(); draw();
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})(); })();