parent
6c9b1d2fb3
commit
4a00402db0
@ -0,0 +1,71 @@
|
||||
# Continuación de Juegoland — 4 de octubre de 2026
|
||||
|
||||
El usuario ha pedido terminar los cambios actuales, dejar este handoff, hacer commit y push y cerrar por hoy. Los componentes de cartas y los juegos nuevos quedan para la siguiente sesión.
|
||||
|
||||
## Trabajo cerrado
|
||||
|
||||
- El parchís sigue la distribución del tablero de referencia: rojo arriba a la izquierda, azul arriba a la derecha, verde abajo a la izquierda y amarillo abajo a la derecha. Las 68 casillas, sus números, las salidas 5/22/39/56 y los pasillos se dibujan con la geometría clásica. Los índices del motor se conservan, incluidos los de partidas antiguas.
|
||||
- Solo las cuatro casillas de salida del parchís tienen popover. En la oca lo conservan las casillas especiales; las normales y el inicio no lo tienen.
|
||||
- Los colores de las fichas son vivos y el amarillo es amarillo. La paleta compartida y los tokens visuales tienen los mismos colores sólidos; los textos del chat conservan tonos legibles para claro y oscuro.
|
||||
- El centro de cada casa del parchís muestra el avatar del jugador. Si no hay avatar, aparecen sus iniciales; las casas libres mantienen un símbolo neutro.
|
||||
- En mesas de dos o tres jugadores, cada jugador puede elegir entre todos los colores libres. Solo se asigna automáticamente el último color cuando se agota la paleta: cuatro jugadores con cuatro colores u ocho con ocho. Un color ocupado se rechaza y cambiar de color desmarca «listo».
|
||||
- El arreglo anterior del chat se conserva: utiliza primero el margen derecho libre y no desplaza el tablero mientras haya espacio.
|
||||
|
||||
## Código de referencia
|
||||
|
||||
- `shared/parchis-board.mjs`: geometría de casillas, números, casas, salidas y pasillos.
|
||||
- `src/lib/components/ParchisMap.svelte`: tablero, avatares, fichas, animaciones y popovers de salida.
|
||||
- `src/lib/components/OcaBoard.svelte`: interacción solo en casillas especiales y contraste de números de fichas.
|
||||
- `shared/player-colors.mjs`: paleta y función `receivesLastColor`.
|
||||
- `server/platform.mjs` y `src/lib/components/PlayerColorChooser.svelte`: asignación y elección de colores.
|
||||
- `src/tokens.css` y `src/app.css`: sistema visual. Consultar `docs/design-system.md`, `docs/typography.md` y `docs/room-layout.md` antes de tocar estilos.
|
||||
- `tests/parchis-board.test.ts` y `tests/platform.test.ts`: posición de casillas y selección de colores, además de las pruebas existentes.
|
||||
|
||||
## Verificación y despliegue
|
||||
|
||||
La suite contiene 81 pruebas. Ejecutar `npm run design:check`, `npm run check`, `npm test -- --maxWorkers=1` y `npm run build` al modificar el proyecto. La revisión visual de este cambio utiliza dos identidades sintéticas y un servidor aislado en `127.0.0.1:4185`; sus archivos y capturas están en `artifacts/`, ignorado por Git. No reiniciar los servidores de otras sesiones de Codex.
|
||||
|
||||
El estado del despliegue se registra en `deploy/server-status.md`. Al cierre de esta sesión quedó activada la versión `20261004-12`, con 81 pruebas aprobadas en Linux y respuesta HTTP 200 del endpoint público de salud. Comprobar allí y con `readlink /opt/mesa-abierta/current` la versión vigente antes de continuar.
|
||||
|
||||
- Proyecto local: `G:\dev\svelte\games`, rama `main`.
|
||||
- Repositorio: `https://g.activething.com/go/Juegoland.git`.
|
||||
- VM: `192.168.18.155`.
|
||||
- Servicio único: `mesa-game`, escucha en `0.0.0.0:3000` para web, API y WebSockets.
|
||||
- Dominio vigente: `https://juegoland.imaginacion.com/`. Usar este dominio en invitaciones; las menciones antiguas a games/juegolang ya no son la dirección vigente.
|
||||
- El proxy Nginx existente de la red apunta a `http://192.168.18.155:3000`. No instalar otro proxy ni Docker Compose en la VM. `mesa-web` y Nginx de la VM están deshabilitados.
|
||||
- PostgreSQL y las credenciales actuales se conservan. No copiar secretos al repositorio ni imprimirlos.
|
||||
- SSH por IPv4 con la clave local `$env:USERPROFILE\.ssh\senzapaura_deploy`. APT y npm deben usar IPv4.
|
||||
- Despliegue nativo: `deploy/deploy-native.ps1 -Release <identificador nuevo> -Activate`. Verifica, hace copia de seguridad, migra y activa la versión; no reutilizar identificadores existentes.
|
||||
|
||||
## Siguiente sesión: componentes de cartas
|
||||
|
||||
El usuario preparará imágenes de la baraja española y de póquer. Todavía no se han recibido ni se han creado estos componentes. Preparar una base reutilizable para carta, reverso, mano, mazo, descarte y bazas/mesa. Separar datos, imágenes, reglas e interacción; cada juego define sus acciones, animaciones y sonidos.
|
||||
|
||||
Prever baraja española de 40/48 cartas y póquer de 52 con comodines opcionales. Identificar cartas por palo y valor mediante un manifiesto de recursos. Mantener manos legibles en móvil, selección accesible y acciones legales claras. No sustituir las imágenes que traerá el usuario por otra baraja.
|
||||
|
||||
El servidor debe autorizar las acciones y ocultar las manos ajenas. Revisar `Platform.view` y la proyección `game.view(state, seat)` antes de implementar estados privados. Esta misma base sirve para dados ocultos y tableros privados de barcos.
|
||||
|
||||
## Juegos solicitados para incorporar poco a poco
|
||||
|
||||
Cartas: brisca, tute de dos jugadores, la 31 y cinquillo. Otras posibilidades mencionadas para valorar después: escoba, chinchón, tute por parejas, pocha y mus.
|
||||
|
||||
Otros juegos solicitados:
|
||||
|
||||
- Serpientes y escaleras: el usuario aportará las imágenes del tablero, como hizo con la oca.
|
||||
- Guerra de barcos / hundir la flota: tableros privados de cada jugador.
|
||||
- El ahorcado.
|
||||
- Tres en raya.
|
||||
- Conecta cuatro.
|
||||
- Mancala: concretar la variante antes de implementar reglas.
|
||||
- Shut the Box: concretar dados y puntuación.
|
||||
- El mentiroso de dados y otros juegos de dados: concretar variantes y dados ocultos.
|
||||
|
||||
No están implementados ni deben presentarse como disponibles en el catálogo. Incorporarlos uno a uno con motor, interfaz, reglas, sonidos, animaciones y validación completos.
|
||||
|
||||
## Preferencias que hay que respetar
|
||||
|
||||
Usar el skill `C:\Users\dev\.codex\skills\frontend-design\SKILL.md`. Conservar el logo transparente y la identidad de Juegoland, los tokens de tipografía y espaciado y las opciones de tema claro/oscuro. Revisar capturas en escritorio y móvil: tamaños, alineaciones y proporciones son una prioridad expresa del usuario.
|
||||
|
||||
Mantener PIN de cuatro cifras, registro opcional, invitaciones con mensaje del anfitrión, avatares editables, notificación de mensajes con el chat cerrado y partidas pendientes. Sonidos y animaciones deben diferenciarse por juego y acción. El popup de entrada debe ser breve; «No acepto» y Escape llevan a `https://imaginacion.com/`. No volver a añadir páginas legales extensas ni un aviso en lugar del popup.
|
||||
|
||||
Este handoff no programa tareas para mañana ni abre otra sesión.
|
||||
@ -0,0 +1,54 @@
|
||||
// Classic board: three equal sectors on each axis, eight rectangular cells per arm.
|
||||
export const parchisStarts = [4, 21, 38, 55];
|
||||
export const parchisHomes = [
|
||||
[400, 400],
|
||||
[400, 0],
|
||||
[0, 0],
|
||||
[0, 400],
|
||||
];
|
||||
const laneWidth = 200 / 3;
|
||||
function cell(x, y, width, height, angle) {
|
||||
const center = [x + width / 2, y + height / 2];
|
||||
const label = [...center];
|
||||
if (height === 25 && x !== 200 + laneWidth)
|
||||
label[0] = x === 200 ? x + width - 11 : x + 11;
|
||||
if (width === 25 && y !== 200 + laneWidth)
|
||||
label[1] = y === 200 ? y + height - 11 : y + 11;
|
||||
return { x, y, width, height, angle, center, label };
|
||||
}
|
||||
const track = [];
|
||||
for (let i = 7; i >= 0; i--)
|
||||
track.push(cell(200 + 2 * laneWidth, 400 + i * 25, laneWidth, 25, 0));
|
||||
for (let i = 0; i < 8; i++)
|
||||
track.push(cell(400 + i * 25, 200 + 2 * laneWidth, 25, laneWidth, 90));
|
||||
track.push(cell(575, 200 + laneWidth, 25, laneWidth, 90));
|
||||
for (let i = 7; i >= 0; i--)
|
||||
track.push(cell(400 + i * 25, 200, 25, laneWidth, 90));
|
||||
for (let i = 7; i >= 0; i--)
|
||||
track.push(cell(200 + 2 * laneWidth, i * 25, laneWidth, 25, 180));
|
||||
track.push(cell(200 + laneWidth, 0, laneWidth, 25, 180));
|
||||
for (let i = 0; i < 8; i++) track.push(cell(200, i * 25, laneWidth, 25, 180));
|
||||
for (let i = 7; i >= 0; i--) track.push(cell(i * 25, 200, 25, laneWidth, 270));
|
||||
track.push(cell(0, 200 + laneWidth, 25, laneWidth, 270));
|
||||
for (let i = 0; i < 8; i++)
|
||||
track.push(cell(i * 25, 200 + 2 * laneWidth, 25, laneWidth, 270));
|
||||
for (let i = 0; i < 8; i++)
|
||||
track.push(cell(200, 400 + i * 25, laneWidth, 25, 0));
|
||||
track.push(cell(200 + laneWidth, 575, laneWidth, 25, 0));
|
||||
export const parchisTrack = track;
|
||||
export function parchisLane(house, step, outer = 65) {
|
||||
const edge = outer === 65 ? 6 : 7;
|
||||
const begin = outer === 65 ? 1 : 0;
|
||||
return [
|
||||
() => cell(200 + laneWidth, 400 + (edge - step) * 25, laneWidth, 25, 0),
|
||||
() => cell(400 + (edge - step) * 25, 200 + laneWidth, 25, laneWidth, 90),
|
||||
() => cell(200 + laneWidth, (begin + step) * 25, laneWidth, 25, 180),
|
||||
() => cell((begin + step) * 25, 200 + laneWidth, 25, laneWidth, 270),
|
||||
][house]();
|
||||
}
|
||||
export function parchisHomePoint(house, piece) {
|
||||
return [
|
||||
parchisHomes[house][0] + 57 + (piece % 2) * 86,
|
||||
parchisHomes[house][1] + 57 + Math.floor(piece / 2) * 86,
|
||||
];
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import {
|
||||
parchisTrack,
|
||||
parchisStarts,
|
||||
parchisHomes,
|
||||
parchisLane,
|
||||
} from '../shared/parchis-board.mjs';
|
||||
|
||||
describe('tablero clásico de la referencia', () => {
|
||||
it('sitúa los cuatro extremos y salidas en el brazo correcto', () => {
|
||||
// Coordinates read from the requested reference, normalized to a 600px board.
|
||||
const expected = [
|
||||
[1, 1100 / 3, 587.5],
|
||||
[5, 1100 / 3, 487.5],
|
||||
[17, 587.5, 300],
|
||||
[22, 487.5, 700 / 3],
|
||||
[34, 300, 12.5],
|
||||
[39, 700 / 3, 112.5],
|
||||
[51, 12.5, 300],
|
||||
[56, 112.5, 1100 / 3],
|
||||
[68, 300, 587.5],
|
||||
];
|
||||
for (const [number, x, y] of expected) {
|
||||
const center = parchisTrack[number - 1].center;
|
||||
expect(center[0]).toBeCloseTo(x);
|
||||
expect(center[1]).toBeCloseTo(y);
|
||||
}
|
||||
expect(parchisTrack).toHaveLength(68);
|
||||
expect(new Set(parchisTrack.map((c) => c.center.join(','))).size).toBe(68);
|
||||
});
|
||||
it('conecta el color de cada salida con su casa y su pasillo hacia el centro', () => {
|
||||
expect(parchisStarts.map((i) => i + 1)).toEqual([5, 22, 39, 56]);
|
||||
expect(parchisHomes).toEqual([
|
||||
[400, 400],
|
||||
[400, 0],
|
||||
[0, 0],
|
||||
[0, 400],
|
||||
]);
|
||||
expect([0, 1, 2, 3].map((house) => parchisLane(house, 0).center)).toEqual([
|
||||
[300, 562.5],
|
||||
[562.5, 300],
|
||||
[300, 37.5],
|
||||
[37.5, 300],
|
||||
]);
|
||||
expect([0, 1, 2, 3].map((house) => parchisLane(house, 6).center)).toEqual([
|
||||
[300, 412.5],
|
||||
[412.5, 300],
|
||||
[300, 187.5],
|
||||
[187.5, 300],
|
||||
]);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue