Skip to content

Vaynerov Technologies

No solo desarrollamos — conjuramos cada línea de código y píxel.

Todos los artículosHistorias de construcción

Un museo con otra gente dentro

La versión uno era un museo para una sola persona. La versión dos es el mismo edificio con otra gente recorriéndolo: cuatro caracteres para entrar, hasta ocho visitantes, voces que se apagan según se alejan — y ni un byte de todo ello guardado en un servidor.

Edward AmirainFundador, Vaynerov Technologies
Publicado 15 min de lectura
En esta página
  1. Una sala es un canal, no un registro
  2. Un relé sin autoridad
  3. Ocho personas en lana y lino
  4. Voces que se apagan cuando te alejas
  5. Visitar sin que te escriban encima
  6. La costura que dejó abierta la versión uno
  7. El edificio en sí mejoró
  8. Lo que salió en silencio

Hace seis semanas escribí sobre un museo para todo lo que tenga URL: el fetch vigilado, la cascada de análisis, un plano que no se mueve nunca. Funcionaba, y era un edificio para exactamente una persona. Podías pegar un enlace, colgar una cosa, recorrer tus propias salas, y después lo único que podías hacer con lo que habías construido era describírselo a alguien.

Así que la versión dos es el mismo museo con otra gente dentro. Abres una sala, lees en voz alta cuatro caracteres y hasta siete visitantes más entran en tu edificio — como figuras que ves al otro lado de una galería, con voces que bajan de volumen a medida que se van a la sala siguiente. El edificio en sí mejoró mientras yo estaba ahí adentro: tres tipos de galería en vez de uno, escultura sobre pedestales, un cielo que cambia según el día y una visita guiada que por fin es un controlador de cámara de verdad.

Nada de esto se almacena en ninguna parte. Esa restricción hizo más trabajo de diseño que cualquier funcionalidad, así que va primero.

8
visitantes en una sala
0
bytes almacenados en el servidor
246
cadenas de interfaz ×6 idiomas
303
pruebas unitarias

La forma operativa del Reliquary v2. El segundo número es el que ya traía la v1; conservarlo con más de una persona dentro es el sentido de casi todo lo que sigue.

Una sala es un canal, no un registro

La manera obvia de construir las visitas compartidas es una tabla de salas: una fila por sala, una lista de presentes, historial para el chat. Es también el punto en el que tu museo nunca sale de tu navegador se convierte calladamente en …salvo las partes que ahora guardamos. Así que no hay registro de sala en ninguna parte. Una sala es un topic de canal — vt:reliquary:v1:<CODE> — sobre un relé de difusión en tiempo real, y el navegador del anfitrión es la sala. Vive mientras la clave de presencia del anfitrión siga en el canal; cuando el anfitrión cierra la pestaña, se acabó.

No tener registro trae una consecuencia que no había previsto: no hay forma de preguntar si una sala existe. Un topic donde no hay nadie se suscribe exactamente con la misma alegría que uno concurrido. Así que la pregunta la responden la presencia y un plazo: un invitado que entra espera seis segundos a que aparezca una clave de anfitrión, y ese tiempo de espera es la definición de «esa sala no existe». Antes de que un anfitrión tome un código, esa misma ausencia le obliga a sentarse 900 ms en el topic para ver si alguien vive ya ahí.

El código son cuatro caracteres, mostrados como REL-7K2M. El alfabeto tiene treinta símbolos: ni 0 ni O, ni 1, I o L, ni U — los dos primeros pares son las confusiones clásicas al leer en voz alta, y la U desaparece para que ningún sorteo componga algo que un visitante prefiera no decir en alto. Treinta a la cuarta son 810,000 códigos, sacados de crypto.getRandomValues. Eso es privacidad por oscuridad, y lo dice sin rodeos: adivinar uno es la única puerta al museo de otra persona, así que el anfitrión tiene un control para cerrar la sala y cada byte que llega se vuelve a validar de todos modos.

Un relé sin autoridad

La credencial que mete un navegador en ese canal es pública por diseño — las páginas de marketing ya se la entregan a cada visitante. La descripción honesta del transporte es una tubería tonta a la que cualquiera con cuatro caracteres puede mandar lo que quiera, y todo lo que hay aguas abajo está construido sobre esa suposición.

Cada mensaje se vuelve a validar al llegar, por tipo y por límites, en una única función que es toda la frontera de confianza de esta funcionalidad. Las piezas que llegan de un par vuelven a pasar por sanitizeExhibit, la misma función con la que se filtra el propio almacenamiento del visitante, importada y nunca copiada para que no se separen. Una URL rechazada desde el disco se rechaza desde el cable. El id del emisor es una afirmación y no una credencial, y deliberadamente no hay capa de firma, a diferencia del cable del ajedrez 4D, donde una jugada falsificada podría robar una partida. Aquí no hay nada que robar.

El emisor nunca es el saneador. El montaje de un invitado es una petición; el anfitrión lo vuelve a sanear, lo aplica a través de su propio almacén y retransmite lo que de verdad quedó colgado.

Lo que sí hubo que defender es la amplificación. Un hello de treinta bytes que compra una resincronización de sesenta piezas es una palanca apuntando a la sala, así que todo mensaje cuya respuesta cuesta más de lo que lleva el mensaje tiene un suelo por emisor: dos segundos entre resincronizaciones, 400 ms entre líneas de chat, tres segundos entre peticiones de montaje. Teclear es más lento que 400 ms; un bucle no. La sincronización se trocea a 48 KB o 24 elementos, lo que llegue antes — y una colección vacía sigue emitiendo un trozo con una lista vacía, porque un invitado que no recibe nada no puede distinguir «el anfitrión no tiene nada» de «la sincronización aún viene de camino».

El canal lleva presentaciones y nada que tenga autoridad. El audio no lo toca nunca: el relé entrega a dos navegadores los blobs opacos de conexión del otro, y el medio va directo.

La posición es el único mensaje que se repite — diez por segundo, por visitante, mientras la sala esté abierta — así que se cuantiza a centímetros y milirradianes. No es solo compresión: el cuantizador es además el detector de inactividad, porque dos poses que cuantizan a los mismos enteros son la misma pose, y quedarse quieto detiene por tanto la emisión sin ninguna comprobación aparte.

Ocho personas en lana y lino

La especificación de la v1 tenía dos líneas arriba del todo: ninguna dependencia nueva de npm, ningún recurso binario. La segunda decidió qué es un visitante. Sin subidas, sin personajes descargados: un visitante son cuatro enteros pequeños y un nombre, y toda la salida del vestidor cabe en una carga útil de presencia.

Ocho paletas, nombradas por tejido y no por color: pizarra, camello, ciruela, musgo, óxido, tinta, lino, cardenillo. El vocabulario de la galería es nogal, cal y latón bajo un sol bajo, y cada atuendo se sitúa dentro de ese rango en vez de pelearse con él. Exactamente una paleta se acerca al turquesa, dos escalones por debajo en croma: un visitante con un abrigo turquesón, no una fuente de luz cruzando la sala. Aquí el turquesa sigue siendo un bisturí.

Las cuatro formas de cabeza son una sola curva. Una superelipse — |y/ry|^n + |x/rx|^n = 1 — es una elipse con n = 2 y se acerca al rectángulo según crece n; redonda, ovalada, cuadrada y cresta son cuatro juegos de parámetros de esa misma curva, la cabeza cuadrada en 3.6, un cubo blando de revolución antes que una caja con esquinas. Una función emite la silueta, la figura 3D la tornea, la vista previa plana del vestidor la refleja en un trazado, así que el selector no puede prometer una cabeza que la figura no vaya a mantener. La altura es una banda estrecha, de 0.9× a 1.1× sobre una figura de 1.70 m.

La decisión con la que esperaba discutir conmigo mismo era la colisión. Los pares son fantasmas: ningún avatar aporta un colisionador y al controlador de marcha nunca se le dice que existen. Lo que dibujamos es una estimación — una conjetura suavizada por muelle sobre dónde estaba alguien un par de cientos de milisegundos atrás — y que te empuje una estimación es peor que atravesar a una persona que sí está ahí. Y una puerta mide 2.3 m de ancho: un visitante quieto plantado en ella, sólido, sella un ala del museo de un desconocido sin manera de pedirle que se aparte. Solaparse es un bochorno de dos segundos; quedarse atrapado es una visita rota.

Voces que se apagan cuando te alejas

El chat de texto fue una mañana. La voz es lo que convierte una página compartida en una sala compartida. El audio va de navegador a navegador por conexiones directas entre pares; el canal solo entrega a dos visitantes los blobs opacos de sesión del otro. Eso es lo que fija el tope en ocho, anfitrión incluido: una malla completa de ocho son 28 conexiones y siete flujos de subida por persona, más o menos lo que sobreviven el enlace de subida de un portátil y el codificador de un móvil. Subirlo significaría un servidor de medios, no una constante mayor.

Los dos extremos de un par se enteran el uno del otro por el mismo evento de presencia, en el mismo instante, así que ambos intentan abrir la conversación y ambos se bloquean: el clásico glare. El arreglo cuesta una comparación: el par cuyo id ordena primero hace la oferta, el otro espera. Los id de par son 32 caracteres hexadecimales, de modo que el orden es total e idéntico en ambos lados. La voz es opcional para cada visitante, así que un contestador que lleva 2.5 segundos sin oír nada se asciende y ofrece igualmente.

Y luego la parte que realmente oyes. Una voz suena a ganancia completa dentro de dos metros — distancia de conversación — y a partir de ahí cae por distancia inversa simple. La inversa física, eso sí, no silencia nunca a nadie: a catorce metros una voz sigue rondando el 14 % de ganancia, y siete de esas por debajo del rumor de la sala son un murmullo que suena a avería y no a museo. Así que la curva se enventana hasta cero exacto en su último tramo mediante un smoothstep, plano en ambos extremos para que nadie chasquee al irse. Las salas de aquí miden unos diez metros, lo que sitúa el desvanecimiento entre el fondo de esta sala y dos salas más allá.

Ambos ejes lineales desde cero. La línea discontinua es la ley inversa sola, aún audible en el borde lejano; la curva publicada es esa ley multiplicada por una ventana, que es lo que hace que la distancia signifique algo en un edificio de este tamaño.

El paneo es la componente lateral del rumbo, limitada a ±0.8, y se colapsa hacia el centro por debajo de un metro para que dos visitantes que se atraviesan no te latiguen de izquierda a derecha en los oídos.

La voz corre en su propio contexto de audio en lugar de tomar prestado el del motor de juegos, que se suspende en cuanto el documento queda oculto: correcto para pasos, equivocado para una conversación. Aun así obedece al mismo silencio, porque quien silenció el museo quería decir que esto esté callado, no que las campanillas estén calladas. El push-to-talk vive en V y corta la pista del micrófono, no la conexión.

El residuo, nombrado en vez de enterrado: todavía no hay servidor de retransmisión. Dos navegadores cuyas redes se niegan a encontrarse directamente no conectan nunca. Ese par queda marcado como no disponible en la lista de visitantes y conserva el chat de texto — peor que una voz que funciona, mucho mejor que un indicador girando para siempre.

Visitar sin que te escriban encima

Un invitado está mirando la colección de otra persona, y la promesa de el aviso de lanzamiento es que tu museo es una clave en tu propio navegador. Así que una visita renderiza un mundo enteramente aparte del que sostiene tu clave, y tu almacenamiento no se escribe mientras estás fuera. El cambio viaja bajo un velo en ambos sentidos, y vela de inmediato, antes de que haya llegado la sincronización troceada: la alternativa es dejar al invitado plantado un instante en su propia galería, preguntándose de quién son esos cuadros.

El solo lectura resultó ser una serie de juicios pequeños en lugar de un único interruptor. El cajón de gestión conserva su lista y su ir-caminando-hasta-ahí, pero eliminar y vaciar han desaparecido. La barra de pegado se queda y se convierte en una petición: el análisis sigue ocurriendo en el navegador del invitado, el resultado saneado viaja, el anfitrión lo sanea otra vez y responde con un veredicto que llega como aviso. Con el montaje desactivado, la barra queda deshabilitada y dice por qué en lugar de desaparecer, porque un control ausente es indistinguible de una página rota.

La costura que dejó abierta la versión uno

El aviso de lanzamiento terminaba con una promesa: una visita guiada, «esbozada detrás de la misma costura de controlador que usa el modo a pie». Durante un tiempo esa visita fue lo que esas cosas suelen acabar siendo — una cadena de tweens de cámara de un solo uso disparados desde dentro del bucle de render, lo que significaba que la cámara tenía dos dueños según el minuto.

Ahora hay una segunda implementación. El raíl es una lista de paradas precalculada: cada obra en orden de colgado, cada una en la pose de visión frontal que ya usa el paseo automático. Entre paradas la cámara vuela la polilínea de puntos de ruta de las puertas en vez de interpolar a través de una pared, se detiene 3.6 segundos y al final da la vuelta. Mirar por arrastre mientras vas montado añade un desplazamiento acotado sobre la orientación propia del raíl — decae de vuelta al centro mientras se viaja, así que la obra siguiente llega siempre centrada, y se mantiene durante la parada. Tocar las teclas de movimiento es el relevo de verdad, y te devuelve a caminar en la pose actual. La mejor consecuencia de un controlador y no de una animación: abrir una obra ahora pausa la visita en lugar de terminarla.

El minimapa sale del mismo módulo de plano del que sale el edificio: entrada arriba, galerías bajando por el panel en el orden en que las recorres. Haz clic en una sala o en un punto y la maquinaria existente de caminar-o-velar te lleva allí. Los demás visitantes aparecen como puntos en sus propios colores de acento; el único turquesa del panel es la cuña que indica hacia dónde miras.

El edificio en sí mejoró

La v1 tenía una sola receta de galería: una sala alargada con las obras alternando por dos paredes lisas. Es una buena sala, y para la pieza treinta es la única sala en la que has estado nunca. Ahora hay tres arquetipos, ciclados por índice de sala: la sala alargada, un salón (una estancia más ancha y solemne con pilastras en las esquinas bajo un óculo en el techo) y una galería de nichos, donde entre colgado y colgado salen pilastras poco profundas de cada pared lateral, de modo que cada pareja de obras queda en su propio nicho.

El invariante que volvió esto delicado es el mismo sobre el que descansa todo el edificio: añadir la pieza N+1 no debe mover nunca las piezas 1 a N. Así que todo lo que cambia un arquetipo es función pura del índice de sala, y la sala 0 es deliberadamente la sala alargada con los números originales, de modo que cada museo construido en junio reproduce exactamente la geometría que tenía. Las piezas sin imagen colgaban antes como una placa en la pared; ahora se levantan como una estela grabada sobre un pedestal, en la posición de hueco idéntica.

Y el cielo se movió. Tres ambientes — hora dorada, una mañana pálida, un crepúsculo de hora azul — se eligen de una rueda ponderada de diez ranuras mediante un hash de la fecha del calendario local. La hora dorada se queda cinco de las diez porque es la cara de la casa; tienes un tiempo todo el día, otro distinto mañana, y dos personas en la misma zona horaria ven el mismo museo. Cada ambiente lleva el contrato de iluminación entero, no solo el cielo: el crepúsculo sube el brillo cálido propio del yeso en vez de bajarlo, porque a la pared que hay sobre una puerta no llegan ni el sol bajo ni los focos de las obras.

Lo que salió en silencio

Ahora se ejecuta una sonda de WebGL antes de montar el canvas, y una ausencia genuina recibe un cartel localizado en lugar de un rectángulo en blanco — ausencia genuina, nunca clase de dispositivo: un móvil con WebGL funcional conserva el museo entero y transitable. La pérdida de contexto está cableada a un estado de recuperación y a un remontaje limpio.

Las obras son mallas, así que no hay nada a lo que llegar con el tabulador. El patrón que encaja con un lienzo de mirada por arrastre es un cursor sobre el orden de colgado: [ y ] recorren las obras, la cámara camina o se teletransporta bajo velo hasta cada una, y cada una se anuncia con cortesía. Enter inspecciona — y sin cursor puesto elige la obra más cercana a donde estás de pie.

Y el museo ya tiene pruebas: 303 repartidas en 11 archivos, desde ninguna. Eso es arquitectura más que virtud: el protocolo, los códigos de sala, la matemática de la voz, el plano y el raíl son módulos puros sin React, sin three.js y sin red dentro, y por eso por qué la voz de esa persona suena por el lado equivocado es una prueba y no una tarde en un navegador. La interfaz pasó de 87 cadenas a 246, en los seis idiomas, con paridad comprobada.

v1 — juniov2 — hoy
Visitantes1hasta 8, anfitrión incluido
Vozmalla por proximidad, directa entre pares
Visita guiadauna cadena de tweens de cámaraun controlador de raíl; el foco la pausa
Salas de galeríauna receta de sala3 arquetipos, ciclados por índice de sala
Cielohora dorada3 ambientes, uno por día de calendario
Lotes sin imagenuna placa en la pareduna estela sobre un pedestal
Orientarsecaminar, o la lista de gestiónminimapa de plano con puntos de los demás
Cadenas de interfaz87 ×6 idiomas246 ×6 idiomas
Pruebas unitarias0303 en 11 archivos
Almacenado en el servidornadasigue sin nada

La última fila es la tesis. Todo lo que hay encima es lo que cuesta mantener cierta esa última fila cuando hay más de una persona en el edificio.

El modelo de privacidad de la versión uno era demasiado simple como para hacerlo mal: sin base de datos, nada que perder. El modo compartido es normalmente donde esa frase recibe una enmienda: necesitas una sala en algún sitio, una lista de presentes en algún sitio, un poco de historial para que el chat se desplace. Resulta que no. Necesitas un canal, un código lo bastante corto como para decirlo en voz alta, y la disciplina de volver a validar cada byte que llega por él, porque un relé sin autoridad solo es seguro si nada aguas abajo se fía de él.

Lo que no esperaba es cuánto mejoró el edificio como efecto secundario. En cuanto una sala puede contener a otras personas te das cuenta de que todas las galerías se parecen, de que el cielo no cambia nunca, de que los lotes de solo texto están pidiendo perdón contra una pared. A solas eso no le importa a nadie. Solo lo ves cuando hay otra persona ahí de pie.