<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ WebGL - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ WebGL - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 09 Jun 2026 10:25:39 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/webgl/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How WebGL and Three.js Power Interactive Online Stores ]]>
                </title>
                <description>
                    <![CDATA[ When online shopping first took off, product pages were built around a few static images and maybe a zoom feature. That was enough back then. But today’s customers expect far more. They want to spin a sneaker around, preview a sofa in their living ro... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-webgl-and-threejs-power-interactive-online-stores/</link>
                <guid isPermaLink="false">68ac8e669a85df841d9f286d</guid>
                
                    <category>
                        <![CDATA[ WebGL ]]>
                    </category>
                
                    <category>
                        <![CDATA[ ThreeJS ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Ajay Kalal ]]>
                </dc:creator>
                <pubDate>Mon, 25 Aug 2025 16:25:10 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1756138909378/69cae8fe-9a57-4036-817a-fde4e6a19f3b.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>When online shopping first took off, product pages were built around a few static images and maybe a zoom feature. That was enough back then. But today’s customers expect far more. They want to spin a sneaker around, preview a sofa in their living room, or customize the color of a water bottle, all before clicking “Add to Cart.” </p>
<p>This is where WebGL and Three.js come in. Together, they make it possible to bring interactive 3D graphics to online stores, directly inside the browser, without plugins or external apps. </p>
<p>In this article, we’ll break down how these technologies work, why they’re transforming eCommerce, and what developers need to know to build the next generation of interactive shopping experiences. </p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#heading-what-is-webgl">What is WebGL?</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-threejs-makes-webgl-developer-friendly">How Three.js Makes WebGL Developer-Friendly</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-build-a-simple-3d-configurator-demo">How to Build a Simple 3D Configurator Demo</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-step-1-setting-up-the-html-file">Step 1: Setting Up the HTML File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-2-adding-styles-with-css">Step 2: Adding Styles with CSS</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-3-creating-the-scene-in-scriptjs">Step 3: Creating the Scene in Script.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-4-adding-a-product-cube">Step 4: Adding a Product (Cube)</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-5-making-the-cube-perspective">Step 5: Making the Cube Interactive</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-step-6-making-it-responsive">Step 6: Making It Responsive</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-role-of-3d-in-ecommerce">The Role of 3D in eCommerce</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-real-world-use-cases">Real-World Use Cases</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-technical-challenges--best-practices">Technical Challenges &amp; Best Practices</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-the-future-of-3d-in-online-stores">The Future of 3D in Online Stores</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-conclusion">Conclusion</a></p>
</li>
</ul>
<h3 id="heading-prerequisites">💡 Prerequisites</h3>
<p>To get the most out of this article, you should have:</p>
<ul>
<li><p>A basic understanding of JavaScript (variables, functions, imports).</p>
</li>
<li><p>Familiarity with HTML and the DOM (since we’ll be rendering into a <code>&lt;canvas&gt;</code>).</p>
</li>
<li><p>Curiosity about graphics programming – no deep math or shader knowledge is required.</p>
</li>
<li><p>Node.js and npm installed (if you want to try out the Three.js examples locally).</p>
</li>
</ul>
<p>If you’ve never worked with 3D graphics before, don’t worry. We’ll keep the examples simple and focus on concepts</p>
<h2 id="heading-what-is-webgl"><strong>What is WebGL?</strong></h2>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API"><strong>WebGL (Web Graphics Library)</strong></a> is a JavaScript API that allows you to render interactive 2D and 3D graphics in the browser using the computer’s GPU. Unlike older browser technologies (think Flash), WebGL is built directly into modern browsers, so users don’t need to install anything extra. </p>
<p>At its core, WebGL is based on OpenGL ES (a subset of the OpenGL specification), and it provides developers with a low-level API to work with shaders, vertices, and rendering pipelines. </p>
<p>A minimal WebGL example might look like this: </p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">canvas</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"glcanvas"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"640"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"480"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">canvas</span>&gt;</span> 

<span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript"> 
  <span class="hljs-keyword">const</span> canvas = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"glcanvas"</span>); 
  <span class="hljs-keyword">const</span> gl = canvas.getContext(<span class="hljs-string">"webgl"</span>); 

  <span class="hljs-keyword">if</span> (!gl) { 
    alert(<span class="hljs-string">"WebGL not supported by your browser"</span>); 
  } 

  <span class="hljs-comment">// Clear the canvas with a background color </span>
  gl.clearColor(<span class="hljs-number">0.0</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">0.5</span>, <span class="hljs-number">1.0</span>); 
  gl.clear(gl.COLOR_BUFFER_BIT); 
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>If you run this snippet, it simply fills a canvas with a teal color. Not too exciting – but it’s happening on the GPU, and from here, you can go all the way to photorealistic 3D. </p>
<h2 id="heading-how-threejs-makes-webgl-developer-friendly"><strong>How Three.js Makes WebGL Developer-Friendly</strong></h2>
<p>While WebGL is powerful, it’s also verbose. Developers need to manage shaders, buffer objects, and projection matrices manually, which is a steep learning curve for most front-end engineers. </p>
<p>This is where <a target="_blank" href="https://threejs.org/"><strong>Three.js</strong></a> shines. It’s a popular JavaScript library that wraps around WebGL and provides a higher-level, developer-friendly API for working with 3D graphics. Instead of hundreds of lines of setup code, you can get a 3D scene up and running in a few lines. </p>
<p>Here’s a simple Three.js example that creates a rotating cube: </p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> * <span class="hljs-keyword">as</span> THREE <span class="hljs-keyword">from</span> <span class="hljs-string">'three'</span>; 

<span class="hljs-comment">// Create a scene </span>
<span class="hljs-keyword">const</span> scene = <span class="hljs-keyword">new</span> THREE.Scene(); 

<span class="hljs-comment">// Camera setup </span>
<span class="hljs-keyword">const</span> camera = <span class="hljs-keyword">new</span> THREE.PerspectiveCamera(<span class="hljs-number">75</span>, <span class="hljs-built_in">window</span>.innerWidth/<span class="hljs-built_in">window</span>.innerHeight, <span class="hljs-number">0.1</span>, <span class="hljs-number">1000</span>); 

<span class="hljs-comment">// Renderer </span>
<span class="hljs-keyword">const</span> renderer = <span class="hljs-keyword">new</span> THREE.WebGLRenderer(); 
renderer.setSize(<span class="hljs-built_in">window</span>.innerWidth, <span class="hljs-built_in">window</span>.innerHeight); 
<span class="hljs-built_in">document</span>.body.appendChild(renderer.domElement); 

<span class="hljs-comment">// Add a cube </span>
<span class="hljs-keyword">const</span> geometry = <span class="hljs-keyword">new</span> THREE.BoxGeometry(); 
<span class="hljs-keyword">const</span> material = <span class="hljs-keyword">new</span> THREE.MeshBasicMaterial({ <span class="hljs-attr">color</span>: <span class="hljs-number">0x00ff00</span> }); 
<span class="hljs-keyword">const</span> cube = <span class="hljs-keyword">new</span> THREE.Mesh(geometry, material); 
scene.add(cube); 

camera.position.z = <span class="hljs-number">5</span>; 

<span class="hljs-comment">// Animation loop </span>
<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">animate</span>(<span class="hljs-params"></span>) </span>{ 
  requestAnimationFrame(animate); 
  cube.rotation.x += <span class="hljs-number">0.01</span>; 
  cube.rotation.y += <span class="hljs-number">0.01</span>; 
  renderer.render(scene, camera); 
} 
animate();
</code></pre>
<p>With just a few lines, you have an interactive 3D object rendered inside the browser. This ease of use is why Three.js has become the go-to library for developers building interactive product experiences online. </p>
<h2 id="heading-how-to-build-a-simple-3d-configurator-demo">How to Build a Simple 3D Configurator Demo</h2>
<p>To understand how these technologies translate to real-world online shopping, let’s build a tiny demo: a 3D box that rotates and changes color when a button is clicked. Think of it as the most basic version of a product previewer. </p>
<h3 id="heading-step-1-setting-up-the-html-file">Step 1: Setting Up the HTML File</h3>
<p>Let’s start with an <code>index.html file</code>. This file will contain a <code>&lt;canvas&gt;</code> function for rendering our 3D scene and a few buttons that act like product “options” (for example, choosing red, blue, or green). </p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span>&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>3D Product Demo<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="css"> 
    <span class="hljs-selector-tag">body</span> { 
      <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>; 
      <span class="hljs-attribute">overflow</span>: hidden; 
      <span class="hljs-attribute">font-family</span>: sans-serif; 
      <span class="hljs-attribute">background</span>: <span class="hljs-number">#f5f5f5</span>; 
    } 
    <span class="hljs-selector-tag">canvas</span> { <span class="hljs-attribute">display</span>: block; } 
    <span class="hljs-selector-class">.controls</span> { 
      <span class="hljs-attribute">position</span>: absolute; 
      <span class="hljs-attribute">top</span>: <span class="hljs-number">20px</span>; 
      <span class="hljs-attribute">left</span>: <span class="hljs-number">20px</span>; 
      <span class="hljs-attribute">display</span>: flex; 
      <span class="hljs-attribute">gap</span>: <span class="hljs-number">10px</span>; 
    } 
    <span class="hljs-selector-tag">button</span> { 
      <span class="hljs-attribute">padding</span>: <span class="hljs-number">10px</span> <span class="hljs-number">16px</span>; 
      <span class="hljs-attribute">font-size</span>: <span class="hljs-number">14px</span>; 
      <span class="hljs-attribute">border</span>: none; 
      <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">4px</span>; 
      <span class="hljs-attribute">cursor</span>: pointer; 
      <span class="hljs-attribute">color</span>: white; 
    } 
    <span class="hljs-selector-class">.red</span> { <span class="hljs-attribute">background</span>: <span class="hljs-number">#e63946</span>; } 
    <span class="hljs-selector-class">.blue</span> { <span class="hljs-attribute">background</span>: <span class="hljs-number">#0077ff</span>; } 
    <span class="hljs-selector-class">.green</span> { <span class="hljs-attribute">background</span>: <span class="hljs-number">#2a9d8f</span>; } 
    <span class="hljs-selector-tag">button</span><span class="hljs-selector-pseudo">:hover</span> { <span class="hljs-attribute">opacity</span>: <span class="hljs-number">0.8</span>; } 
  </span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span> 
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span> 
  <span class="hljs-comment">&lt;!-- Controls to change product colors --&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"controls"</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"red"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"setColor(0xe63946)"</span>&gt;</span>Red<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"blue"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"setColor(0x0077ff)"</span>&gt;</span>Blue<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> 
    <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"green"</span> <span class="hljs-attr">onclick</span>=<span class="hljs-string">"setColor(0x2a9d8f)"</span>&gt;</span>Green<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span> 
  <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span> 

  <span class="hljs-comment">&lt;!-- Import Three.js library --&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/three@0.154/build/three.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> 
  <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"script.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span> 
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Here’s what we’ve done: </p>
<ul>
<li><p>Added a few styled buttons for color options. </p>
</li>
<li><p>Set up some basic CSS for layout and design. </p>
</li>
<li><p>Included the Three.js library from a CDN. </p>
</li>
<li><p>Linked to a <code>script.js</code> file where we’ll write our 3D logic. </p>
</li>
</ul>
<h3 id="heading-step-2-creating-the-scene-in-scriptjs">Step 2: Creating the Scene in Script.js</h3>
<p>Now create a file called <code>script.js</code>. This is where we’ll build the 3D world. </p>
<p>The first step is to create a scene, a camera, and a renderer. Think of it like this: the <strong>scene</strong> is the stage, the <strong>camera</strong> is the viewpoint, and the <strong>renderer</strong> is what draws everything to the screen. </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create the scene </span>
<span class="hljs-keyword">const</span> scene = <span class="hljs-keyword">new</span> THREE.Scene(); 

<span class="hljs-comment">// Set up a camera </span>
<span class="hljs-keyword">const</span> camera = <span class="hljs-keyword">new</span> THREE.PerspectiveCamera( 
  <span class="hljs-number">75</span>, <span class="hljs-built_in">window</span>.innerWidth / <span class="hljs-built_in">window</span>.innerHeight, <span class="hljs-number">0.1</span>, <span class="hljs-number">1000</span> 
); 
camera.position.z = <span class="hljs-number">3</span>; 

<span class="hljs-comment">// Create a WebGL renderer </span>
<span class="hljs-keyword">const</span> renderer = <span class="hljs-keyword">new</span> THREE.WebGLRenderer({ <span class="hljs-attr">antialias</span>: <span class="hljs-literal">true</span> }); 
renderer.setSize(<span class="hljs-built_in">window</span>.innerWidth, <span class="hljs-built_in">window</span>.innerHeight); 
<span class="hljs-built_in">document</span>.body.appendChild(renderer.domElement);
</code></pre>
<h3 id="heading-step-3-adding-a-product-cube">Step 3: Adding a Product (Cube)</h3>
<p>For simplicity, we’ll use a cube to represent our product. Later, this could be any 3D model (like a shoe, sofa, or banner stand). </p>
<pre><code class="lang-javascript"><span class="hljs-comment">// Create a cube geometry </span>
<span class="hljs-keyword">const</span> geometry = <span class="hljs-keyword">new</span> THREE.BoxGeometry(<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>); 

<span class="hljs-comment">// Apply a material (blue color by default) </span>
<span class="hljs-keyword">let</span> material = <span class="hljs-keyword">new</span> THREE.MeshStandardMaterial({ <span class="hljs-attr">color</span>: <span class="hljs-number">0x0077ff</span> }); 

<span class="hljs-comment">// Combine geometry and material into a mesh </span>
<span class="hljs-keyword">const</span> cube = <span class="hljs-keyword">new</span> THREE.Mesh(geometry, material); 

<span class="hljs-comment">// Add the cube to the scene </span>
scene.add(cube); 

<span class="hljs-comment">// Add lighting so we can see the cube properly </span>
<span class="hljs-keyword">const</span> light = <span class="hljs-keyword">new</span> THREE.DirectionalLight(<span class="hljs-number">0xffffff</span>, <span class="hljs-number">1</span>); 
light.position.set(<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">5</span>).normalize(); 
scene.add(light);
</code></pre>
<h3 id="heading-step-4-animating-the-cube">Step 4: Animating the Cube</h3>
<p>We want the cube to spin. This creates the feeling of an interactive product preview. Here’s how we can make that happen:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">animate</span>(<span class="hljs-params"></span>) </span>{ 
  requestAnimationFrame(animate); 

  cube.rotation.x += <span class="hljs-number">0.01</span>; 
  cube.rotation.y += <span class="hljs-number">0.01</span>; 

  renderer.render(scene, camera); 
} 
animate();
</code></pre>
<p>Now, when you load the page, the cube will rotate continuously. </p>
<h3 id="heading-step-5-adding-interactivity">Step 5: Adding Interactivity</h3>
<p>Let’s connect the color buttons to the cube. Each button calls the <code>setColor()</code> function with a hex code. </p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">setColor</span>(<span class="hljs-params">hex</span>) </span>{ 
  cube.material.color.setHex(hex); 
}
</code></pre>
<p>Now, when you click “Red,” “Blue,” or “Green,” the cube changes color instantly, like switching between product variations. </p>
<h3 id="heading-step-6-making-it-responsive">Step 6: Making It Responsive</h3>
<p>Finally, let’s ensure the canvas resizes properly on different devices. </p>
<pre><code class="lang-javascript"><span class="hljs-built_in">window</span>.addEventListener(<span class="hljs-string">"resize"</span>, <span class="hljs-function">() =&gt;</span> { 
  camera.aspect = <span class="hljs-built_in">window</span>.innerWidth / <span class="hljs-built_in">window</span>.innerHeight; 
  camera.updateProjectionMatrix(); 
  renderer.setSize(<span class="hljs-built_in">window</span>.innerWidth, <span class="hljs-built_in">window</span>.innerHeight); 
});
</code></pre>
<p>We now have a mini product/Object previewer: </p>
<ul>
<li><p>A 3D object (cube) that rotates like a real product. </p>
</li>
<li><p>Buttons that change its color, simulating product options. </p>
</li>
<li><p>Responsive rendering across screen sizes. </p>
</li>
</ul>
<p>This is, of course, a simplified demo, but the same principles are used in real-world ecommerce experiences.</p>
<h3 id="heading-example-of-3d-configurator">Example of 3D Configurator</h3>
<div class="embed-wrapper"><iframe height="523" style="width:100%" src="https://codepen.io/Petr-Hovorka-the-sans/embed/qEdEJjy?default-tab=result" title="Embedded content" loading="lazy">
  See the Pen <a href="https://codepen.io/Petr-Hovorka-the-sans/pen/qEdEJjy">
  3D Configurator 0.9</a> by Petr Hovorka (<a href="https://codepen.io/Petr-Hovorka-the-sans">@Petr-Hovorka-the-sans</a>)
  on <a href="https://codepen.io">CodePen</a>.
</iframe></div>

<h2 id="heading-the-role-of-3d-in-ecommerce">The Role of 3D in eCommerce</h2>
<p>Why should online stores invest in 3D at all? The answer lies in user engagement. Studies show that customers are far more likely to convert when they can interact with products in detail. Instead of scrolling through flat images, they rotate, zoom, and even customize products in real-time. </p>
<p>From a developer’s perspective, integrating 3D isn’t just about “making it pretty.” It’s about: </p>
<ul>
<li><p><strong>Reducing return rates</strong> (customers know exactly what they’re buying). </p>
</li>
<li><p><strong>Increasing time-on-site</strong> (3D models encourage exploration). </p>
</li>
<li><p><strong>Supporting customization workflows</strong> (colors, materials, engravings). </p>
</li>
</ul>
<h2 id="heading-real-world-use-cases">Real-World Use Cases</h2>
<p>There are a few areas where WebGL + Three.js are already changing eCommerce. <a target="_blank" href="https://www.designnbuy.com/3d-product-configurator-software/">3D product configurators</a> utilize Three.js to enable customers to customize products interactively, changing colors and textures.</p>
<p>For example, 3D product reviews where online stores let customers rotate couches, cars, or appliances to see every angle. Virtual try-ons are also becoming popular among eyewear and fashion brands. They use AR + WebGL to let customers virtually try items online. Online printers and manufacturers also let customers configure their products in 3D before purchasing them.</p>
<h2 id="heading-technical-challenges-amp-best-practices"><strong>Technical Challenges &amp; Best Practices</strong></h2>
<p>Building interactive 3D experiences isn’t without hurdles. Developers need to think about: </p>
<ul>
<li><p><strong>Performance optimization</strong> – Compressing models, using Level of Detail (LOD), and reducing texture sizes. </p>
</li>
<li><p><strong>Cross-device compatibility</strong> – Ensuring 3D experiences work smoothly on both high-end desktops and mobile devices. </p>
</li>
<li><p><strong>Loading times</strong> – Using lazy loading for textures and assets. </p>
</li>
<li><p><strong>User experience</strong> – Smooth navigation controls, fallback images for unsupported devices, and accessible interactions. </p>
</li>
</ul>
<h3 id="heading-the-future-of-3d-in-online-stores"><strong>The Future of 3D in Online Stores</strong></h3>
<p>We’re only scratching the surface of what’s possible. Some trends shaping the future include: </p>
<ul>
<li><p>WebGPU: a next-generation graphics API that promises even better performance than WebGL. </p>
</li>
<li><p>Augmented Reality (AR): blending real and digital worlds with WebXR. </p>
</li>
<li><p>AI-powered customization: automatically generating product variations or suggestions. </p>
</li>
</ul>
<h2 id="heading-conclusion"><strong>Conclusion</strong></h2>
<p>WebGL and Three.js are powering a new wave of interactive online shopping. What used to require native apps or heavy plugins is now achievable directly in the browser, giving customers richer experiences and businesses higher conversion rates. </p>
<p>For developers, experimenting with WebGL and Three.js opens the door to a whole range of applications, from simple product previews to full-fledged 3D configurators. And as browser technology evolves, the line between online shopping and real-world interaction will only continue to blur.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to use WebGL shaders in WebAssembly ]]>
                </title>
                <description>
                    <![CDATA[ By Dan Ruta WebAssembly is blazing fast for number crunching, game engines, and many other things, but nothing can quite compare to the extreme parallelization of shaders, running on the GPU. This is especially so if you’re looking to do some image p... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-use-webgl-shaders-in-webassembly-1e6c5effc813/</link>
                <guid isPermaLink="false">66c355f2e9895571912a0c99</guid>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Shaders ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Tutorial ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WebAssembly ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WebGL ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 28 Dec 2017 18:26:48 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*wJXxr-2-89FQ2O1wVXBD8w.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Dan Ruta</p>
<p>WebAssembly is blazing fast for <a target="_blank" href="https://ai.danruta.co.uk/webassembly">number crunching</a>, <a target="_blank" href="http://webassembly.org/demo/">game engines</a>, and many other things, but nothing can quite compare to the extreme parallelization of shaders, running on the GPU.</p>
<p>This is especially so if you’re looking to do some image processing. Usually, on the web, this is done through WebGL, but how would you access its APIs when using WebAssembly?</p>
<h3 id="heading-setting-up">Setting up</h3>
<p>We’ll very briefly go through setting up an example project, then we’ll look at how an image can be loaded as a texture. Then, in a separate context, we’ll apply an edge detection GLSL shader to the image.</p>
<p>All the code is in a repo <a target="_blank" href="https://github.com/DanRuta/webassembly-webgl-shaders">here</a>, if you’d prefer to jump straight to that. Note that you have to serve your files via a server for WebAssembly to work.</p>
<p>As a prerequisite, I’m going to assume you already have your WebAssembly project set up. If not, you can check out the article <a target="_blank" href="https://medium.com/statuscode/setting-up-the-ultimate-webassembly-c-workflow-6484efa3e162">here</a> on how to do it, or just fork the repo linked above.</p>
<p>For demoing the below code, I’m using a basic html file which serves only to load an image, get its imageData, and pass it to the WebAssembly code using <a target="_blank" href="https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97">the <em>ccallArrays</em> function</a>.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*zJIvrPP5Q_-JqJSSAH738g.png" alt="Image" width="342" height="464" loading="lazy">
<em>The HTML file with the preview input image</em></p>
<p>As for the C++ code, there is an emscripten.cpp file which manages and routes method calls to context instances created in the Context.cpp file. The Context.cpp file is structured as follows:</p>
<h3 id="heading-compilation">Compilation</h3>
<p>WebGL is based on and follows the OpenGL ES (Embedded Systems) spec, which is a subset of OpenGL. When compiling, emscripten will map our code to the WebGL API.</p>
<p>There are a couple of different versions we can target. OpenGL ES 2 maps to WebGL 1, whereas OpenGL ES 3 maps to WebGL 2. By default you should target WebGL 2, as it comes with <a target="_blank" href="https://github.com/kripken/emscripten/blob/incoming/site/source/docs/optimizing/Optimizing-WebGL.rst#which-gl-mode-to-target">some free optimizations and improvements</a>.</p>
<p>To do this, we must add <a target="_blank" href="https://kripken.github.io/emscripten-site/docs/porting/multimedia_and_graphics/OpenGL-support.html#webgl-friendly-subset-of-opengl-es-2-0-3-0">the <code>USE_WEBGL2=1</code> flag</a> to the compilation.</p>
<p>If you are planning to use some OpenGL ES features not present in the WebGL spec, you can use t<a target="_blank" href="https://kripken.github.io/emscripten-site/docs/porting/multimedia_and_graphics/OpenGL-support.html#opengl-es-2-0-3-0-emulation">he <code>FULL_ES2=1</code> and/or <code>FULL_ES3=1</code> flags</a>.</p>
<p>To be able to handle large textures/images, we can also add <a target="_blank" href="https://kripken.github.io/emscripten-site/docs/optimizing/Optimizing-Code.html#memory-growth">the <code>ALLLOW_MEMORY_GROWTH=1</code> flag</a>. This removes the memory limit of the WebAssembly program, at the cost of some optimizations.</p>
<p>If you know ahead of time how much memory you’ll need, you can instead use the <code>TOTAL_MEMORY=X</code> flag, where X is the memory size.</p>
<p>So we’re going to end up with something like this:</p>
<p><code>emcc -o ./dist/appWASM.js ./dev/cpp/emscripten.cpp -O3 -s ALLOW_MEMORY_GROWTH=1 -s USE_WEBGL2=1 -s FULL_ES3=1 -s WASM=1 -s NO_EXIT_RUNTIME=1 -std=c++1z</code></p>
<p>Finally, we need the following imports, in our code:</p>
<pre><code>#include &lt;emscripten.h&gt;#include &lt;string&gt;#include &lt;GLES2/gl2.h&gt;#include &lt;EGL/egl.h&gt;extern <span class="hljs-string">"C"</span> {       #include <span class="hljs-string">"html5.h"</span> <span class="hljs-comment">// emscripten module}</span>
</code></pre><h3 id="heading-implementation">Implementation</h3>
<p>If you have previous experience with WebGL or OpenGL, then this bit may seem familiar.</p>
<p>When writing OpenGL, the API will not work until you create a context. This is normally done using platform specific APIs. However, the web is not platform bound, and we can instead use an API integrated into OpenGL ES.</p>
<p>The majority of the legwork, however, can be more easily implemented using emscripten’s APIs in <a target="_blank" href="http://kripken.github.io/emscripten-site/docs/api_reference/html5.h">the html5.h file</a>. The functions we’re interested in are:</p>
<ul>
<li>_emscripten_webgl_create<em>context</em> — This will instantiate a context for the given canvas and attributes</li>
<li>_emscripten_webgl_destroy<em>context</em> — This is needed for cleaning up memory when destructing context instances</li>
<li>_emscripten_webgl_make_context<em>current</em> — This will assign and switch which context WebGL will render to</li>
</ul>
<h4 id="heading-create-the-context">Create the context</h4>
<p>To start implementing, you have to first create the canvas elements in your JavaScript code. Then, when using the <code>emscripten_webgl_create_context</code> function, you pass the id of the canvas as the first parameter, with any configurations as the second. The <code>emscripten_webgl_make_context_current</code> function is used to set the new context as the one currently in use.</p>
<p>Next, the vertex shader (to specify coordinates) and the fragment shader (to calculate the colour at each pixel) are both compiled, and the program is built.</p>
<p>Finally, the shaders are attached to the program, which is then linked, and validated.</p>
<p>Though that sounds like a lot, the code for this is as follows:</p>
<p>The shader compilation is done within the <code>CompileShader</code> helper function which performs the compilation, printing out any errors:</p>
<h4 id="heading-create-the-shader">Create the shader</h4>
<p>The shader code for this example is minimal, and it just maps each pixel to itself, to display the image as a texture:</p>
<p>You can access the canvas’ context in JavaScript in addition to the context in the C++ code, but it must be of the same type, ‘webgl2’. While defining multiple context types does nothing when just using JavaScript, if you do it before creating the webgl2 context in WebAssembly, it will throw an error when the code execution gets there.</p>
<h4 id="heading-loading-the-texture">Loading the texture</h4>
<p>The first thing to do when applying the shader is to call the <code>emscripten_webgl_make_context_current</code>function to make sure that we are still using the correct context, and <code>glUseProgram</code>to make sure we are using the correct program.</p>
<p>Next, we get the indices of the GLSL variables (similar to getting a pointer) via the<code>glGetAttribLocation</code>and <code>glGetUniformLocation</code> functions, so we can assign our own values to those locations. The function used to do that depends on the value type.</p>
<p>For example, an integer, such as the texture location needs <code>glUniform1i</code>, whereas a float would need <code>glUniform1f</code>. <a target="_blank" href="https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glUniform.xhtml">This is a good resource</a> for seeing which function you need to use.</p>
<p>Next, we get the texture object via <code>glGenTextures</code>, assign it as the active texture, and load the imageData buffer. The vertex and indices buffers are then bound, to set the boundaries of the texture to fill the canvas.</p>
<p>Finally, we clear the existing content, define our remaining variables with data, and draw to the canvas.</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*lICDL2HxpbsJ2RjvjfzCbg.png" alt="Image" width="479" height="455" loading="lazy">
<em>The texture being loaded</em></p>
<h4 id="heading-detect-edges-using-a-shader">Detect edges using a shader</h4>
<p>To add another context, where the edge detection is done, we load a different fragment shader (which applies the <a target="_blank" href="https://en.wikipedia.org/wiki/Sobel_operator">Sobel</a> filter), and we bind the width and height as extra variables, in the code.</p>
<p>To pick between different fragment shaders, for the different contexts, we just add an if-else statement in the constructor, like so:</p>
<p>And to load the width and height variables, we add the following to the run function:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*kfvsG8s4vRLbxPxZot8isg.png" alt="Image" width="700" height="455" loading="lazy"></p>
<p>If you run into an error similar to<code>ERROR: GL_INVALID_OPERATION : glUniform1i: wrong uniform function for type</code>, then there’s a mismatched assignment function for the given variable.</p>
<p>One thing to look out for when sending the imageData, is to use the correct heap, unsigned integer (the Uint8Array typed array). You can learn more about those <a target="_blank" href="https://becominghuman.ai/passing-and-returning-webassembly-array-parameters-a0f572c65d97">here</a>, but if you’re using the ccallArray function, set the ‘<em>heapIn</em>’ config to “<em>HEAPU8</em>”, as seen above.</p>
<p>If the type is not correct, the texture will still load, but you’re going to be seeing strange renderings, like these:</p>
<p><img src="https://cdn-media-1.freecodecamp.org/images/1*0_EmLybuEaLJnnd_JfobFg.png" alt="Image" width="706" height="466" loading="lazy"></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>We’ve gone through a mini “Hello World!”-style project to show how to load textures and apply GLSL shaders to them in WebAssembly. The complete code is hosted on GitHub <a target="_blank" href="https://github.com/DanRuta/webassembly-webgl-shaders">here</a>, for further reference.</p>
<p>For a real project, you may want to add some additional error handling. I omitted it here, for clarity.</p>
<p>It may also be more efficient (in the above example) to share data such as the imageData texture between contexts. You can read more about this and more <a target="_blank" href="https://blog.gvnott.com/some-usefull-facts-about-multipul-opengl-contexts/">here</a>.</p>
<p>For some further reading, you can check out <a target="_blank" href="https://www.khronos.org/opengl/wiki/Common_Mistakes">this link</a> for common mistakes, or you can look through some demo projects in emscripten’s <a target="_blank" href="https://github.com/kripken/emscripten/tree/incoming/tests/glbook">glbook</a> folder, on GitHub.</p>
<p>To see WebGL being used in a WebAssembly project, you can check out the <a target="_blank" href="https://github.com/DanRuta/jsNet/tree/dev">dev branch on jsNet</a>, a web based deep learning framework, where I’ll be working on moving heavier computations onto shaders, over the next few weeks (support for WebGL compute shaders via OpenGL ES 3.1 <a target="_blank" href="https://www.khronos.org/webgl/public-mailing-list/public_webgl/1706/msg00034.php">can’t come soon enough</a> ? ).</p>
<p><strong>Update</strong></p>
<p>To see what GPU compute using shaders would look like in WebAssembly, you can check out <a target="_blank" href="https://github.com/DanRuta/GPGPU">the repo for GPGPU</a>, a small library I’m working on, with both JavaScript and WebAssembly versions.</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
