Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ npm run models:optimize # comprimir los .glb de public/assets/models
- Nunca hacer commit, amend, push ni PR sin que lo pida explícitamente la
persona usuaria.
- Remoto: `origin` → https://github.com/jmoredev/PC-Simulator.git
- **Colaboración externa:** quien no trabaja aquí propone los cambios desde una
rama propia con un *pull request* hacia `main`, para que se revisen antes de
publicarse (las instrucciones para la persona colaboradora están en
`README.md`, sección «Cómo colaborar»).

## 4. Estructura de carpetas

Expand Down Expand Up @@ -194,7 +198,13 @@ Reglas de layout:
| 57 | **En práctica, cada fase empieza con su cartel** | Antes el cartel salía solo al completar una fase, así que quien arrancaba la partida o saltaba de fase no veía qué había que hacer. Ahora sale al **empezar** cada fase en práctica (también la primera, y también al reiniciar), se quita solo a los 3,6 s, y el estado guarda `lastAdvance` para poder decir «Fase completada» solo cuando se llegó completando y no cuando se saltó. En examen no se monta: el examen no da explicaciones. Cubierto en §16. |
| 58 | **La pieza seleccionada se ve ampliada en una ventanita** (fase 1) | En la fase 1 están todas las piezas sobre la mesa y los conectores se ven muy pequeños. Al seleccionar una, una ventanita la enseña entera: el **PNG del conector** cuando existe (más nítido que el dibujo 3D: `ps2`, `usb`, `lan`, `hdmi`, `displayport`, `dvi`, `vga`) y, si no, una **vista 3D de cerca** con la misma `ComponentVisual` (drei no trae `View` en esta versión, así que es un mini lienzo). Va al centro-abajo —la captura enseñó que a la izquierda tapaba la lista de fases—, con `pointer-events: none` para no estorbar el arrastre, solo en la fase 1 y **sin el nombre en examen** (misma regla que la 56). Cubierto en §17. |
| 59 | **La ventanita del zoom se monta una vez por fase, no por pieza** | Montarla condicionada a la pieza seleccionada la desmontaba **en cada colocación** de la fase 1 (18 por partida) y **cada montaje creaba un contexto WebGL nuevo**; el que el navegador se lleva por agotamiento es el más antiguo, o sea el de la **escena principal**, y la vista 3D dejaría de pintar. Ahora el panel (y su lienzo) viven toda la fase 1 y sin selección se **ocultan** con `zoom--oculto` (así el lienzo conserva su tamaño y su contexto); fuera de la fase 1 se desmontan, porque ahí no hacen falta. Hallazgo `R4-001` de la revisión nativa; cubierto en §17, donde el ciclo **seleccionar → colocar (que deselecciona) → seleccionar** se comprueba de verdad y un marcador sobre el nodo del lienzo detecta cualquier remontaje (falsado: con el montaje condicional fallan las cinco comprobaciones de ese ciclo). |
| 60 | **Los carteles de la fase 1 se reparten en 6 × 3, con las filas a 1,75 u** | Cada cartel acepta **un solo tipo** de pieza, así que la pieza nunca se coloca en el cartel equivocado: el defecto que reportó el alumnado era de **conteo**. `endDrag` cuenta fallo cuando **no** hay cartel correcto a `snapRadius` (0,6) y **sí** uno ajeno a `wrongRadius` (0,6), y con las filas a 0,95 u esa banda empezaba **a 0,35 u del centro**, o sea 0,15 u más allá del borde visible de la tarjeta (1,0 × 0,4): soltar cerca del borde contaba el vecino y **restaba puntos** (medido en examen: 100 → 97, 0 → 1 fallos). Con 1,75 u las dos regiones ya no se solapan (1,75 ≥ 0,6 + 0,6): fallar de largo solo deja la pieza sin colocar, sin coste. El peor hueco en pantalla entre dos tarjetas pasa de **23 px a 31 px**. Cuatro filas de cinco columnas no caben más separadas —a 1,25 u la de atrás queda a 0,1 u del borde de la mesa y a 1,3 se sale—, así que la forma pasa a 6 × 3 (18 celdas exactas, sin huecos). Todo medido con la proyección de la cámara, y el agarre de la pieza en el arnés quedó unificado en `COGER_PIEZA` (el monitor caía 0,15 u por encima del punto calculado y no se dejaba coger). Cubierto en §19, con la regla geométrica, el hueco en pantalla y la suelta real a 0,7 u; falsado: con 0,95 u fallan los cuatro. |
| 60 | **Los carteles de la fase 1 se reparten en 6 × 3, con las filas a 1,75 u** | Cada cartel acepta **un solo tipo** de pieza, así que la pieza nunca se coloca en el cartel equivocado: el defecto que reportó el alumnado era de **conteo**. `endDrag` cuenta fallo cuando **no** hay cartel correcto a `snapRadius` (0,6) y **sí** uno ajeno a `wrongRadius` (0,6), y lo cuenta **pasado `snapRadius`** —antes de eso la pieza coloca—, así que lo que decide es hasta dónde alcanza el vecino: con las filas a 0,95 u su banda llegaba a los **0,35 u** del centro, 0,15 u más allá del borde visible de la tarjeta (1,0 × 0,4), de modo que **cualquier tiro de más de 0,6 u caía dentro**, contaba el vecino y **restaba puntos** (medido en examen: 100 → 97, 0 → 1 fallos). Con las filas a 1,75 u (y la columna a 1,5 u, que es el mínimo) el vecino no entra hasta los **0,9 u**: los tiros entre 0,6 y 0,9 u ya no cuestan nada y solo dejan la pieza sin colocar, y pasado 0,9 u el vecino vuelve a contar — el margen sin coste pasa de 0,6 u a 0,9 u, **no a infinito**. El peor hueco en pantalla entre dos tarjetas pasa de **23 px a 31 px**. Cuatro filas de cinco columnas no caben más separadas —a 1,25 u la de atrás queda a 0,1 u del borde de la mesa y a 1,3 se sale—, así que la forma pasa a 6 × 3 (18 celdas exactas, sin huecos). Todo medido con la proyección de la cámara, y el agarre de la pieza en el arnés quedó unificado en `COGER_PIEZA` (el monitor caía 0,15 u por encima del punto calculado y no se dejaba coger). Cubierto en §19 —regla geométrica, hueco en pantalla, suelta real a 0,7 u y los márgenes de `snapRadius` y del vecino—; falsado: con 0,95 u fallan los seis. Las dos primeras redacciones de esta fila decían que el fallo empezaba a 0,35 u y que fallar de largo no costaba nada: lo corrigió la verificación independiente (V1-V5 MET, sin bloqueantes) y los checks que la acompañan lo dejan fijado. |
| 61 | **La rejilla de la fase 1 se deriva del número de piezas** | La fase 1 tiene una pieza por cada tipo de conector de la placa, así que su número cambia con la placa: **18** con ocho tipos y **19** en la 03, que trae uno más. La rejilla estaba fija en 6 columnas × 3 filas = 18 celdas, y los carteles en `ceil(n / 6)` filas, así que con 19 piezas el reparto se rompía por dos sitios a la vez: la pieza 19 repetía la celda de la 15 (una columna de más hacía que `floor(18 / 3)` se recortara a la última) y los carteles, repartidos en `ceil(19 / 6) = 4` filas de 1,75 u, dejaban **una fila entera fuera de la mesa** —medido: borde trasero en z = −6,2 con la mesa acabando en −4,9, y en pantalla a y = 111 px, por encima del borde lejano de la mesa (y = 154)—. Es el defecto que se reportó («los cables de audio, micrófono y E/S salen fuera de la mesa»): los carteles de esos cables eran algunos de los que quedaban flotando más allá del borde, y la pieza que compartía celda desaparecía al colocarla. Ahora `gridCols` calcula las columnas que hacen falta —hasta el suelo de separación: 0,9 u entre piezas (huella 0,75 + aire), 1,5 u entre carteles (`snapRadius` + `wrongRadius`) y ±4 / ±4,5 u de ancho— y avisa por consola si ni así caben, en vez de dejar dos piezas compartiendo sitio en silencio. Las filas y sus separaciones no cambian, así que con 18 piezas el reparto sale **idéntico** al de antes, y el arnés mide las dos formas: `traySeparation` e `identifyCards` corren en `motherboard-01` y `motherboard-03` —§11 y §19—. |
| 62 | **La pieza procedural se alinea midiendo en su espacio, no en el mundo** | Las piezas que dibuja el código (`Placeholder`) se ajustan con `Align`, que centraba la pieza midiendo su caja envolvente con `Box3.setFromObject` —en coordenadas de **mundo**—, así que el centrado incluía la propia colocación en la mesa y la dejaba en el **origen del mundo**: el centro de la mesa. Solo se notaba en las **cuatro piezas procedurales de la fase 1** (los tres jacks y el USB-C, los únicos sin PNG ni `.glb`): su celda quedaba vacía —el cartel con su nombre sí salía, así que el cable parecía estar fuera de la mesa— y al cogerlas con el ratón el fantasma aparecía en el centro de la mesa en vez de bajo el cursor, de modo que al soltarlas se perdían. Los `.glb` se ajustan dentro de `GltfModel` y los conectores con imagen son un plano que no se alinea, por eso llevaba tiempo ahí sin que lo cazara nadie: lo reportó el alumnado («algunos cables de los construidos por ti salen fuera de la mesa y desaparecen»). Ahora `localBox` mide cada malla por su matriz **relativa al grupo** (mundo → grupo) y el centrado vuelve a ser el correcto. Cubierto en §20 —barrido del lienzo, pieza por pieza: ninguna puede quedarse sin geometría en su celda—; falsado: sin el arreglo falla nombrando las cuatro piezas procedurales. |
| 63 | **La imagen del USB-C es una foto de Wikimedia Commons (CC BY-SA 4.0)** | El cable USB-C (señuelo de la fase 2) era el único conector sin PNG: se dibujaba con la forma procedural, justo la que destapó el defecto del `Align` (fila 62). Se parte de la foto de Santeri Viinamäki (`USB_Type-C_plug_20170626_crop.jpg`, Commons), se gira para que la clavija apunte hacia abajo como en el resto de imágenes y se le quita el fondo (PNG con transparencia; el fondo se detecta por crecimiento de región desde el borde, parando en el gradiente del contorno). Es la primera imagen del proyecto con licencia **BY-SA**: el archivo sigue bajo CC BY-SA 4.0 y hay que seguir citando autor y fuente. Está en `CREDITS.md` y en `src/data/credits.ts`, que se mantienen en paralelo (decisión 42). |
| 64 | **La portada se presenta como proyecto colaborativo y construido con Gentle-AI** | El repositorio es público, así que el `README.md` lleva el enlace al repositorio, el sello **«Built with Gentle-AI»** (el enlace y la imagen que pide el propio proyecto) y la sección **«Cómo colaborar»** con el flujo que pide su responsable: **nunca trabajar sobre `main`**, cada cambio en su rama (`feat/…`, `fix/…`, `docs/…`) y una **propuesta de cambio (pull request) hacia `main`** para que la revise antes de fusionarla —desde un *fork* si quien colabora no tiene permiso de escritura—. El desarrollo interno sigue en `develop` (sección 3). Es documentación pura, así que no hay prueba automática: se comprobaron los tres enlaces (repositorio, destino del sello e imagen del sello, los tres 200) y el snippet HTML renderizado en la portada. |
| 65 | **El proyecto se publica con licencia MIT (el código) y los recursos de terceros mantienen la suya** | El repositorio no tenía licencia, así que se añade `LICENSE` con **MIT**: permite a cualquiera usar, copiar y modificar el producto **citando el original** (conservar el aviso de copyright y el texto de la licencia), que es exactamente lo que se pidió y sin las obligaciones de una licencia copyleft. El titular es `jmoredev` (autoría de todos los commits del proyecto), con el año del primer commit (2026). `package.json` lo declara (`"license": "MIT"`) y el `README.md` lo explica. **Lo importante**: la licencia MIT cubre el **código** —lo que hay en el repositorio salvo los recursos de terceros—, y los **modelos 3D y las imágenes** NO se relicencian: cada archivo mantiene su licencia (CC BY, CC BY-SA 4.0 la foto del USB-C), con su autor y su fuente en `CREDITS.md`; si algún día se quisiera relicenciar todo, habría que sustituir los recursos de terceros por otros propios o compatibles. GitHub enseña la licencia en el lateral del repositorio cuando el archivo `LICENSE` está en la rama por defecto (`main`), así que llega al publicarse el PR. Es documentación y metadatos: no hay prueba automática, se comprobó el texto estándar de MIT sin modificar y que `npm run build`/`lint` siguen igual. |


