Wijzigen voor document Tekenveld
Laatst gewijzigd door Jeeves de Butler op 23-10-2026 02:42
Van versie 3.1
gewijzigd door Jeeves de Butler
op 16-10-2026 12:29
op 16-10-2026 12:29
Opmerking bij wijziging:
Er is geen opmerking bij deze versie
Naar versie 8.1
gewijzigd door Jeeves de Butler
op 19-10-2026 01:23
op 19-10-2026 01:23
Opmerking bij wijziging:
Er is geen opmerking bij deze versie
Samenvatting
-
Objecten (1 gewijzigd, 3 toegevoegd, 0 verwijderd)
Details
- XWiki.JavaScriptExtension[0]
-
- code
-
... ... @@ -1,5 +1,5 @@ 1 1 /* Tekenveld voor de Kennisbank. Gemaakt met maak-tekenveld.js uit de skill xwiki-wardenburg-admin. 2 - Engine: Ember src/lib/glyphField.js, commit 2af047d. Niet hier wijzigen: pas de bron aan en maak opnieuw. */2 + Engine: Ember src/lib/glyphField.js, commit 83ea536. Niet hier wijzigen: pas de bron aan en maak opnieuw. */ 3 3 (function () { 4 4 "use strict"; 5 5 // /src/lib/glyphField.js ... ... @@ -258,9 +258,11 @@ 258 258 const styles = getComputedStyle(root); 259 259 const text = styles.getPropertyValue("--text").trim() || "#111827"; 260 260 const accent = styles.getPropertyValue("--brand-red").trim() || "#e62b27"; 261 + // Een eigen kleur voor de hartslaglijn (ECG); zonder --glyph-line is dat het accent, zoals in Ember. 262 + const line = styles.getPropertyValue("--glyph-line").trim() || accent; 261 261 // :root zonder attribuut is in Ember donker; zie layout.css. 262 262 const mode = root.getAttribute("data-appearance") === "light" ? "light" : "dark"; 263 - return { text, accent, mode }; 265 + return { text, accent, line, mode }; 264 264 } 265 265 266 266 /* De tekens van een thema: een niet-lege lijst van hooguit 256 tekens (de index staat in een Uint8Array). */ ... ... @@ -305,9 +305,12 @@ 305 305 let trail = new Float32Array(0); 306 306 let pulse = new Float32Array(0); 307 307 let streak = new Float32Array(0); 310 + // Het spoor van de hartslaglijn apart van dat van de smileys, zodat de lijn een eigen kleur kan hebben. 311 + let lineTrail = new Float32Array(0); 308 308 let quiet = new Float32Array(0); 309 309 let neutralAtlas = null; 310 310 let accentAtlas = null; 315 + let lineAtlas = null; 311 311 let yellowAtlas = null; 312 312 let orangeAtlas = null; 313 313 let smokeAtlas = null; ... ... @@ -356,6 +356,7 @@ 356 356 function buildAtlases() { 357 357 neutralAtlas = buildAtlas(theme.text); 358 358 accentAtlas = buildAtlas(theme.accent); 364 + lineAtlas = theme.line === theme.accent ? accentAtlas : buildAtlas(theme.line); 359 359 // Vuurkleuren voor de explosie. 360 360 yellowAtlas = buildAtlas(theme.mode === "light" ? "#eab308" : "#facc15"); 361 361 orangeAtlas = buildAtlas("#f97316"); ... ... @@ -387,6 +387,7 @@ 387 387 trail = new Float32Array(cols * rows); 388 388 pulse = new Float32Array(cols * rows); 389 389 streak = new Float32Array(cols * rows); 396 + lineTrail = new Float32Array(cols * rows); 390 390 quiet = new Float32Array(cols * rows); 391 391 minC = minR = 1; 392 392 maxC = maxR = 0; ... ... @@ -398,7 +398,7 @@ 398 398 399 399 function applyTheme() { 400 400 const next = readTheme(); 401 - if (next.text === theme.text && next.accent === theme.accent && next.mode === theme.mode) return; 408 + if (next.text === theme.text && next.accent === theme.accent && next.line === theme.line && next.mode === theme.mode) return; 402 402 theme = next; 403 403 buildAtlases(); 404 404 lastAmbient = -Infinity; ... ... @@ -625,7 +625,7 @@ 625 625 const phase = x / ecg.beatWidth + ecg.offset; 626 626 const y = ecg.baseY - (ecgShape(phase % 1) * beatScale(ecg, Math.floor(phase)) + wander) * ecg.amplitude; 627 627 if (Math.hypot(x - ecg.stampX, y - ecg.stampY) >= options.ecgRadius * 0.3) { 628 - stamp(x, y, options.ecgRadius, options.ecgStrength, true, streak);635 + stamp(x, y, options.ecgRadius, options.ecgStrength, true, lineTrail); 629 629 ecg.stampX = x; 630 630 ecg.stampY = y; 631 631 } ... ... @@ -801,8 +801,9 @@ 801 801 let heat = trail[index]; 802 802 let beat = pulse[index]; 803 803 let flash = streak[index]; 811 + let pulseLine = lineTrail[index]; 804 804 let hush = quiet[index]; 805 - if (heat <= 0 && beat <= 0 && flash <= 0 && hush <= 0) continue; 813 + if (heat <= 0 && beat <= 0 && flash <= 0 && pulseLine <= 0 && hush <= 0) continue; 806 806 807 807 if (heat > 0) { 808 808 heat *= decay; ... ... @@ -819,12 +819,17 @@ 819 819 if (flash < 0.03) flash = 0; 820 820 streak[index] = flash; 821 821 } 830 + if (pulseLine > 0) { 831 + pulseLine *= streakDecay; 832 + if (pulseLine < 0.03) pulseLine = 0; 833 + lineTrail[index] = pulseLine; 834 + } 822 822 if (hush > 0) { 823 823 hush *= streakDecay; 824 824 if (hush < 0.03) hush = 0; 825 825 quiet[index] = hush; 826 826 } 827 - if (heat === 0 && beat === 0 && flash === 0 && hush === 0) continue; 840 + if (heat === 0 && beat === 0 && flash === 0 && pulseLine === 0 && hush === 0) continue; 828 828 829 829 if (c < nextMinC) nextMinC = c; 830 830 if (c > nextMaxC) nextMaxC = c; ... ... @@ -832,7 +832,7 @@ 832 832 if (r > nextMaxR) nextMaxR = r; 833 833 834 834 // Onder het spoor en de hartslag wisselen de tekens snel. 835 - if (dt > 0 && Math.random() < (heat * 9 + beat * 5 + flash * 6) * dt) glyphs[index] = randomGlyph(); 848 + if (dt > 0 && Math.random() < (heat * 9 + beat * 5 + (flash + pulseLine) * 6) * dt) glyphs[index] = randomGlyph(); 836 836 837 837 // Een verse ring is roder dan het spoor; verder weg is hij al zwakker en daarmee 838 838 // vanzelf grijzer. ... ... @@ -846,9 +846,10 @@ 846 846 const x = cellX(c); 847 847 const sx = glyphs[index] * tileW; 848 848 // Achter een smiley wordt het rustende veld stilgezet (hush), zodat het gezicht 849 - // niet in de wolken verdwijnt. De lijn en desmileys (flash) zijn vooral rood.850 - const neutral = ambient[index] * calm * (1 - lift) * (1 - hush) + neutralMax * lift + streakNeutral * flash; 862 + // niet in de wolken verdwijnt. De smileys (flash) en de hartslaglijn (pulseLine) zijn vooral rood; de lijn in --glyph-line. 863 + const neutral = ambient[index] * calm * (1 - lift) * (1 - hush) + neutralMax * lift + streakNeutral * Math.max(flash, pulseLine); 851 851 const red = Math.max(glow * glow * accentMax, flash * streakAccent); 865 + const lineRed = pulseLine * streakAccent; 852 852 ctx.clearRect(x, y, tileW, tileH); 853 853 if (neutral >= MIN_ALPHA) { 854 854 ctx.globalAlpha = neutral; ... ... @@ -858,6 +858,10 @@ 858 858 ctx.globalAlpha = Math.min(1, red); 859 859 ctx.drawImage(accentAtlas, sx, 0, tileW, tileH, x, y, tileW, tileH); 860 860 } 875 + if (lineRed > 0.01) { 876 + ctx.globalAlpha = Math.min(1, lineRed); 877 + ctx.drawImage(lineAtlas, sx, 0, tileW, tileH, x, y, tileW, tileH); 878 + } 861 861 } 862 862 } 863 863 ... ... @@ -1186,6 +1186,7 @@ 1186 1186 fallers = null; 1187 1187 canvas.style.transform = ""; 1188 1188 streak.fill(0); 1207 + lineTrail.fill(0); 1189 1189 quiet.fill(0); 1190 1190 minC = minR = 1; 1191 1191 maxC = maxR = 0; ... ... @@ -1287,6 +1287,13 @@ 1287 1287 // beeldverkeer op de terminalserver); bij de eerste beweging loopt het weer. 1288 1288 const KB_STILSTAND_MS = 60000; 1289 1289 1309 +// De explosie van de engine: vijf klikken op de lege achtergrond binnen 1,6 seconde, met een 1310 +// nasleep van een minuut. Dezelfde getallen als de standaard van de engine; hier alleen om 1311 +// tijdens de explosie het vervagen naar het midden weg te halen en het veld wakker te houden. 1312 +const KB_BOEM_KLIKKEN = 5; 1313 +const KB_BOEM_VENSTER_MS = 1600; 1314 +const KB_BOEM_DUUR_MS = 62000; 1315 + 1290 1290 function kbTekenveld() { 1291 1291 // Alleen op de startpagina; de extensie wordt ook alleen daar geladen. 1292 1292 if (!document.querySelector(".wb-home")) return; ... ... @@ -1299,29 +1299,59 @@ 1299 1299 canvas.setAttribute("aria-hidden", "true"); 1300 1300 document.body.prepend(canvas); 1301 1301 1328 + const isAchtergrond = (event) => event.target instanceof Element && !event.target.closest(KB_NIET_ACHTERGROND); 1302 1302 const opties = { 1303 1303 ...glyphFieldSettings({ intensity: "lijst" }), 1304 - // Geen atoomexplosie op de Kennisbank. 1305 - nukeClicks: Infinity, 1306 - isBackground: (event) => event.target instanceof Element && !event.target.closest(KB_NIET_ACHTERGROND), 1331 + isBackground: isAchtergrond, 1307 1307 obstacles: () => Array.from(document.querySelectorAll(KB_BLOKKEN), (element) => element.getBoundingClientRect()), 1308 1308 }; 1309 1309 1310 1310 let veld = null; 1311 1311 let rustTimer = 0; 1337 + let klikken = []; 1338 + let boemTot = 0; 1312 1312 1313 - function wakker() { 1314 - if (!veld) veld = createGlyphField(canvas, opties); 1340 + function slaap() { 1341 + // Tijdens een explosie niet: de nasleep duurt een minuut, ook zonder muis. 1342 + if (Date.now() < boemTot) { 1343 + rustTimer = window.setTimeout(slaap, boemTot - Date.now()); 1344 + return; 1345 + } 1346 + // Het laatste beeld blijft staan; alleen de animatie stopt. 1347 + veld.destroy(); 1348 + veld = null; 1349 + } 1350 + 1351 + // De klik die een slapend veld wekt, ziet de engine zelf niet (hij luistert pas daarna); 1352 + // die telt hier dus ook niet mee, anders lopen de twee tellers uiteen. 1353 + let wekklik = null; 1354 + 1355 + function wakker(event) { 1356 + if (!veld) { 1357 + veld = createGlyphField(canvas, opties); 1358 + wekklik = event || null; 1359 + } 1315 1315 window.clearTimeout(rustTimer); 1316 - rustTimer = window.setTimeout(() => { 1317 - // Het laatste beeld blijft staan; alleen de animatie stopt. 1318 - veld.destroy(); 1319 - veld = null; 1320 - }, KB_STILSTAND_MS); 1361 + rustTimer = window.setTimeout(slaap, KB_STILSTAND_MS); 1321 1321 } 1322 1322 1364 + function telKlik(event) { 1365 + const nu = Date.now(); 1366 + if (event === wekklik || event.button !== 0 || nu < boemTot || !isAchtergrond(event)) return; 1367 + klikken = klikken.filter((tijd) => nu - tijd < KB_BOEM_VENSTER_MS); 1368 + klikken.push(nu); 1369 + if (klikken.length < KB_BOEM_KLIKKEN) return; 1370 + klikken = []; 1371 + boemTot = nu + KB_BOEM_DUUR_MS; 1372 + // Tijdens de explosie het hele scherm, niet alleen de randen. 1373 + canvas.classList.add("kb-tekenveld--boem"); 1374 + window.setTimeout(() => canvas.classList.remove("kb-tekenveld--boem"), KB_BOEM_DUUR_MS); 1375 + } 1376 + 1323 1323 window.addEventListener("pointermove", wakker, { passive: true }); 1378 + // Eerst wakker maken, zodat de engine de klik ook krijgt als het veld sliep. 1324 1324 window.addEventListener("pointerdown", wakker, { passive: true }); 1380 + window.addEventListener("pointerdown", telKlik, { passive: true }); 1325 1325 wakker(); 1326 1326 } 1327 1327
- XWiki.StyleSheetExtension[0]
-
- Caching policy
-
... ... @@ -1,0 +1,1 @@ 1 +long - Code
-
... ... @@ -1,0 +1,54 @@ 1 +/* Tekenveld op de startpagina van de Kennisbank (Wardenburg.Code.Tekenveld); alleen geladen op 2 + de startpagina. Het canvas ligt achter de inhoud; de vlakken eromheen worden doorzichtig. */ 3 + 4 +/* Kleuren voor de engine: de tekstkleur en het donkere oranje (brand-warning) uit het kleurthema; 5 + de hartslaglijn in het rood van het thema (brand-danger). */ 6 +html { 7 + --text: #202124; 8 + --brand-red: #e8920c; 9 + --glyph-line: #d0021b; 10 + background: #ffffff; 11 +} 12 + 13 +body, 14 +#body, 15 +#contentcontainer, 16 +#contentcolumn, 17 +#mainContentArea, 18 +.main, 19 +#xwikicontent, 20 +.wb-home { 21 + background: transparent !important; 22 +} 23 + 24 +canvas.kb-tekenveld { 25 + position: fixed; 26 + inset: 0; 27 + z-index: -1; 28 + pointer-events: none; 29 + /* Naar het midden, waar het zoekveld en de tegels staan, vervaagt het veld tot 40%: het zwakke 30 + grijze veld is daar vrijwel weg, de rode hartslaglijn komt er nog doorheen. */ 31 + -webkit-mask-image: radial-gradient(ellipse 48% 58% at 50% 55%, rgba(0, 0, 0, .4) 45%, #000 100%); 32 + mask-image: radial-gradient(ellipse 48% 58% at 50% 55%, rgba(0, 0, 0, .4) 45%, #000 100%); 33 +} 34 + 35 +/* Tijdens de explosie (vijf snelle klikken) het hele scherm. */ 36 +canvas.kb-tekenveld.kb-tekenveld--boem { 37 + -webkit-mask-image: none; 38 + mask-image: none; 39 +} 40 + 41 +/* Leesbaarheid: een zachte witte gloed achter de kop, het zoekveld en elke tegel. */ 42 +.wb-zoek > h1, 43 +.wb-zoek > p, 44 +.wb-zoek > form, 45 +.wb-tegels > li > a { 46 + background: radial-gradient(closest-side, rgba(255, 255, 255, .97) 62%, rgba(255, 255, 255, 0) 100%); 47 +} 48 + 49 +.wb-home-onder { 50 + background: #ffffff; 51 + border-radius: 16px; 52 + box-shadow: 0 0 36px 28px #ffffff; 53 +} 54 + - Content Type
-
... ... @@ -1,0 +1,1 @@ 1 +CSS - Naam
-
... ... @@ -1,0 +1,1 @@ 1 +Wardenburg tekenveld - Inhoud verwerken
-
... ... @@ -1,0 +1,1 @@ 1 +Nee - Gebruik deze uitbreiding
-
... ... @@ -1,0 +1,1 @@ 1 +onDemand
- XWiki.XWikiRights[1]
-
- allow
-
... ... @@ -1,0 +1,1 @@ 1 +Sta toe - groups
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.XWikiAllGroup - levels
-
... ... @@ -1,0 +1,1 @@ 1 +view
- XWiki.XWikiRights[2]
-
- allow
-
... ... @@ -1,0 +1,1 @@ 1 +Sta toe - groups
-
... ... @@ -1,0 +1,1 @@ 1 +XWiki.XWikiAdminGroup - levels
-
... ... @@ -1,0 +1,1 @@ 1 +view,edit,comment,script