Changeset 084b046 in Klonkt for src/assets


Ignore:
Timestamp:
08/12/2026 08:04:38 PM (3 months ago)
Author:
Robin <roboburr@…>
Children:
5218863
Parents:
a5a6249
Message:

De Ward PWA: de avatarhemel achter de kaarten

Plak 3. Robins correctie: niet de hemel IN PLAATS VAN de kaarten, maar
allebei, met de hemel er altijd achter. Zelfde beweging als in Shaer: de
kaarten vallen weg en wat eronder lag was er al.

MODEL EN RENDERER APART, en die naad is het punt. orbitPlacement en
nearestFace zijn pure wiskunde en bestaan nu drie keer (Swift, Kotlin,
hier). Drie keer kans op drift, en drift zie je niet aan een screenshot:
je ziet het als gezichten ergens anders hangen dan in de app. Daarom in
een eigen module, met dezelfde eigenschappen bewaakt als AvatarSkyTest.kt.

CANVAS, GEEN ENGINE, en dat is een afweging en geen luiheid. De rem is
niet het aantal sprites maar het aantal texturen: alle avatars gaan een
keer in een atlas, daarna is elk gezicht een drawImage uit datzelfde
plaatje. Dat haalt duizenden. Wil het ooit meer, dan vervangt een
WebGL-variant alleen SkyRenderer en merkt de rest er niets van. De echte
schaaloplossing is trouwens niet sneller tekenen maar clusteren; dat
staat als bead voor later.

New file:
src/assets/js/ward-sky.js

  • orbitPlacement + nearestFace, letterlijke port
  • SkyRenderer: atlas, ademhaling, pan, zoom, tik

test/ward-sky.test.js

  • vers dichterbij dan oud, deterministisch, geen overlap, mikken kiest de dichtstbijzijnde en schaalt mee met de zoom

Changed files:
src/routes/ward.js

  • /api/conversations: per tegenpartij het jongste bericht
  • /sky.js als eigen asset

src/views/pages/ward.ejs

  • canvas achter alles, wisselknop, app.js als module

src/assets/js/ward.js

  • de wissel: kaarten of hemel, hemel draait altijd

src/assets/css/ward.css

  • hemel op z-index 0, kaarten erboven

src/services/i18n.js

  • drie sleutels in nl, en, de

remarks: 895 tests groen. Een tik op een gezicht wijst naar /ward/thread,
en die route bestaat nog niet; dat is de volgende plak.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

Location:
src/assets
Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • src/assets/css/ward.css

    ra5a6249 r084b046  
    8686  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
    8787}
     88
     89/* ── De hemel ─────────────────────────────────────────────────────────── */
     90/* Ligt achter alles en draait altijd. In kaartenstand is hij decor; in
     91   berichtenstand vallen de kaarten weg en is hij de interface. */
     92#sky { position: fixed; inset: 0; width: 100%; height: 100%; z-index: 0; }
     93#app { position: relative; z-index: 1; }
     94.topbar { display: flex; align-items: center; gap: 12px; }
     95.topbar h1 { margin: 8px 0 20px; }
     96.topbar #mode {
     97  margin-left: auto; border: 0; border-radius: 999px; padding: 8px 16px;
     98  background: #2a3342; color: var(--ink); font: inherit;
     99}
     100/* De kaarten vallen weg, de hemel blijft: dezelfde beweging als in de app. */
     101body.messages-mode .help, body.messages-mode .cards { display: none; }
  • src/assets/js/ward.js

    ra5a6249 r084b046  
    77 * pagina en dit bestand tekent hem. Alles wat nieuw is komt van /ward/api/*.
    88 */
    9 'use strict';
     9import { SkyRenderer } from '/ward/sky.js';
    1010
    1111const state = JSON.parse(document.getElementById('ward-state').textContent);
    … …  
    215215}
    216216
    217 /** De controle kost per guardian een remote fetch, dus hij komt ná het tekenen. */
     217/**
     218 * De hemel en de kaarten zijn één scherm met twee standen.
     219 *
     220 * De hemel draait ALTIJD en ligt achter de kaarten; in kaartenstand is hij
     221 * decor en vangt hij geen tikken, in berichtenstand vallen de kaarten weg en
     222 * wordt hij de interface. Dat is precies de beweging uit Shaer: de kaarten
     223 * vallen weg en wat eronder lag was er al.
     224 */
     225function wireSky() {
     226  const canvas = document.getElementById('sky');
     227  const btn = document.getElementById('mode');
     228  const main = document.getElementById('app');
     229  let convs = [];
     230
     231  const sky = new SkyRenderer(canvas, (i) => {
     232    const c = convs[i];
     233    if (c) window.location.href = `/ward/thread?with=${encodeURIComponent(c.uri)}`;
     234  });
     235
     236  let messagesMode = false;
     237  const setMode = (on) => {
     238    messagesMode = on;
     239    sky.interactive = on;
     240    canvas.setAttribute('aria-hidden', String(!on));
     241    // touch-action pas uitzetten als de hemel echt bedienbaar is: anders kun
     242    // je in kaartenstand niet meer scrollen.
     243    canvas.style.touchAction = on ? 'none' : '';
     244    canvas.style.pointerEvents = on ? 'auto' : 'none';
     245    document.body.classList.toggle('messages-mode', on);
     246    btn.textContent = on ? state.strings.toCards : state.strings.toSky;
     247    btn.setAttribute('aria-pressed', String(on));
     248    main.querySelectorAll('section').forEach((sec) => { sec.hidden = on; });
     249  };
     250
     251  btn.addEventListener('click', () => setMode(!messagesMode));
     252  setMode(false);
     253
     254  (async () => {
     255    try {
     256      const r = await fetch('/ward/api/conversations', { headers: { Accept: 'application/json' } });
     257      if (!r.ok) return;
     258      convs = (await r.json()).items || [];
     259      await sky.setFaces(convs.map((c) => ({ name: c.name, icon: c.icon, ageMs: c.ageMs })));
     260      sky.start();
     261    } catch { /* zonder hemel blijft het scherm gewoon werken */ }
     262  })();
     263}
     264
     265/** De controle kost per guardian een remote fetch, dus hij komt ná het tekenen. *//** De controle kost per guardian een remote fetch, dus hij komt ná het tekenen. */
    218266async function loadChecks() {
    219267  if (!state.guardians.length) return;
    … …  
    240288renderGuardians(null);
    241289wireBuoy();
     290wireSky();
    242291loadFeed();
    243292renderOffers();
Note: See TracChangeset for help on using the changeset viewer.