## 7. Pipeline de assets 3D

Expand Down Expand Up @@ -388,6 +398,13 @@ disfrazaba de fallo de producto: siete comprobaciones «se quedó en identificac
pasada entera, que dura unos 11 minutos): `ONLY=touchDrag,loadingBar node
tests/run.mjs`, con los nombres de `SECTIONS` separados por comas.

**El socket de HMR de Vite no cuenta como error de la app**: el arnés ignora los
`console.error` de `WebSocket connection to ws://… failed` (una vez, en una
pasada de 20 minutos, el servidor rechazó una reconexión y la sección «sin
errores de página» salía en rojo con todos sus checks funcionales en verde). Si
el servidor se cae de verdad, las secciones fallan por sus propios checks y
`requireServer()` avisa antes de empezar.

## 11. Despliegue (GitHub Pages)

- **URL pública (tras activar Pages):** <https://jmoredev.github.io/PC-Simulator/>
Expand Down
9 changes: 9 additions & 0 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Créditos y licencias

El **código** del simulador es [MIT](../LICENSE) (usar, copiar y modificar citando
el original). Lo de abajo son los **recursos de terceros**, que mantienen su propia
licencia.

Los **modelos 3D** y las **imágenes de los conectores** de este proyecto son obra
de sus autores y se usan bajo la licencia que se indica en la tabla. Se pueden
consultar también dentro del simulador, en **Menú → Créditos y licencias**.
Expand Down Expand Up @@ -64,6 +68,11 @@ Todos los modelos 3D proceden de [Sketchfab](https://sketchfab.com) y son
| `displayport.png` | Conector DisplayPort | | | | |
| `dvi.png` | Conector DVI | | | | |
| `vga.png` | Conector VGA | | | | |
| `usb-c.png` | Conector USB-C | Santeri Viinamäki | [Wikimedia Commons](https://commons.wikimedia.org/wiki/File:USB_Type-C_plug_20170626_crop.jpg) | [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/) | Recortada, girada y con el fondo quitado (PNG con transparencia) |

> La imagen del USB-C es una **foto** de Wikimedia Commons: al ser **CC BY-SA**,
> el archivo `usb-c.png` (versión recortada y con fondo transparente) se
> distribuye con la misma licencia, y hay que seguir citando a su autor.

## Otras librerías

Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2026 jmoredev

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
56 changes: 56 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@ didáctica para cada componente.

![modos](https://img.shields.io/badge/modos-práctica%20%7C%20examen-38bdf8)

**Repositorio:** <https://github.com/jmoredev/PC-Simulator> — si quieres
proponer un cambio, mira [Cómo colaborar](#cómo-colaborar).

<a href="https://github.com/Gentleman-Programming/gentle-ai">
<img width="220" src="https://raw.githubusercontent.com/Gentleman-Programming/gentle-ai/main/docs/assets/brand/built-with-gentle-ai.png" alt="Built with Gentle-AI" />
</a>

## Versión publicada

La versión online para el aula se publica desde la rama `main` en
Expand Down Expand Up @@ -90,6 +97,9 @@ npm run models:optimize # comprime los .glb de public/assets/models
- **`develop`** → rama de trabajo; **todo el desarrollo va aquí**.
- Ramas cortas desde `develop` con prefijo `feat/`, `fix/` o `docs/`.

Si vas a proponer un cambio para que se revise, sigue [Cómo
colaborar](#cómo-colaborar): rama propia y *pull request* hacia `main`.

```bash
git clone https://github.com/jmoredev/PC-Simulator.git
cd PC-Simulator
Expand All @@ -100,6 +110,41 @@ npm install
Las decisiones de diseño, la estructura de carpetas y las convenciones están
documentadas en [`AGENTS.md`](AGENTS.md).

## Cómo colaborar

El proyecto vive en <https://github.com/jmoredev/PC-Simulator> y **todo cambio
pasa por una revisión** antes de llegar a la versión publicada: se propone en una
rama y se revisa en un *pull request* hacia `main`.

1. **Trabaja siempre en una rama**, nunca directamente sobre `main`:

```bash
git clone https://github.com/jmoredev/PC-Simulator.git
cd PC-Simulator
git checkout -b feat/mi-cambio # o fix/..., docs/...
```

2. **Haz el cambio y pruébalo** antes de proponerlo:

```bash
npm run build # compila sin errores
npm run lint # sin avisos
node tests/run.mjs # arnés de pruebas (necesita el servidor de dev levantado)
```

3. **Abre un *pull request* hacia `main`**, no hacia otra rama, explicando qué
cambia y por qué. El responsable del proyecto lo revisa antes de fusionarlo;
hasta entonces el cambio vive en tu rama (y en `main` no entra nada sin
revisar).

4. **Si no tienes permiso de escritura en el repositorio**, haz antes un *fork*
con el botón **Fork** de GitHub y abre el pull request desde tu copia a
`main` del repositorio original.

Si el cambio añade o cambia algo visible (una fase, una pieza, un texto de la
interfaz), cuenta también qué hay que mirar para comprobarlo: es lo que se
revisa en el pull request.

## Pruebas

Con el servidor de desarrollo levantado:
Expand Down Expand Up @@ -245,6 +290,17 @@ src/
y [@react-three/drei](https://github.com/pmndrs/drei)
- [Zustand](https://zustand.docs.pmnd.rs/) para el estado

## Licencia

El **código** de este proyecto (todo lo que hay en el repositorio salvo los
recursos de terceros) es **MIT**: cualquiera puede usarlo, copiarlo y modificarlo,
**citando el original** (conservar el aviso de copyright y la licencia, ver
[`LICENSE`](LICENSE)).

Los **modelos 3D y las imágenes** de terceros **no** entran en esa licencia: cada
archivo mantiene la suya (CC BY, CC BY-SA…), con su autor y su fuente, en
[`CREDITS.md`](CREDITS.md).

## Créditos y licencias

Los modelos 3D y las imágenes de los conectores son obra de sus autores y se usan
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"version": "0.0.0",
"type": "module",
"license": "MIT",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
Expand Down
7 changes: 7 additions & 0 deletions src/assets/connectors/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,10 @@ El nombre debe ser el `kind` del conector. Estos son los que se usan:

Si un PNG falta, ese conector se dibuja con la forma procedural de
`src/three/Placeholder.tsx` y el simulador sigue funcionando.

## Créditos

El autor, la fuente, la licencia y los cambios de cada imagen están en
[`CREDITS.md`](../../CREDITS.md) y en `src/data/credits.ts`. Ojo con
`usb-c.png`: es una foto de Wikimedia Commons con licencia **CC BY-SA 4.0**, así
que hay que seguir citando a su autor y el archivo se queda con esa licencia.
Binary file added src/assets/connectors/usb-c.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading