Estante 3D: entradas, orden A–Z, sin conexión, pósit y giroscopio calibrado

- Estante: entradas desde el menú, la librería y la ficha; orden reciente o A–Z; foto del estante, arte de lomos y portadas
  guardados en el dispositivo; sin conexión muestra solo lo guardado.
- Notas de 40 letras sin cortar palabras, lomo curvo, sombra en las portadas de frente y lomos con logo sin el título.
- Pósit cuadrado con el capítulo y la página por la que va el usuario; paso al lector sin pantalla de carga.
- Giroscopio: integra rotationRate (sin los saltos de β/γ con el dispositivo vertical), tope suave, menos sensibilidad al
  caminar, lado en horizontal según la gravedad, suavizado por tiempo y más rango en el estante y el libro.
- Laboratorio del giroscopio en Ajustes (temporal, solo desarrollo) para grabar los sensores.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-06 21:12:58 -06:00
co-authored by Claude Opus 5.5
parent e40127265f
commit d7400f27ad
8 changed files with 539 additions and 108 deletions
+15 -15
View File
@@ -487,25 +487,25 @@ body.reading #netbanner { display: none; }
.reader.b3d.b3dcrop { background: #000; }
.reader.b3d.b3dcrop > #b3d { display: none; }
.reader.b3d.b3dcrop > #pages img { visibility: visible; }
/* Vistazo del estante: la nota del tomo sacado, como un pósit pegado junto a él (a la derecha en apaisado, abajo en vertical).
/* Vistazo del estante: la nota del tomo sacado, un pósit cuadrado pegado junto a él (a la derecha en apaisado, abajo en vertical).
Papel, tinta, letra e inclinación son los de la nota de su colección en la balda (--np, --ni, --nf, --nw, --ns, --nt). */
.shelfpeek { --np: #fff27a; --ni: #24242e; --nf: cursive; --nw: 400; --ns: 1; --nt: 0deg;
position: fixed; z-index: 3; right: calc(4vw + env(safe-area-inset-right)); top: 50%; width: min(36vw, 360px); transform: translate(14px, -50%) rotate(var(--nt)); opacity: 0; transition: opacity .22s, transform .26s;
padding: 30px 20px 18px; border-radius: 2px 2px 3px 18px / 2px 2px 3px 10px; color: var(--ni); font-family: var(--nf), cursive; font-weight: var(--nw);
background: linear-gradient(180deg, rgb(0 0 0 / .07) 0 22px, transparent 22px), linear-gradient(160deg, rgb(255 255 255 / .18), transparent 40%), linear-gradient(0deg, rgb(0 0 0 / .1), transparent 30%), var(--np);
.shelfpeek { --np: #fff27a; --ni: #24242e; --nf: cursive; --nw: 400; --ns: 1; --nt: 0deg; --side: min(34vw, 330px);
position: fixed; z-index: 3; right: calc(5vw + env(safe-area-inset-right)); top: 50%; width: var(--side); height: var(--side); box-sizing: border-box;
display: flex; flex-direction: column; overflow: hidden; transform: translate(14px, -50%) rotate(var(--nt)); opacity: 0; transition: opacity .22s, transform .26s;
padding: 34px 22px 18px; border-radius: 1px 1px 2px 14px / 1px 1px 2px 8px; color: var(--ni); font-family: var(--nf), cursive; font-weight: var(--nw);
background: linear-gradient(180deg, rgb(0 0 0 / .07) 0 24px, transparent 24px), linear-gradient(160deg, rgb(255 255 255 / .18), transparent 40%), linear-gradient(0deg, rgb(0 0 0 / .1), transparent 30%), var(--np);
box-shadow: 0 1px 1px rgb(0 0 0 / .18), 4px 14px 22px -8px rgb(0 0 0 / .55); }
.shelfpeek.on { opacity: 1; transform: translate(0, -50%) rotate(var(--nt)); }
.shelfpeek .ptitle { margin: 0 30px 6px 0; font-family: inherit; font-weight: inherit; font-size: calc(1.75rem * var(--ns)); line-height: 1.05; overflow-wrap: anywhere; }
.shelfpeek .psub, .shelfpeek .pwhere { margin: 4px 0; font-size: calc(1.15rem * var(--ns)); line-height: 1.2; opacity: .85; }
.shelfpeek .pbar { height: 5px; margin: 12px 0 6px; border-radius: 3px; background: color-mix(in srgb, var(--ni) 16%, transparent); overflow: hidden; }
.shelfpeek .pbar i { display: block; height: 100%; background: var(--ni); opacity: .75; border-radius: 3px; }
.shelfpeek .pacts { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px; }
.shelfpeek .pacts .btn { flex: 1 1 auto; justify-content: center; font-family: inherit; font-weight: inherit; font-size: calc(1.15rem * var(--ns)); background: transparent; color: var(--ni); border: 2px solid var(--ni); border-radius: 14px 10px 16px 9px / 10px 15px 9px 14px; box-shadow: none; }
.shelfpeek .pacts .btn.primary { background: var(--ni); color: var(--np); }
.shelfpeek .peekx { position: absolute; top: 4px; right: 6px; width: 32px; height: 32px; display: grid; place-items: center; border: 0; border-radius: 50%; background: transparent; color: inherit; cursor: pointer; opacity: .7; }
.shelfpeek .ptitle { margin: 0 26px 8px 0; font-family: inherit; font-weight: inherit; font-size: calc(clamp(1.3rem, 2.6vw, 1.8rem) * var(--ns)); line-height: 1.05; overflow-wrap: anywhere; }
.shelfpeek .psub, .shelfpeek .pwhere, .shelfpeek .phint { margin: 4px 0; font-size: calc(clamp(1rem, 1.7vw, 1.2rem) * var(--ns)); line-height: 1.2; }
.shelfpeek .psub { opacity: .8; }
.shelfpeek .phint { margin-top: auto; color: inherit; text-decoration: none; opacity: .75; }
.shelfpeek .peekx { position: absolute; top: 2px; right: 4px; width: 30px; height: 30px; display: grid; place-items: center; border: 0; border-radius: 50%; background: transparent; color: inherit; cursor: pointer; opacity: .6; }
@media (orientation: portrait) {
.shelfpeek { left: calc(14px + env(safe-area-inset-left)); right: calc(14px + env(safe-area-inset-right)); top: auto; bottom: calc(14px + env(safe-area-inset-bottom)); width: auto; transform: translateY(14px) rotate(var(--nt)); }
.shelfpeek.on { transform: rotate(var(--nt)); }
.shelfpeek { --side: min(64vw, 300px); right: auto; left: 50%; top: auto; bottom: calc(18px + env(safe-area-inset-bottom)); transform: translate(-50%, 14px) rotate(var(--nt)); }
.shelfpeek.on { transform: translate(-50%, 0) rotate(var(--nt)); }
.shelfpeek .ptitle { font-size: calc(1.45rem * var(--ns)); }
.shelfpeek .psub, .shelfpeek .pwhere, .shelfpeek .phint { font-size: calc(1.08rem * var(--ns)); }
}
body.handing .reader .loading { visibility: hidden; }
.handoff { position: fixed; inset: 0; z-index: 60; width: 100vw; height: 100vh; object-fit: cover; pointer-events: none; transition: opacity .35s ease; }