<?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: Peacoke</title>
    <description>The latest articles on DEV Community by Peacoke (@peacoke).</description>
    <link>https://dev.to/peacoke</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%2F4190908%2F3d61df1e-5d49-4d24-afd2-25e673ce7fe9.png</url>
      <title>DEV Community: Peacoke</title>
      <link>https://dev.to/peacoke</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/peacoke"/>
    <language>en</language>
    <item>
      <title>Como funciona o algoritmo do Teste de Ideologia Política 12 Axes (TanStack Start, Vite e 12 Dimensões)</title>
      <dc:creator>Peacoke</dc:creator>
      <pubDate>Mon, 19 Oct 2026 12:48:13 +0000</pubDate>
      <link>https://dev.to/peacoke/como-funciona-o-algoritmo-do-teste-de-ideologia-politica-12-axes-tanstack-start-vite-e-12-46bm</link>
      <guid>https://dev.to/peacoke/como-funciona-o-algoritmo-do-teste-de-ideologia-politica-12-axes-tanstack-start-vite-e-12-46bm</guid>
      <description>&lt;p&gt;Nos últimos meses, testes de bússola política voltaram a viralizar com força no TikTok e no X (Twitter). No entanto, o clássico modelo 2D (Esquerda vs. Direita no eixo econômico e Autoritário vs. Libertário no social) mostrou-se insuficiente para capturar as complexidades do debate moderno — especialmente em democracias multifacetadas como as da América Latina e do Brasil.&lt;/p&gt;

&lt;p&gt;Para resolver essa limitação matemática e conceitual, criamos a versão moderna do &lt;a href="https://12axes.site/pt/" rel="noopener noreferrer"&gt;teste de ideologia política 12 eixos&lt;/a&gt;, uma plataforma web estática, aberta e com zero armazenamento em banco de dados, construída sobre &lt;strong&gt;TanStack Start&lt;/strong&gt;, &lt;strong&gt;React 19&lt;/strong&gt;, &lt;strong&gt;Vite&lt;/strong&gt; e &lt;strong&gt;Cloudflare Workers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Neste artigo, explicamos como funciona o modelo matemático de 12 vetores, as garantias de privacidade zero-backend e por que essa arquitetura garante velocidade e transparência absolutas.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Por que 2 eixos (ou 4 quadrantes) falham matematicamente?
&lt;/h2&gt;

&lt;p&gt;O clássico &lt;em&gt;Political Compass&lt;/em&gt; comprime dezenas de variáveis políticas em apenas dois números $(X, Y)$. Essa compressão resulta em perdas graves de informação:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Confusão entre Diplomacia e Comércio:&lt;/strong&gt; Um intervencionista militar pode ser favorável ao livre comércio, enquanto um pacifista pode defender tarifas protecionistas estritas. No modelo 2D, ambos são jogados no mesmo ponto arbitrário.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confusão entre Segurança do Estado e Liberdade Civil:&lt;/strong&gt; Medidas de vigilância governamental não se alinham perfeitamente com valores morais tradicionais ou progressistas.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reducionismo Tecnológico:&lt;/strong&gt; Como posicionar aceleração tecnológica, automação por inteligência artificial e bioética em um simples eixo esquerda-direita?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;O modelo &lt;a href="https://12axes.site/pt/" rel="noopener noreferrer"&gt;12axes.site/pt/&lt;/a&gt; expande essa análise para &lt;strong&gt;12 dimensões ortogonais&lt;/strong&gt;, agrupadas em quatro esferas fundamentais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Governamental:&lt;/strong&gt; Federal vs. Unitário | Democrático vs. Autocrático | Segurança vs. Liberdade&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diplomático:&lt;/strong&gt; Nacionalismo vs. Internacionalismo | Militarista vs. Pacifista | Assimilacionista vs. Multiculturalista&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Econômico:&lt;/strong&gt; Coletivização vs. Privatização | Economia Planejada vs. Laissez-faire | Globalismo vs. Protecionismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Societal:&lt;/strong&gt; Tradicionalista vs. Progressista | Teocrático vs. Secular | Aceleracionista vs. Bioconservador&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. O Algoritmo de Cálculo Vetorial e Correspondência de Ideologias
&lt;/h2&gt;

&lt;p&gt;Cada afirmação do teste (oferecemos opções de 36, 60 ou 288 perguntas) possui um vetor de peso pré-definido $W_{i, a} \in [-1, 1]$ para cada eixo $a \in {1..12}$.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cálculo da Pontuação por Eixo
&lt;/h3&gt;

