<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kmkjsky</title>
    <description>The latest articles on DEV Community by kmkjsky (@kmkjsky).</description>
    <link>https://dev.to/kmkjsky</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4238629%2F6de6d014-e504-45f4-b418-dd4dcfd6fc76.png</url>
      <title>DEV Community: kmkjsky</title>
      <link>https://dev.to/kmkjsky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kmkjsky"/>
    <language>en</language>
    <item>
      <title>Hice un vuelo espacial a escala real con three.js, de la Tierra a Andrómeda</title>
      <dc:creator>kmkjsky</dc:creator>
      <pubDate>Wed, 11 Nov 2026 08:13:11 +0000</pubDate>
      <link>https://dev.to/kmkjsky/hice-un-vuelo-espacial-a-escala-real-con-threejs-de-la-tierra-a-andromeda-3746</link>
      <guid>https://dev.to/kmkjsky/hice-un-vuelo-espacial-a-escala-real-con-threejs-de-la-tierra-a-andromeda-3746</guid>
      <description>&lt;p&gt;Estoy haciendo yo solo un simulador de vuelo espacial que corre en el navegador, con todo a su distancia real. Sales de la Tierra, pasas por los planetas en la posición que tienen hoy, vuelas entre estrellas cercanas y terminas fuera de la Vía Láctea y en Andrómeda. Es gratis y no pide registro.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://howsmallarewe.com/es/?utm_source=devto_es" rel="noopener noreferrer"&gt;https://howsmallarewe.com/es/?utm_source=devto_es&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tlglxn9a77psslbjng5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0tlglxn9a77psslbjng5.jpg" alt="Superficie beige de Saturno ocupando la mitad inferior, con el horizonte curvo y estrellas arriba, una de ellas con la etiqueta &amp;quot;Urano&amp;quot;; abajo a la izquierda un panel de estado dice &amp;quot;Altitud sobre Saturno: 3494 km&amp;quot;" width="518" height="865"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Está hecho con three.js 0.170 y Vite. En la misma escena tiene que verse Saturno desde 3.494 km de altura y Andrómeda a unos 2,5 millones de años luz, y eso rompió varias cosas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Origen flotante y scaled space
&lt;/h2&gt;

&lt;p&gt;En los shaders se trabaja con float32, así que las posiciones reales viven en la CPU como números de JavaScript (double), en kilómetros. En cada fotograma le resto la posición de la cámara a todo, la cámara queda siempre en el origen y a la GPU solo le llegan coordenadas relativas.&lt;/p&gt;

&lt;p&gt;Aun así, los polígonos a más de unos 1e15 km se dibujaban mal. Todo lo que está más lejos de 2e10 km (más allá de la órbita de Neptuno) lo acerco a esa distancia sobre la misma dirección y lo escalo por el mismo factor. Ocupa el mismo ángulo en pantalla y la GPU trabaja con números manejables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planetas que desaparecían enteros
&lt;/h2&gt;

&lt;p&gt;Uso &lt;code&gt;logarithmicDepthBuffer: true&lt;/code&gt;. Con esta relación near/far, en la proyección estándar el z de clip queda casi igual a w, y en GPUs reales, por redondeo, z a veces superaba a w por muy poco. El vértice quedaba "más allá del plano lejano" y el planeta entero se recortaba.&lt;/p&gt;

&lt;p&gt;Con el depth buffer logarítmico, three.js escribe la profundidad aparte en el fragment shader (&lt;code&gt;gl_FragDepth&lt;/code&gt;), así que el z de clip ya no hace falta para la profundidad. Lo dejo siempre en 0 parcheando el chunk en un módulo que importo en la primera línea del archivo principal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="no"&gt;CHUNK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ShaderChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logdepthbuf_vertex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="no"&gt;CHUNK&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'gl_Position.z = 0.0'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="no"&gt;THREE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ShaderChunk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;logdepthbuf_vertex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`${CHUNK}
#ifdef USE_LOGDEPTHBUF
  gl_Position.z = 0.0;
#endif`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Los vértices detrás de la cámara (w &amp;lt; 0) se siguen recortando por la comprobación de rango de x, y, z. Si tienen &lt;code&gt;ShaderMaterial&lt;/code&gt; propios, hay que meter los &lt;code&gt;#include&lt;/code&gt; de logdepthbuf en el vertex y en el fragment. En mi caso eran las ~110.000 estrellas del catálogo HYG, que son un &lt;code&gt;THREE.Points&lt;/code&gt; con shader propio y calculan su brillo según la distancia real a la cámara.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cielo en ultravioleta
&lt;/h2&gt;

&lt;p&gt;Con la tecla V todo el cielo cambia al nuevo mapa ultravioleta de todo el cielo de Brice Ménard (presentado con Anthropic, hecho con Claude Science). Según su autor, cerca de un tercio del mapa, sobre todo el plano galáctico, es predicción a partir de otras longitudes de onda. La Vía Láctea vista desde fuera es un modelo, no una foto.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqsxai68fbrbphrs9p5ey.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqsxai68fbrbphrs9p5ey.jpg" alt="Dos capturas del mismo punto, lado a lado: a la izquierda en luz visible, un núcleo blanco amarillento cruzado en diagonal por una banda de estrellas; a la derecha en ultravioleta, el mismo lugar como un disco violeta lleno de puntos brillantes. En ambas, la etiqueta &amp;quot;La Vía Láctea completa (modelo)&amp;quot;" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Lo que me gustaría saber
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Parchear &lt;code&gt;THREE.ShaderChunk&lt;/code&gt; de forma global funciona, pero temo que se rompa con alguna actualización de three.js. ¿Alguien resolvió escalas así de otra manera, por ejemplo con reversed-Z o dividiendo la escena en varias pasadas por distancia?&lt;/li&gt;
&lt;li&gt;Cómo va la tasa de fotogramas en su equipo, sobre todo en portátiles y teléfonos (los teléfonos cargan texturas 4K en lugar de 8K).&lt;/li&gt;
&lt;li&gt;Cualquier cosa que se vea mal en los cambios de escala, como estrellas que aparecen de golpe o parpadeo de profundidad.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;El código no está publicado, pero si a alguien le sirve puedo pegar más fragmentos en los comentarios.&lt;/p&gt;

