Opens in a new tab

Albina — zboara in jurul cursorului

Pagina live: /albina/. Nu e un port: e o piesa scrisa de noi, care refoloseste albina Lottie si tratamentul umbrei de la LeoParpeix, dar o conduce cu mouse-ul in loc de scroll.

Ce face

  • Un singur ecran galben, un titlu scurt, si albina care zboara in preajma cursorului — fara sa se aseze vreodata pe el.
  • Efectul vine din trei intarzieri suprapuse, si asta e tot secretul: (1) o ancora urmareste cursorul, incet; (2) un punct de orbita se roteste la nesfarsit in jurul ancorei; (3) albina urmareste punctul de orbita, ceva mai repede. Pentru ca pasul 2 nu se opreste niciodata, albina continua sa dea ocol si cand mouse-ul sta pe loc, in loc sa se parcheze pe cursor.
  • Orbita e turtita pe verticala (ORBIT_FLATTEN = 0.55), ceea ce citeste ca perspectiva: pare ca da ocol pe orizontala, nu ca deseneaza un cerc pe ecran.
  • Inclinarea vine din viteza ei orizontala, nu din pozitia cursorului — deci se inclina in directia in care chiar merge, inclusiv cand se intoarce singura in orbita.
  • Umbra foloseste distanta ramasa pana la ancora ca senzatie de inaltime: cand goneste dupa cursor se departeaza si paleste, cand s-a asezat in cerc se strange sub ea.
  • Pana la prima miscare de mouse — si deci pe orice ecran tactil, unde aceea nu vine niciodata — cursorul e inlocuit de doua sinusoide lente, iar albina hoinareste singura prin ecran. Pagina nu arata niciodata moarta la incarcare.

Ce cere site-ul

  • GSAP 3.13.0 — deja global. Se folosesc doar gsap.set, gsap.ticker si gsap.utils.clamp.
  • lottie-web 5.13.0, build-ul lottie_svg.min.js, incarcat cu un tag <script> creat din JS, doar pe pagina asta. Acelasi fisier leo-bee.json ca la LeoParpeix — nu s-a mai urcat inca o copie.
  • Fara ScrollTrigger si fara Lenis. Pagina nu are scroll deloc, deci nu exista un proprietar al scroll-ului si nu se bate cu nimic. In tabelul de compatibilitate sta la grupa 3 (GSAP plus un fisier tras de pe CDN), nu la grupa 2, exact din cauza lui lottie.
  • Fonts: DM Sans, acelasi ca la LeoParpeix.

Cum e construit in Bricks

O sectiune, un element Code. Markup-ul are 610 octeti — o secventa de titlu si doua div-uri goale pe care le umple lottie.

  • Sectiunea .alb e position: fixed; inset: 0, adica e chiar viewport-ul. Asta e alegerea care scuteste toata aritmetica: clientX / clientY de la mouse se pun direct pe x / y la albina, fara corectii de scroll sau de offset.
  • Page settings: bodyClasses: albina, headerDisabled, footerDisabled, disableLazyLoad.
  • body.albina { overflow: hidden } — o pagina de un singur ecran nu trebuie sa poata fi derulata.
  • Ca la orice port: *, titlul si restul sunt scopate sub .alb, iar color: #000 si font-size: 16px sunt puse explicit pentru ca tema pune gri si 15px.
  • Titlul are doua variante, comutate din CSS: „Misca mouse-ul” pe desktop si „Albina zboara singura” sub @media (hover: none), (pointer: coarse). Fara asta, pe telefon pagina ar cere ceva ce nu se poate face acolo.

Reglaje

Cele patru numere de sus din JS schimba complet caracterul zborului:

Constanta Acum Ce face
ORBIT_R 90px cat de larg da ocol cursorului
ORBIT_SPEED 1.5 rad/s cat de repede se invarte
ANCHOR_EASE 0.055 cat de repede vine cand misti mouse-ul
BEE_EASE 0.13 cat de strans tine cercul

Capcane

  • Interpolarea pe cadru nu e acelasi lucru cu interpolarea pe secunda. x += (tinta - x) * 0.13 merge de doua ori mai repede pe un ecran la 120Hz decat pe unul la 60Hz. Aici toate cele trei urmariri trec prin approach(), care corecteaza cu 1 - Math.pow(1 - ease, dt * 60) — aceeasi fractie pe secunda, indiferent de monitor. La fel si inclinarea, impartita la dt * 60.
  • Delta de la ticker se plafoneaza. Math.min(deltaMs, 50): dupa o pauza de tab, un delta de doua secunde ar teleporta albina. Cu plafon, isi reia zborul de unde a ramas.
  • Bara de admin adauga 32px de scroll (html { margin-top: 32px }), deci pagina pare derulabila cat esti logat. Vizitatorul delogat nu o vede. Nu e un defect al paginii — se verifica cu document.getElementById('wpadminbar') inainte sa dai vina pe CSS.
  • Pe 390px albina iese pana la 75px dincolo de marginea din dreapta, pentru ca orbita de 90px plus amplitudinea hoinarelii depasesc jumatatea ecranului. Lasat intentionat asa — o albina care iese o clipa din cadru si revine arata natural. Nu produce scroll orizontal. Daca cineva vrea totusi sa o tina in ecran, solutia e sa lege ORBIT_R si amplitudinea de latimea viewport-ului, nu sa le lase fixe.
  • Spre deosebire de LeoParpeix, aici requestAnimationFrame chiar merge in tabul de automatizare (72 de cadre in 1200ms), deci zborul se poate verifica direct. Nu presupune nici intr-o parte, nici in alta: citeste gsap.ticker.frame de doua ori si compara.

Pasi de reproducere

  1. Fa sectiunea position: fixed; inset: 0 si pune overflow: hidden pe body. De aici incolo coordonatele mouse-ului sunt direct coordonatele albinei.
  2. Incarca lottie-web (build-ul svg) cu un tag <script> creat din JS si porneste abia dupa onload. Randeaza acelasi JSON de doua ori: o data albina, o data umbra, filtrata brightness(0) blur(2px) si turtita scaleY: 0.5.
  3. Tine trei perechi de coordonate: cursorul, ancora, albina. Ancora urmareste cursorul; punctul de orbita se roteste in jurul ancorei; albina urmareste punctul de orbita. Toate trei prin approach(), corectat de rata de cadre.
  4. Inclinarea din viteza orizontala proprie, limitata la ±18 grade. Umbra din distanta ramasa pana la ancora.
  5. Steagul following porneste false si devine true la primul mousemove. Cat e false, cursorul e generat din doua sinusoide cu perioade fara numitor comun, ca traseul sa nu se repete vizibil. Asta acopera si ecranele tactile, fara nicio detectie de dispozitiv.
  6. Scrie pagina cu wp_slash() si signature => wp_hash($code), verifica md5 la citire, apoi \Bricks\Breakpoints::regenerate_bricks_css_files().
  7. Verifica pe pagina, in ordinea asta: (a) gsap.ticker.frame creste; (b) fara niciun mousemove, albina se misca singura; (c) trimisa cu dispatchEvent intr-un colt, ajunge acolo; (d) cu cursorul tinut nemiscat, pozitia ei continua sa varieze — dovada ca orbiteaza si nu se parcheaza.