&lt;p&gt;A resposta do usuário varia em uma escala Likert de 5 pontos (Discordo Totalmente, Discordo, Neutro, Concordo, Concordo Totalmente), mapeada para multiplicadores $M_i \in {-1.0, -0.5, 0.0, 0.5, 1.0}$.&lt;/p&gt;

&lt;p&gt;Para cada eixo $a$, a pontuação final $S_a \in [0, 100]$ é calculada como uma proporção normalizada:&lt;/p&gt;

&lt;p&gt;$$S_a = 50 \times \left(1 + \frac{\sum_{i} M_i \cdot W_{i,a}}{\sum_{i} |W_{i,a}|}\right)$$&lt;/p&gt;

&lt;p&gt;Um valor $S_a = 50\%$ representa perfeita neutralidade no eixo; $S_a &amp;lt; 50\%$ inclina-se para o primeiro polo e $S_a &amp;gt; 50\%$ para o segundo polo.&lt;/p&gt;

&lt;h3&gt;
  
  
  Correspondência com as 38 Ideologias
&lt;/h3&gt;

&lt;p&gt;Para identificar a ideologia política mais próxima do usuário, calculamos a &lt;strong&gt;Distância Euclidiana Ponderada&lt;/strong&gt; no espaço vetorial de 12 dimensões em relação ao catálogo de 38 ideologias de referência:&lt;/p&gt;

&lt;p&gt;$$D(u, k) = \sqrt{\sum_{a=1}^{12} (S_{u, a} - I_{k, a})^2}$$&lt;/p&gt;

&lt;p&gt;A ideologia correspondente é aquela que minimiza a distância $D(u, k)$, acompanhada de uma taxa percentual de proximidade semântica.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Privacidade Absoluta: Arquitetura Zero-Backend
&lt;/h2&gt;

&lt;p&gt;Um teste de convicção política lida com dados extremamente sensíveis. Ao contrário de plataformas tradicionais que exigem cadastro de e-mail e salvam preferências em bancos de dados na nuvem, o &lt;a href="https://12axes.site/pt/" rel="noopener noreferrer"&gt;12axes.site&lt;/a&gt; foi desenhado sob o princípio de &lt;strong&gt;privacidade por design&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sem Contas e Sem Banco de Dados:&lt;/strong&gt; Suas respostas nunca saem do navegador. O cálculo é feito 100% no cliente em TypeScript puro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resultados Codificados na URL:&lt;/strong&gt; O resultado completo dos 12 eixos é compactado em uma string alfanumérica de base 36 e anexado ao parâmetro hash &lt;code&gt;?r=...&lt;/code&gt;. Quando você compartilha seu resultado com amigos ou baixa seu card 9:16 para o Instagram/WhatsApp, o link carrega todo o estado de forma puramente matemática.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geração Local de Cards de Compartilhamento:&lt;/strong&gt; O card gráfico para redes sociais é renderizado via canvas HTML5 localmente no dispositivo do usuário, garantindo exportação instantânea e confidencial.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Conclusão
&lt;/h2&gt;

&lt;p&gt;Entender seu posicionamento político não deve se limitar a um rótulo binário ou a uma pergunta simplista de "esquerda ou direita". O espectro multidimensional de 12 eixos oferece um espelho muito mais nítido para autocrítica e diálogo cívico.&lt;/p&gt;

&lt;p&gt;Você pode &lt;a href="https://12axes.site/pt/test" rel="noopener noreferrer"&gt;fazer o teste político de 12 eixos grátis&lt;/a&gt; e explorar a definição detalhada de cada eixo em português com total privacidade.&lt;/p&gt;

&lt;p&gt;O código-fonte de cálculo das fórmulas matemáticas e as definições dos 12 eixos estão abertos para estudo da comunidade.&lt;/p&gt;

</description>
      <category>opensource</category>
    </item>
    <item>
      <title>How We Built a 100% In-Browser Image to Bead Pattern Generator (CIE Lab Color Matching &amp; Zero-Cost Architecture)</title>
      <dc:creator>Peacoke</dc:creator>
      <pubDate>Sun, 18 Oct 2026 00:57:02 +0000</pubDate>
      <link>https://dev.to/peacoke/how-we-built-a-100-in-browser-image-to-bead-pattern-generator-cie-lab-color-matching-zero-cost-3ggj</link>
      <guid>https://dev.to/peacoke/how-we-built-a-100-in-browser-image-to-bead-pattern-generator-cie-lab-color-matching-zero-cost-3ggj</guid>
      <description>&lt;p&gt;When converting user-uploaded photographs into physical fuse bead patterns (such as Perler, Hama, or Artkal beads) or retro 8-bit game sprites, most web services take the expensive path: upload the JPEG to a server, process it with OpenCV or ImageMagick in Python, and return a grid of hex codes.&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://beadpattern.art/" rel="noopener noreferrer"&gt;BeadPattern&lt;/a&gt;, we wanted a completely different architecture: &lt;strong&gt;100% client-side processing directly in the user's browser&lt;/strong&gt;. No image leaves the user's device, zero server compute or egress costs for image transformations, and instant feedback when users tweak bead counts or contrast sliders.&lt;/p&gt;