&lt;p&gt;Créditos: mapa UV de Ménard (CC BY 4.0), texturas de planetas de Solar System Scope (CC BY 4.0), HYG Database v3.5.1 (CC BY-SA 2.5), posiciones de Astronomy Engine (MIT).&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>spanish</category>
      <category>threejs</category>
      <category>javascript</category>
    </item>
    <item>
      <title>I built a true-scale space flight in three.js, from Earth to Andromeda</title>
      <dc:creator>kmkjsky</dc:creator>
      <pubDate>Wed, 11 Nov 2026 08:11:24 +0000</pubDate>
      <link>https://dev.to/kmkjsky/i-built-a-true-scale-space-flight-in-threejs-from-earth-to-andromeda-28l8</link>
      <guid>https://dev.to/kmkjsky/i-built-a-true-scale-space-flight-in-threejs-from-earth-to-andromeda-28l8</guid>
      <description>&lt;p&gt;I've been building a browser space flight where everything sits at its real distance. You leave Earth, pass the planets at their actual positions for today, fly between nearby stars, and end up outside the Milky Way and at Andromeda.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://howsmallarewe.com/en/?utm_source=devto" rel="noopener noreferrer"&gt;https://howsmallarewe.com/en/?utm_source=devto&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fem9xi4jd8hclnan2gl1k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fem9xi4jd8hclnan2gl1k.jpg" alt="Saturn with its wide rings tilted toward the viewer against a black starfield, with a small Saturn label on the planet" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I started it because textbook diagrams put the planets right next to each other, and I never had a sense of how big the gaps are.&lt;/p&gt;

&lt;p&gt;It's three.js r170 with Vite and no other rendering library. Three parts took most of the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  One scene from a metre to 2.5 million light-years
&lt;/h2&gt;

&lt;p&gt;The renderer uses &lt;code&gt;logarithmicDepthBuffer&lt;/code&gt;. True positions live on the CPU in km as JS doubles. Every frame I subtract the camera position from everything, so the camera always sits at the origin (floating origin) and the GPU only sees camera-relative coordinates.&lt;/p&gt;

&lt;p&gt;That wasn't enough on its own. Polygons more than about 1e15 km from the camera still broke up from float precision. So anything farther than 2e10 km, which is outside Neptune's orbit, gets pulled in to that distance along the same direction and scaled down by the same factor. It keeps the same angular size on screen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="no"&gt;PROXY_KM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2e10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// beyond Neptune's orbit (4.5e9 km)&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="n"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subVectors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;truePos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camPos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;PROXY_KM&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="no"&gt;PROXY_KM&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;multiplyScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Stars that depend on where you are
&lt;/h2&gt;

&lt;p&gt;About 110k stars from the HYG catalogue are packed into a binary file at 20 bytes per star (xyz in parsecs, absolute magnitude, RGB). The vertex shader works out the apparent magnitude from the real camera distance every frame and turns it into point size and alpha. From Earth you get the normal night sky. Fly to Sirius and the sky is drawn as it would look from there.&lt;/p&gt;

&lt;h2&gt;
  
  
  An ultraviolet sky
&lt;/h2&gt;

&lt;p&gt;Press V to swap the whole sky for the new full-sky UV map by Brice Ménard (released with Anthropic, made with Claude Science). A Python script converts the Mollweide image to equirectangular, and the sky sphere samples it by direction through a J2000 galactic rotation. About a third of the map, mostly the galactic plane, is predicted from other wavelengths, per the map's author.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo136vqgwphqcbzeuz6yi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fo136vqgwphqcbzeuz6yi.jpg" alt="Two crops of the same view from 3,494 km above Saturn's cloud tops: on the left a black sky with white stars, on the right the same sky replaced by the blue and violet ultraviolet map" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Flight speed is 0.9 times the distance to the nearest surface per second, so the same keys move you kilometres near a planet and light-years between stars. Planet positions come from Astronomy Engine. The Milky Way you see from outside is a model, not a photo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feedback I'd like
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Right in front of a UV landmark the additive blending blows out to white and you lose the shape. I haven't found a good fix yet.&lt;/li&gt;
&lt;li&gt;Frame rate on your GPU, especially laptops and phones (phones get 4K textures instead of 8K).&lt;/li&gt;
&lt;li&gt;Anything that looks wrong at the scale transitions, like stars popping or depth fighting.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Credits: UV map by Ménard (CC BY 4.0), planet textures from Solar System Scope (CC BY 4.0), HYG Database v3.5.1 (CC BY-SA 2.5), positions from Astronomy Engine (MIT).&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>threejs</category>
      <category>webgl</category>
      <category>javascript</category>
    </item>
  </channel>
</rss>
