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:
parent
e12c40e00c
commit
0419114755
3 changed files with 167 additions and 155 deletions
|
|
@ -1,93 +1,97 @@
|
|||
/* 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
|
||||
Keycloak n'a pas de <canvas>). Respecte prefers-reduced-motion.
|
||||
Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */
|
||||
Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Keycloak
|
||||
n'a pas de <canvas>). Attend le DOM (le script est injecté dans <head>).
|
||||
Respecte prefers-reduced-motion. Métaphore : chaque artisan est une étoile ;
|
||||
reliés, ils forment la constellation. */
|
||||
(function () {
|
||||
"use strict";
|
||||
if (document.querySelector(".ab-sky")) return;
|
||||
|
||||
var sky = document.createElement("div");
|
||||
sky.className = "ab-sky";
|
||||
sky.setAttribute("aria-hidden", "true");
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.id = "ab-constellation";
|
||||
var aurora = document.createElement("div");
|
||||
aurora.className = "ab-aurora";
|
||||
sky.appendChild(canvas);
|
||||
sky.appendChild(aurora);
|
||||
document.body.insertBefore(sky, document.body.firstChild);
|
||||
function init() {
|
||||
if (!document.body || document.querySelector(".ab-sky")) return;
|
||||
|
||||
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var stars = [];
|
||||
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
var LINK_DIST = 130;
|
||||
var sky = document.createElement("div");
|
||||
sky.className = "ab-sky";
|
||||
sky.setAttribute("aria-hidden", "true");
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.id = "ab-constellation";
|
||||
var aurora = document.createElement("div");
|
||||
aurora.className = "ab-aurora";
|
||||
sky.appendChild(canvas);
|
||||
sky.appendChild(aurora);
|
||||
document.body.insertBefore(sky, document.body.firstChild);
|
||||
|
||||
function resize() {
|
||||
w = canvas.clientWidth;
|
||||
h = canvas.clientHeight;
|
||||
canvas.width = w * dpr;
|
||||
canvas.height = h * dpr;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
seed();
|
||||
}
|
||||
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var stars = [];
|
||||
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
var LINK_DIST = 130;
|
||||
|
||||
function seed() {
|
||||
var count = Math.round((w * h) / 14000);
|
||||
count = Math.max(40, Math.min(160, count));
|
||||
stars = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
x: Math.random() * w,
|
||||
y: Math.random() * h,
|
||||
r: Math.random() * 1.3 + 0.4,
|
||||
vx: (Math.random() - 0.5) * 0.12,
|
||||
vy: (Math.random() - 0.5) * 0.12,
|
||||
tw: Math.random() * Math.PI * 2
|
||||
});
|
||||
function resize() {
|
||||
w = canvas.clientWidth || window.innerWidth;
|
||||
h = canvas.clientHeight || window.innerHeight;
|
||||
canvas.width = w * dpr;
|
||||
canvas.height = h * dpr;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
seed();
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (var i = 0; i < stars.length; i++) {
|
||||
for (var j = i + 1; j < stars.length; j++) {
|
||||
var dx = stars[i].x - stars[j].x;
|
||||
var dy = stars[i].y - stars[j].y;
|
||||
var d = Math.sqrt(dx * dx + dy * dy);
|
||||
if (d < LINK_DIST) {
|
||||
var a = (1 - d / LINK_DIST) * 0.22;
|
||||
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(stars[i].x, stars[i].y);
|
||||
ctx.lineTo(stars[j].x, stars[j].y);
|
||||
ctx.stroke();
|
||||
function seed() {
|
||||
var count = Math.round((w * h) / 14000);
|
||||
count = Math.max(40, Math.min(160, count));
|
||||
stars = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
x: Math.random() * w, y: Math.random() * h,
|
||||
r: Math.random() * 1.3 + 0.4,
|
||||
vx: (Math.random() - 0.5) * 0.12, vy: (Math.random() - 0.5) * 0.12,
|
||||
tw: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (var i = 0; i < stars.length; i++) {
|
||||
for (var j = i + 1; j < stars.length; j++) {
|
||||
var dx = stars[i].x - stars[j].x, dy = stars[i].y - stars[j].y;
|
||||
var d = Math.sqrt(dx * dx + dy * dy);
|
||||
if (d < LINK_DIST) {
|
||||
ctx.strokeStyle = "rgba(120, 200, 255," + (1 - d / LINK_DIST) * 0.22 + ")";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(stars[i].x, stars[i].y);
|
||||
ctx.lineTo(stars[j].x, stars[j].y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
var s = stars[k];
|
||||
s.tw += 0.02;
|
||||
var glow = 0.6 + Math.sin(s.tw) * 0.4;
|
||||
ctx.beginPath();
|
||||
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(255,255,255," + glow + ")";
|
||||
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
||||
ctx.shadowBlur = 6;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
if (!reduce) {
|
||||
s.x += s.vx;
|
||||
s.y += s.vy;
|
||||
if (s.x < 0 || s.x > w) s.vx *= -1;
|
||||
if (s.y < 0 || s.y > h) s.vy *= -1;
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
var s = stars[k];
|
||||
s.tw += 0.02;
|
||||
ctx.beginPath();
|
||||
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(255,255,255," + (0.6 + Math.sin(s.tw) * 0.4) + ")";
|
||||
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
||||
ctx.shadowBlur = 6;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
if (!reduce) {
|
||||
s.x += s.vx; s.y += s.vy;
|
||||
if (s.x < 0 || s.x > w) s.vx *= -1;
|
||||
if (s.y < 0 || s.y > h) s.vy *= -1;
|
||||
}
|
||||
}
|
||||
if (!reduce) requestAnimationFrame(draw);
|
||||
}
|
||||
if (!reduce) requestAnimationFrame(draw);
|
||||
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
draw();
|
||||
}
|
||||
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
draw();
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,11 @@ html, body {
|
|||
height: 100%;
|
||||
font-family: var(--font);
|
||||
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,
|
||||
body .login-pf-page {
|
||||
|
|
|
|||
|
|
@ -1,93 +1,97 @@
|
|||
/* 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
|
||||
Keycloak n'a pas de <canvas>). Respecte prefers-reduced-motion.
|
||||
Métaphore : chaque artisan est une étoile ; reliés, ils forment la constellation. */
|
||||
Vanilla JS, aucune dépendance. Crée son propre ciel en fond (le template Keycloak
|
||||
n'a pas de <canvas>). Attend le DOM (le script est injecté dans <head>).
|
||||
Respecte prefers-reduced-motion. Métaphore : chaque artisan est une étoile ;
|
||||
reliés, ils forment la constellation. */
|
||||
(function () {
|
||||
"use strict";
|
||||
if (document.querySelector(".ab-sky")) return;
|
||||
|
||||
var sky = document.createElement("div");
|
||||
sky.className = "ab-sky";
|
||||
sky.setAttribute("aria-hidden", "true");
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.id = "ab-constellation";
|
||||
var aurora = document.createElement("div");
|
||||
aurora.className = "ab-aurora";
|
||||
sky.appendChild(canvas);
|
||||
sky.appendChild(aurora);
|
||||
document.body.insertBefore(sky, document.body.firstChild);
|
||||
function init() {
|
||||
if (!document.body || document.querySelector(".ab-sky")) return;
|
||||
|
||||
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var stars = [];
|
||||
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
var LINK_DIST = 130;
|
||||
var sky = document.createElement("div");
|
||||
sky.className = "ab-sky";
|
||||
sky.setAttribute("aria-hidden", "true");
|
||||
var canvas = document.createElement("canvas");
|
||||
canvas.id = "ab-constellation";
|
||||
var aurora = document.createElement("div");
|
||||
aurora.className = "ab-aurora";
|
||||
sky.appendChild(canvas);
|
||||
sky.appendChild(aurora);
|
||||
document.body.insertBefore(sky, document.body.firstChild);
|
||||
|
||||
function resize() {
|
||||
w = canvas.clientWidth;
|
||||
h = canvas.clientHeight;
|
||||
canvas.width = w * dpr;
|
||||
canvas.height = h * dpr;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
seed();
|
||||
}
|
||||
var reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
||||
var ctx = canvas.getContext("2d");
|
||||
var stars = [];
|
||||
var w = 0, h = 0, dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||
var LINK_DIST = 130;
|
||||
|
||||
function seed() {
|
||||
var count = Math.round((w * h) / 14000);
|
||||
count = Math.max(40, Math.min(160, count));
|
||||
stars = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
x: Math.random() * w,
|
||||
y: Math.random() * h,
|
||||
r: Math.random() * 1.3 + 0.4,
|
||||
vx: (Math.random() - 0.5) * 0.12,
|
||||
vy: (Math.random() - 0.5) * 0.12,
|
||||
tw: Math.random() * Math.PI * 2
|
||||
});
|
||||
function resize() {
|
||||
w = canvas.clientWidth || window.innerWidth;
|
||||
h = canvas.clientHeight || window.innerHeight;
|
||||
canvas.width = w * dpr;
|
||||
canvas.height = h * dpr;
|
||||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
||||
seed();
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (var i = 0; i < stars.length; i++) {
|
||||
for (var j = i + 1; j < stars.length; j++) {
|
||||
var dx = stars[i].x - stars[j].x;
|
||||
var dy = stars[i].y - stars[j].y;
|
||||
var d = Math.sqrt(dx * dx + dy * dy);
|
||||
if (d < LINK_DIST) {
|
||||
var a = (1 - d / LINK_DIST) * 0.22;
|
||||
ctx.strokeStyle = "rgba(120, 200, 255," + a + ")";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(stars[i].x, stars[i].y);
|
||||
ctx.lineTo(stars[j].x, stars[j].y);
|
||||
ctx.stroke();
|
||||
function seed() {
|
||||
var count = Math.round((w * h) / 14000);
|
||||
count = Math.max(40, Math.min(160, count));
|
||||
stars = [];
|
||||
for (var i = 0; i < count; i++) {
|
||||
stars.push({
|
||||
x: Math.random() * w, y: Math.random() * h,
|
||||
r: Math.random() * 1.3 + 0.4,
|
||||
vx: (Math.random() - 0.5) * 0.12, vy: (Math.random() - 0.5) * 0.12,
|
||||
tw: Math.random() * Math.PI * 2
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function draw() {
|
||||
ctx.clearRect(0, 0, w, h);
|
||||
for (var i = 0; i < stars.length; i++) {
|
||||
for (var j = i + 1; j < stars.length; j++) {
|
||||
var dx = stars[i].x - stars[j].x, dy = stars[i].y - stars[j].y;
|
||||
var d = Math.sqrt(dx * dx + dy * dy);
|
||||
if (d < LINK_DIST) {
|
||||
ctx.strokeStyle = "rgba(120, 200, 255," + (1 - d / LINK_DIST) * 0.22 + ")";
|
||||
ctx.lineWidth = 1;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(stars[i].x, stars[i].y);
|
||||
ctx.lineTo(stars[j].x, stars[j].y);
|
||||
ctx.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
var s = stars[k];
|
||||
s.tw += 0.02;
|
||||
var glow = 0.6 + Math.sin(s.tw) * 0.4;
|
||||
ctx.beginPath();
|
||||
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(255,255,255," + glow + ")";
|
||||
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
||||
ctx.shadowBlur = 6;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
if (!reduce) {
|
||||
s.x += s.vx;
|
||||
s.y += s.vy;
|
||||
if (s.x < 0 || s.x > w) s.vx *= -1;
|
||||
if (s.y < 0 || s.y > h) s.vy *= -1;
|
||||
for (var k = 0; k < stars.length; k++) {
|
||||
var s = stars[k];
|
||||
s.tw += 0.02;
|
||||
ctx.beginPath();
|
||||
ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
|
||||
ctx.fillStyle = "rgba(255,255,255," + (0.6 + Math.sin(s.tw) * 0.4) + ")";
|
||||
ctx.shadowColor = "rgba(160,220,255,0.9)";
|
||||
ctx.shadowBlur = 6;
|
||||
ctx.fill();
|
||||
ctx.shadowBlur = 0;
|
||||
if (!reduce) {
|
||||
s.x += s.vx; s.y += s.vy;
|
||||
if (s.x < 0 || s.x > w) s.vx *= -1;
|
||||
if (s.y < 0 || s.y > h) s.vy *= -1;
|
||||
}
|
||||
}
|
||||
if (!reduce) requestAnimationFrame(draw);
|
||||
}
|
||||
if (!reduce) requestAnimationFrame(draw);
|
||||
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
draw();
|
||||
}
|
||||
|
||||
window.addEventListener("resize", resize);
|
||||
resize();
|
||||
draw();
|
||||
if (document.readyState === "loading") {
|
||||
document.addEventListener("DOMContentLoaded", init);
|
||||
} else {
|
||||
init();
|
||||
}
|
||||
})();
|
||||
|
|
|
|||
Loading…
Reference in a new issue