&lt;p&gt;Here is an architectural walkthrough of how we solved the three core engineering bottlenecks: perceptual color quantization, real-time canvas dithering, and responsive mobile interaction.&lt;/p&gt;




&lt;h3&gt;
  
  
  1. The Trap of Euclidean RGB Distance (Why Skin Tones Look Gray)
&lt;/h3&gt;

&lt;p&gt;The simplest way to match a pixel $(R_1, G_1, B_1)$ to a known manufacturer's bead palette is calculating Euclidean distance in standard sRGB space:&lt;/p&gt;

&lt;p&gt;$$\text{distance} = \sqrt{(R_1 - R_2)^2 + (G_1 - G_2)^2 + (B_1 - B_2)^2}$$&lt;/p&gt;

&lt;p&gt;If you implement this, you quickly notice a serious visual problem: &lt;strong&gt;subtle peach, skin tones, and pastels turn into dull gray or olive green&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The human visual cortex does not perceive light linearly. A 10-unit delta in pure green is far more noticeable to the human eye than a 10-unit delta in dark blue. To get accurate plastic bead matches, we convert every pixel and every catalog bead color into &lt;strong&gt;CIE L*a*b*&lt;/strong&gt; color space:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;$L^*$&lt;/strong&gt;: Perceptual Lightness (0 = black, 100 = white)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$a^*$&lt;/strong&gt;: Position between green (negative) and red/magenta (positive)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;$b^*$&lt;/strong&gt;: Position between blue (negative) and yellow (positive)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The Conversion Pipeline
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Step 1: sRGB to linear RGB with inverse gamma companding&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;srgbToLinear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;/=&lt;/span&gt; &lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mf"&gt;0.04045&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;12.92&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mf"&gt;0.055&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;1.055&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Step 2: Linear RGB to CIE XYZ (D65 standard illuminant)&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;rgbToXyz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&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="nx"&gt;rLin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;srgbToLinear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gLin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;srgbToLinear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bLin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;srgbToLinear&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.4124564&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.3575761&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;bLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1804375&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.2126729&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.7151522&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;bLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0721750&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;rLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.0193339&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.1191920&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;bLin&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.9503041&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Step 3: XYZ to CIE L*a*b*&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;xyzToLab&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Normalized to D65 reference white&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;95.047&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;yn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;108.883&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.008856&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cbrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&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="mf"&gt;7.787&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;116&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;zn&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;116&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;fy&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fx&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;fy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fy&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;fz&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;L&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;b&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;Once colors are in $L^&lt;em&gt;a^*b^&lt;/em&gt;$, we measure delta using the standard CIE76 Euclidean distance:&lt;/p&gt;

&lt;p&gt;$$\Delta E = \sqrt{(L_1 - L_2)^2 + (a_1 - a_2)^2 + (b_1 - b_2)^2}$$&lt;/p&gt;

&lt;p&gt;This single math adjustment immediately eliminated the "muddy portrait" bug when matching plastic beads against official catalogs. You can inspect the real-time cross-brand color mappings on our &lt;a href="https://beadpattern.art/colors" rel="noopener noreferrer"&gt;BeadPattern Interactive Color Directory&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. High-Performance Palette Quantization with Precomputed Lookups
&lt;/h3&gt;

&lt;p&gt;A typical high-resolution photograph downsampled to a $58 \times 58$ pegboard grid contains 3,364 cells. While that is small, comparing each pixel against 200+ commercial bead codes (Perler + Hama + Artkal + Mard) on every slider change requires roughly $3,364 \times 200 = 672,800$ distance calculations.&lt;/p&gt;

&lt;p&gt;To keep slider dragging at 60 FPS without dropping frames:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Precompute $L^&lt;em&gt;a^*b^&lt;/em&gt;$ vectors for the palette&lt;/strong&gt;: When the app boots, we parse all official color codes into typed &lt;code&gt;Float32Array&lt;/code&gt; buffers so coordinate lookups don't trigger JavaScript garbage collection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;K-d Tree Nearest Neighbor Lookup&lt;/strong&gt;: Instead of scanning linearly through the palette for each pixel, we index the active palette into a balanced 3D K-d tree in $L^&lt;em&gt;a^*b^&lt;/em&gt;$ space. This drops search complexity from $O(N)$ to $O(\log N)$ per bead cell.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  3. Spatial Error Diffusion (Floyd-Steinberg Dithering)
&lt;/h3&gt;

&lt;p&gt;Downsampling natural photographs to a fixed 48-color plastic palette causes harsh visual color banding, particularly across smooth gradients like skies and sunsets.&lt;/p&gt;

&lt;p&gt;To preserve perceived detail without adding artificial noise, we implemented 2D error diffusion (Floyd-Steinberg algorithm):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Error weights distributed to neighboring unfinished pixels:&lt;/span&gt;
&lt;span class="c1"&gt;//           [ current ]   7/16 (x+1, y)&lt;/span&gt;
&lt;span class="c1"&gt;// 3/16(x-1, y+1)  5/16(x, y+1)  1/16(x+1, y+1)&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;applyErrorDiffusion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Float32Array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// RGB buffer in 0..255 range&lt;/span&gt;
  &lt;span class="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ColorEntry&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="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&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;let&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="o"&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="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;oldB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;findClosestPaletteColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;oldR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;oldB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;palette&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;idx&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldR&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldG&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;errB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;oldB&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

      &lt;span class="c1"&gt;// Distribute error&lt;/span&gt;
      &lt;span class="nf"&gt;distributeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errG&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errB&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nf"&gt;distributeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errG&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errB&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nf"&gt;distributeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errG&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errB&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nf"&gt;distributeError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pixels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;errR&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errG&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;errB&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;16&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The difference is night and day: smooth skin tones and skies transition gracefully into stippled dots that naturally mimic physical bead art. For detailed step-by-step visual comparisons between clustered quantization vs dithered sprites, see our engineering guide on &lt;a href="https://beadpattern.art/blog/photo-to-pixel-art" rel="noopener noreferrer"&gt;Photo to Pixel Art Conversion&lt;/a&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  4. Zero-Server Cost Architecture
&lt;/h3&gt;

&lt;p&gt;Because all computational heavy lifting happens in client memory:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Static Delivery&lt;/strong&gt;: The application shell is served as lightweight static assets on Cloudflare Workers edge nodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy by Design&lt;/strong&gt;: Crafters frequently upload family portraits, custom anime art, and personal logos. Zero bytes of image data touch any server disk or cloud database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Instant Export&lt;/strong&gt;: Vectorized 1:1 printable PDF pegboard charts and bead inventory tables are assembled on the client using jsPDF and offscreen canvas renderers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can try the live tool directly in your browser at &lt;a href="https://beadpattern.art/" rel="noopener noreferrer"&gt;BeadPattern&lt;/a&gt;—no signup or installation required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Screens from BeadPattern
&lt;/h2&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%2F7qmyrax8wfqynh6qeobq.png" 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%2F7qmyrax8wfqynh6qeobq.png" alt="Editable bead grid with palette controls" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The editor keeps the bead grid and palette controls together.&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%2F7tn3czi3n1fh3g1lhydt.png" 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%2F7tn3czi3n1fh3g1lhydt.png" alt="Perler bead color chart" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Brand color charts show codes alongside the available shades.&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%2Fuwpxi75k97jyoqmu53qy.png" 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%2Fuwpxi75k97jyoqmu53qy.png" alt="Ready-made pattern library" width="800" height="479"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The library provides ready-made patterns to open in the editor.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>canvas</category>
      <category>performance</category>
    </item>
    <item>
      <title>Cómo funciona el test de ideología política 12 Axes: matemáticas, privacidad y 12 ejes</title>
      <dc:creator>Peacoke</dc:creator>
      <pubDate>Sat, 17 Oct 2026 17:23:12 +0000</pubDate>
      <link>https://dev.to/peacoke/como-funciona-el-test-de-ideologia-politica-12-axes-matematicas-privacidad-y-12-ejes-a44</link>
      <guid>https://dev.to/peacoke/como-funciona-el-test-de-ideologia-politica-12-axes-matematicas-privacidad-y-12-ejes-a44</guid>
      <description>&lt;p&gt;En los últimos días, el &lt;strong&gt;test de ideología política 12 Axes&lt;/strong&gt; se ha vuelto viral en redes sociales y medios de América Latina como una alternativa mucho más precisa a la tradicional brújula política bidimensional (Political Compass).&lt;/p&gt;

&lt;p&gt;A diferencia de los cuestionarios que reducen toda la visión política a dos ejes (económico y social), este modelo evalúa 12 dimensiones independientes. Desarrollamos una versión moderna, gratuita y de código abierto en español: &lt;a href="https://12axes.site/es/" rel="noopener noreferrer"&gt;test de ideología política 12 axes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Aquí te explicamos la arquitectura técnica detrás del cálculo, cómo protegemos la privacidad y por qué funciona en el navegador.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Doce dimensiones en lugar de dos
&lt;/h2&gt;

&lt;p&gt;El test mide 12 escalas independientes del 0 al 100:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Constructo (Económico)&lt;/strong&gt;: Comunismo vs. Capitalismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Autoridad (Poder)&lt;/strong&gt;: Anarquismo vs. Autoritarismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontera (Diplomacia)&lt;/strong&gt;: Globalismo vs. Nacionalismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gobierno (Estado)&lt;/strong&gt;: Democracia directa vs. Autocracia&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cultura&lt;/strong&gt;: Progresismo vs. Tradicionalismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sociedad&lt;/strong&gt;: Igualitarismo vs. Jerarquía&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Justicia&lt;/strong&gt;: Rehabilitación vs. Punitivismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ecología&lt;/strong&gt;: Ecologismo vs. Productivismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tecnología&lt;/strong&gt;: Transhumanismo vs. Bioconservadurismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Militarismo&lt;/strong&gt;: Pacifismo vs. Militarismo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Religión&lt;/strong&gt;: Secularismo vs. Teocracia&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Seguridad&lt;/strong&gt;: Libertad civil vs. Seguridad del Estado&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cada afirmación afecta únicamente a un eje específico con una ponderación fija (de fuertemente en desacuerdo a fuertemente de acuerdo).&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Tres modalidades: 36, 60 y 288 preguntas
&lt;/h2&gt;

&lt;p&gt;El cuestionario original de 288 afirmaciones es exhaustivo, pero requiere más de 25 minutos. Para adaptarlo al uso en dispositivos móviles sin perder rigor estadístico:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modo Express (36 preguntas)&lt;/strong&gt;: 3 afirmaciones por eje, diseñado para resolverse en unos 4 minutos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modo Estándar (60 preguntas)&lt;/strong&gt;: 5 afirmaciones por eje, el equilibrio recomendado entre precisión y tiempo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modo Completo (288 preguntas)&lt;/strong&gt;: La prueba completa para investigación profunda.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Privacidad 100% en el cliente (Zero-Knowledge)
&lt;/h2&gt;

&lt;p&gt;La mayoría de los cuestionarios de personalidad almacenan tus respuestas en bases de datos o rastrean tu perfil. &lt;/p&gt;

&lt;p&gt;En &lt;a href="https://12axes.site/es/" rel="noopener noreferrer"&gt;12axes.site&lt;/a&gt;, todo el cálculo se ejecuta en JavaScript dentro del navegador del usuario:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sin cuentas ni correos&lt;/strong&gt;: No pedimos registro.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sin base de datos&lt;/strong&gt;: Las respuestas nunca se envían a ningún servidor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resultados en la URL&lt;/strong&gt;: La puntuación final se codifica en un parámetro compacto Base36 (&lt;code&gt;?r=...&lt;/code&gt;) que el usuario puede compartir si lo desea, garantizando total soberanía de datos.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Coincidencia con 38 ideologías y figuras históricas
&lt;/h2&gt;

&lt;p&gt;Al completar el cuestionario, el algoritmo calcula la distancia euclidiana multidimensional normalizada entre tu vector de 12 ejes y una matriz de 38 ideologías políticas documentadas:&lt;/p&gt;

&lt;p&gt;$$D = \sqrt{\sum_{i=1}^{n} (P_{\text{usuario}, i} - P_{\text{ideología}, i})^2}$$&lt;/p&gt;

&lt;p&gt;Además, compara tu perfil con más de 70 figuras políticas históricas para mostrar qué pensadores tenían posturas similares a las tuyas.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pruébalo gratis y en español
&lt;/h2&gt;

&lt;p&gt;Si quieres conocer tu ubicación exacta en los doce ejes y descargar tu tarjeta de resultados:&lt;/p&gt;

&lt;p&gt;👉 &lt;strong&gt;&lt;a href="https://12axes.site/es/" rel="noopener noreferrer"&gt;Hacer el test político 12 ejes en español&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;El código está optimizado con Vite, TanStack Router y Cloudflare Workers para cargar de forma instantánea en cualquier móvil.&lt;/p&gt;

</description>
      <category>spanish</category>
      <category>webdev</category>
      <category>javascript</category>
      <category>algorithms</category>
    </item>
  </channel>
</rss>
