Textures are images that wrap around 3D shapes to make them look real

A texture is a 2D image file — usually PNG or JPG — that you map onto a 3D object in your game. Instead of drawing a cube as a flat color, you wrap a brick texture around it, or a wood texture, or a metal surface. The browser reads the image file and stretches it across the geometry you've built.

In HTML games, you almost always use WebGL (the graphics standard that browsers support) and a library like Three.js or Babylon.js to handle the heavy lifting. These libraries give you straightforward commands to load an image and attach it to a shape. Without a library, you'd write raw WebGL code that takes hundreds of lines just to display one textured cube.

The process has three steps: load the image file, create a material that uses that image, and attach the material to your 3D object. Most of the work is making sure the image file path is correct and the image is actually loaded before you try to use it.

Key Takeaways

  • Textures are image files (PNG or JPG) that wrap around 3D shapes to give them detail and realism without adding geometry.
  • Three.js and Babylon.js are the two most common libraries for HTML games because they handle texture loading and WebGL rendering for you.
  • You load a texture with a TextureLoader, create a material that references it, and then assign that material to your mesh or object.
  • Texture coordinates (UV mapping) tell the browser which part of the image goes on which part of the shape, and most 3D models come with these already set.
  • Common mistakes are using the wrong file path, forgetting to wait for the image to load, or using an image that is too large and slows down the game.

Loading a texture with Three.js

Three.js includes a TextureLoader object that handles image loading. You create a new TextureLoader, call its load method with the path to your image, and pass a function that runs when the image is ready.

Here is the actual pattern you use:

Create a TextureLoader. Call loader.load() with the image path. Inside the load function, create a material that uses the texture. Create a mesh with that material. Add the mesh to your scene. The browser downloads the image in the background, and when it arrives, your function runs and builds the object.

The most common mistake is trying to use the texture before it loads. If you create your mesh outside the load function, the texture will not be attached yet. Always create the mesh inside the callback function, after the texture variable is set.

Setting up texture coordinates on your 3D model

UV mapping is the system that tells the browser which part of the image goes on which part of the shape. U and V are the horizontal and vertical axes of your image (like X and Y, but for 2D images). Every vertex of your 3D model has UV coordinates that point to a spot on the texture.

If you build your model in Blender or another 3D tool, the UV map is usually already there. When you export the model as OBJ or glTF format and load it into Three.js, the UV data comes with it. You do not have to set it manually.

If you are using a built-in shape like BoxGeometry or SphereGeometry, Three.js has already assigned sensible UV coordinates. The texture will wrap around the shape automatically. You only need to worry about UV mapping if you are building custom geometry by hand, which is rare in browser games.

Choosing the right image format and size

PNG and JPG are both fine. PNG is lossless and supports transparency (useful for things like leaves or fabric). JPG is smaller on disk but loses detail, which is usually not noticeable for textures. Use PNG if the texture has sharp edges or needs to be see-through. Use JPG for photos and surfaces where compression artifacts do not matter.

Size matters for performance. A 4096×4096 texture looks great but takes up memory and slows down the browser. A 1024×1024 texture is usually enough for objects that fill a decent part of the screen. For distant objects or background elements, 512×512 or even 256×256 is fine. Start with 1024×1024 and go smaller if the game feels slow.

Keep your image files in a folder next to your HTML file, or in a subfolder like /textures. Use relative paths in your code: loader.load('textures/brick.png') instead of absolute paths. Relative paths work the same way whether you are testing locally or the game is live on a server.

Using Babylon.js instead of Three.js

Babylon.js works the same way but with different syntax. You create a StandardMaterial, set its diffuse texture using new BABYLON.Texture(), and assign it to your mesh. The texture loads in the background, and Babylon.js handles the waiting automatically.

Babylon.js also includes a AssetsManager that lets you load multiple textures at once and run a function when all of them are ready. This is useful if your game has many textured objects. Three.js does not have a built-in assets manager, so you have to track loading yourself or use a third-party library.

Both libraries do the same job. Three.js is more widely used and has more tutorials online. Babylon.js has better documentation and slightly easier syntax for beginners. Pick whichever one you find clearer.

Normal maps and other texture types

A normal map is a second image that adds fake surface detail without adding geometry. It makes a flat surface look bumpy or wrinkled. The image is usually blue and purple and looks strange on its own, but when the browser reads it, it changes how light bounces off the surface.

To use a normal map in Three.js, load it the same way you load a color texture, then set it on the material: material.normalMap = normalTexture. You can use a color texture and a normal map on the same object. The normal map does not replace the color texture; it adds detail on top of it.

Other texture types include roughness maps (which control how shiny the surface is) and metallic maps (which make parts of the surface reflective). These are optional. A color texture alone looks good for most game objects. Add normal maps if you want more detail without slowing down the game, and add roughness or metallic maps if you are building a realistic scene.

Troubleshooting textures that do not appear

If your texture does not show up, check these things in order. First, open the browser console (press F12, click Console) and look for error messages. If you see a 404 error, the file path is wrong. Check that the image file actually exists in that folder and the spelling matches exactly.

Second, make sure you are creating the mesh inside the load callback, not before it. If the mesh is created before the texture loads, it will have no texture attached. Move your mesh creation code inside the function that runs when the texture is ready.

Third, check that the image file is actually an image. If you accidentally point to a text file or a file with no extension, the loader will fail silently. Make sure the file ends in .png or .jpg and opens in an image viewer.

Fourth, if the texture appears but looks stretched or wrong, the UV coordinates on your model are probably incorrect. If you built the model yourself, re-export it from your 3D tool and make sure the UV map is unwrapped. If you are using a built-in shape, try a different shape to see if the problem is the geometry or the texture.

Frequently Asked Questions

Can I use a texture from the internet in my game?

Technically yes, but you should not. If you link to an image on another website, that site might move or delete it, breaking your game. More importantly, you might be violating copyright. read the image and save it in your own project folder, and make sure you have permission to use it. Free texture sites like Poly Haven and Textures.com have images you can use legally.

Why does my texture look blurry or pixelated?

Blurry usually means the image is too small for how close the camera is. Use a larger image file (2048×2048 instead of 512×512). Pixelated usually means the image is too large and stretched across the shape. Use a smaller image or adjust the UV coordinates so the texture does not stretch as far. You can also change the texture filter in Three.js to control how the browser samples the image.

Do I need to optimize textures for mobile phones?

Yes. Mobile browsers have less memory and slower graphics cards. Use smaller images (512×512 or 256×256) and compress them as much as possible. Test your game on an actual phone, not just the browser's mobile emulator. If it feels slow, reduce texture sizes first before you try other optimizations.

Can I animate a texture, like make it scroll or change over time?

Yes. You can change the texture's offset or scale every frame using material.map.offset or material.map.scale. You can also swap textures entirely by setting material.map to a different texture. This is useful for things like flowing water or flickering fire, but it costs performance because the browser has to update the material every frame.

What is the difference between a texture and a sprite?

A sprite is a 2D image drawn flat on the screen, usually for 2D games. A texture is a 2D image wrapped around a 3D shape. If you are building a 3D game with Three.js or Babylon.js, you are using textures. If you are building a 2D game with Canvas or Phaser, you are using sprites.