Estante 3D: mueble, lomos, logos y vista previa de tomos

This commit is contained in:
2026-11-06 09:28:23 -06:00
parent 66502409fe
commit bda8800a89
19 changed files with 1649 additions and 15 deletions
+7 -6
View File
@@ -115,9 +115,9 @@ export function fitCamera(points, aspect, marginX, marginY) {
// Colores de la portada para la contraportada y sus botones.
const luma = c => { const f = v => (v <= 0.03928 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4); return 0.2126 * f(c[0]) + 0.7152 * f(c[1]) + 0.0722 * f(c[2]) }
const contrast = (a, b) => { const x = luma(a), y = luma(b); return (Math.max(x, y) + 0.05) / (Math.min(x, y) + 0.05) }
const inkOn = c => (contrast(c, [1, 1, 1]) >= contrast(c, [0.07, 0.06, 0.05]) ? [1, 1, 1] : [0.07, 0.06, 0.05])
export const inkOn = c => (contrast(c, [1, 1, 1]) >= contrast(c, [0.07, 0.06, 0.05]) ? [1, 1, 1] : [0.07, 0.06, 0.05])
const mixColor = (a, b, t) => a.map((n, k) => n + (b[k] - n) * t)
const css = c => `rgb(${c.map(n => Math.round(n * 255)).join(' ')})`
export const css = c => `rgb(${c.map(n => Math.round(n * 255)).join(' ')})`
// Color dominante y color de acento: el acento es el que más destaca sobre el dominante, sin ser una mota de la imagen.
export function coverPalette(data) {
const boxes = new Map()
@@ -143,7 +143,7 @@ export function coverPalette(data) {
}
// Madera generada: se repite sin que se note el corte.
function woodCanvas() {
export function woodCanvas() {
const S = 1024, PLANKS = 5, canvas = Object.assign(document.createElement('canvas'), { width: S, height: S }), g = canvas.getContext('2d')
let seed = 7
const rnd = () => (seed = (seed * 16807) % 2147483647) / 2147483647
@@ -243,7 +243,7 @@ void main() {
}`
// Junta rejillas en una malla: pos(3) normal(3) uv(2).
class Shape {
export class Shape {
constructor() { this.v = []; this.i = [] }
grid(cols, rows, at) {
const base = this.v.length / 8
@@ -305,8 +305,9 @@ function rimShape(pts, y0, y1, thick) {
// El sensor: los ejes de la pantalla a partir de la orientación del dispositivo. La inclinación se desvanece con el tiempo.
// MAX_DEG: lo que hay que girar el dispositivo para llegar al tope. ORBIT_*: cuánto rodea entonces la cámara al libro, en grados.
const MAX_DEG = 15, FADE_S = 2.5, QUIET = 0.6, ORBIT_TILT = 7, ORBIT_YAW = 10, ORBIT_BACK = 0.06
function createTilt(onChange) {
export const MAX_DEG = 15
const FADE_S = 2.5, QUIET = 0.6, ORBIT_TILT = 7, ORBIT_YAW = 10, ORBIT_BACK = 0.06
export function createTilt(onChange) {
const target = { x: 0, y: 0 }
let listening = false, gotOrientation = false, lastT = 0, lastOri = null, lastFade = 0, askOnTouch = null
const clamp = v => Math.max(-MAX_DEG, Math.min(MAX_DEG, v))