# Full Dominoes — Pack 06

Lo del 6 fue la pista que faltaba. Con eso encontré la causa real del giro
y resultó ser el mismo error de raíz en dos lugares distintos.

---

## 1. Archivos

| Archivo | Destino | Tipo |
|---|---|---|
| `public/assets/js/sala.js` | `public/assets/js/` | **reemplaza** |
| `public/assets/js/tablero3d.js` | `public/assets/js/` | **reemplaza** |
| `public/assets/js/btn-lobby-luz.js` | `public/assets/js/` | **reemplaza** (v2) |
| `public/assets/js/fd-fondo-vivo.js` | `public/assets/js/` | **reemplaza** |
| `public/assets/js/fd-experiencia.js` | `public/assets/js/` | **reemplaza** |
| `public/assets/js/fd-profundidad.js` | `public/assets/js/` | igual que el 04 |
| `public/assets/css/fd-experiencia.css` | `public/assets/css/` | igual que el 04 |
| `public/home.html` | `public/` | **reemplaza** |
| `public/index.html` | `public/` | **reemplaza** (login) |

---

## 2. El 6 que se comportaba como doble

Esto lo encontraste vos y fue lo que destrabó todo.

```js
const celdas = (valor === 6 && !esDoble) ? PATRON_6_SUELTO : PATRONES_PIP[valor];
```

El 6 se dibuja en **dos columnas** si la ficha está parada y en **dos
filas** si está acostada. Pero el código no preguntaba cómo estaba puesta
la ficha: preguntaba si era doble.

Funcionaba de casualidad. Como los dobles eran las únicas fichas que se
ponen paradas, *"es doble"* hacía de sinónimo de *"está parada"*. El
sinónimo se rompe en el momento exacto en que una ficha **normal** se
para — que es justo la bisagra de un giro. Por eso un 6 en la esquina
salía con el patrón del doble.

Ahora se pregunta lo que de verdad importa:

```js
const parada = !horizontal;
const celdas = (valor === 6 && !parada) ? PATRON_6_SUELTO : PATRONES_PIP[valor];
```

Estaba en dos archivos con la misma lógica: `tablero3d.js` (la mesa 3D) y
`sala.js` (la mano y la ficha ganadora). Corregidos los dos.

---

## 3. El giro: en la mitad, no en la esquina

Y acá está lo bueno — es **el mismo error de raíz**: una cuenta que
dependía de si la ficha anterior era doble.

```js
x = cursor.x + dirX * (anchoAnterior / 2 - FP_BISAGRA.ancho / 2);
```

La bisagra se alineaba con el **borde exterior** de la ficha anterior. Ese
desplazamiento depende del ancho de esa ficha:

| Ficha anterior | Ancho | Desplazamiento | Cómo se ve el giro |
|---|---|---|---|
| normal | 54 | 13.5 px | cruza por la **esquina** |
| doble | 27 | 0 px | cruza por el **centro** |

O sea que el giro salía de una forma o de la otra **según qué ficha
hubiera caído justo antes**, sin que el jugador hiciera nada distinto. Un
giro centrado y el siguiente en la esquina. Exactamente lo que describiste.

Ahora la bisagra se centra siempre:

```js
x = cursor.x;   // el codo cruza SIEMPRE por el centro de la última ficha
```

Verificado con manos de 27 fichas a un mismo lado, forzando dobles en
distintas posiciones:

```
sin dobles                      -> codos: dx=0.0 (anterior ancho 54) | dx=0.0 (54)
doble justo antes del 1er codo  -> codos: dx=0.0 (anterior ancho 27) | dx=0.0 (54)
doble antes de ambos codos      -> codos: dx=0.0 (27) | dx=0.0 (27)
dobles por todos lados          -> codos: dx=0.0 (54) | dx=0.0 (54)
```

`dx=0.0` en los cuatro casos, con la ficha anterior midiendo 54 o 27
indistintamente. El giro se lee igual siempre. Cero solapamientos.

---

## 4. Pips negro absoluto

Los dos intentos anteriores fallaron por el mismo motivo: pusieron luz
**dentro** del pip. Cualquier cosa dibujada encima del negro lo sube de
valor, y un negro con 5% de blanco encima ya no es negro — es gris oscuro,
y contra el marfil se lee apagado.

Ahora la iluminación va **solo por fuera**, que es como se reconoce un
hueco real de todos modos:

- **Realce del bisel**: un anillo apenas más claro que el marfil, pegado
  al borde del pip. Es lo que lo levanta de la cara.
- **Sombra del canto**, desplazada abajo-derecha (la luz de la escena
  viene de arriba-izquierda).
- **El pip**: `#000000` puro, sin una sola capa encima.

Y las fichas: exposición **1.32 → 1.52**, y el marfil deja de bajar hasta
`#f0ece1` — ahora su punto más oscuro es `#f7f4ec`. Esa esquina apagada
arrastraba a toda la ficha sobre el fondo neón. El veteado se sigue
notando porque lo que lo hace visible es el contraste entre manchas, no lo
oscuro que sea el fondo.

---

## 5. Botones: la ola en orden

Todos destellaban a la vez porque compartían la misma animación sin
desfase — y eso los hacía parecer un cartel de neón, no una interfaz.

Ahora cada uno arranca desfasado 0.42s respecto al anterior, así que se ve
una ola recorriendo la columna.

Dos detalles que hacen que funcione bien:

- **El orden es visual, no del DOM.** Se mide con
  `getBoundingClientRect()` y se ordena de arriba hacia abajo (agrupando
  por bandas de 40px, para que dos botones a la misma altura se ordenen
  entre sí por X). En el lobby el orden del HTML no coincide con lo que se
  ve, y usando el del documento la ola saltaba de un lado a otro.
- **El desfase es un `animation-delay` negativo.** Con delay positivo, la
  primera vuelta dejaría al último botón apagado casi 4 segundos esperando
  su turno. Negativo, arrancan todos ya, cada uno en un punto distinto de
  su ciclo.

---

## 6. Login

Los cinco botones del login reciben la misma luz: invitado, Google,
Facebook, crear cuenta e iniciar sesión. Con dos paletas nuevas —
**nieve** para Google (es un botón claro y un aro de color lo ensuciaría)
y **facebook** en su azul.

**Los logos de Google y Facebook no se tocan.** Son marcas registradas y
tienen que quedar exactamente como son; ahí solo se suma la luz.

El login también recibe el fondo animado y las ondas al pulsar.

---

## 7. Estrellas fugaces

En `fd-fondo-vivo.js`. Entran por el borde de arriba y cruzan en diagonal
de 25 a 40 grados — más plano se lee como un rayo, más vertical como
lluvia. La cola no es una línea: es un gradiente que va de la cabeza
blanca a transparente, porque lo que se ve en una fugaz real es el rastro
apagándose.

Van **muy espaciadas a propósito**: una cada 4 a 11 segundos. Un cielo con
fugaces constantes deja de leerse como cielo y pasa a ser un protector de
pantalla; lo que las hace funcionar es que sean un acontecimiento, no un
adorno permanente. La primera tarda 2.5-6s en salir, para que no parezca
parte de la animación de carga.

**En la mesa de juego están desactivadas.** Durante una mano la atención
tiene que estar en las fichas, y un destello cruzando la pantalla justo
cuando vas a soltar una es exactamente lo contrario de lo que querés.

Para ajustarlas:

```js
FDFondoVivo.configurar({ estrellaMin: 2500, estrellaMax: 7000 });
FDFondoVivo.configurar({ estrellasActivas: false });
```
