Skip to main content
All static assets live under src/assets/. This guide covers how to replace each category of asset and what else needs to change in the code when you do.
src/assets/
├── 3d/
│   └── bedroom.glb
├── fonts/
│   └── retro.ttf
├── icons/
│   ├── clock.gif
│   ├── github.png
│   ├── github.svg
│   ├── home.gif
│   ├── home2.gif
│   ├── linkedin.png
│   └── linkedin.svg
└── images/
    ├── loader.jpg
    └── loader-mobile.jpg

Replacing the 3D model

The scene is driven by a single GLTF binary file: src/assets/3d/bedroom.glb. It is loaded in src/models/Computer.jsx via useGLTF from @react-three/drei.
src/models/Computer.jsx
import computerScene from '../assets/3d/bedroom.glb';

const { nodes, materials } = useGLTF(computerScene);
The .glb file is imported as a module (not fetched by URL string). Vite hashes and bundles it into the dist/ output automatically.
1

Export a GLTF from Blender

In Blender, go to File → Export → glTF 2.0 (.glb/.gltf).Recommended export settings:
  • Format: glTF Binary (.glb) — single file, easier to manage.
  • Include: check Meshes, Materials, and Textures.
  • Compression: enable Draco mesh compression if file size is a concern (requires the three/examples/jsm/loaders/DRACOLoader setup).
  • Transform: apply any pending rotations/scales before export so the scene loads in the correct orientation.
2

Replace the file

Copy your new .glb into src/assets/3d/ and name it bedroom.glb, or update the import in Computer.jsx:
src/models/Computer.jsx
// Option A — same filename, just drop the new file in place
import computerScene from '../assets/3d/bedroom.glb';

// Option B — new filename
import computerScene from '../assets/3d/my-room.glb';

const { nodes, materials } = useGLTF(computerScene);
3

Update mesh and material references

Node and material names in the destructured nodes and materials objects are taken directly from your Blender scene. When you swap the model these names will change.In Computer.jsx the scene is built with JSX like:
src/models/Computer.jsx
<mesh
  castShadow
  receiveShadow
  geometry={nodes.Cube010_Material006_0.geometry}
  material={materials['Material.006']}
/>
To find the correct names for your new model, add a temporary console.log after the useGLTF call:
src/models/Computer.jsx
const { nodes, materials } = useGLTF(computerScene);
console.log('nodes:', Object.keys(nodes));
console.log('materials:', Object.keys(materials));
Replace each nodes.OldName and materials['OldMaterial'] reference with the names logged for your new model.
The .glb file must live under src/assets/ (not public/) so Vite processes it through the module graph. Importing it with import gives you the hashed, bundled URL that useGLTF fetches at runtime.

Swapping icons

Icons are used in two places: the 2D overlay in Home.jsx and the loader screen in Loader.jsx.
FilePurpose
clock.gifAnimated clock shown in the ChangingTimeOverlay (the 2-second black transition when switching time of day)
home.gifAnimated icon shown on the loader screen above the loading text
home2.gifAlternative home icon (not actively imported in current source)
github.png / github.svgGitHub link icon in the HUD overlay
linkedin.png / linkedin.svgLinkedIn link icon in the HUD overlay
To replace any icon, drop the new file into src/assets/icons/ using the same filename. Vite will pick it up automatically. If you need to use a different filename, update the corresponding import in Home.jsx or Loader.jsx:
// Example: renaming the GitHub icon
import githubIcon from '../assets/icons/my-github-icon.svg';
SVG files are preferred over PNG for icons because they scale without quality loss and usually have smaller file sizes. Both .png and .svg variants are included for the social icons — use whichever format you replace.

Swapping loader background images

The full-screen loading background uses responsive images imported in src/components/Loader.jsx.
FileShown whenRecommended size
loader.jpgViewport width > 768 px1920 × 1080 px (16:9), < 500 KB
loader-mobile.jpgViewport width ≤ 768 px750 × 1334 px (9:16), < 300 KB
The breakpoint is detected using a resize event listener in Loader.jsx:
src/components/Loader.jsx
const handleResize = () => {
  if (window.innerWidth <= 768) {
    setBackgroundImage(loaderMobileImage);
  } else {
    setBackgroundImage(loaderImage);
  }
};
handleResize(); // run on mount
window.addEventListener('resize', handleResize);
Drop replacement files into src/assets/images/ using the same filenames. If you prefer WebP for better compression:
src/components/Loader.jsx
import loaderImage       from '../assets/images/loader.webp';
import loaderMobileImage from '../assets/images/loader-mobile.webp';

Font replacement

The retro font is declared once in src/pages/Home.css and referenced by name throughout Home.jsx.
src/pages/Home.css
@font-face {
  font-family: 'retro';
  src: url('../assets/fonts/retro.ttf') format('truetype');
}
To use a different font:
  1. Add the new font file to src/assets/fonts/.
  2. Update the src path (and optionally the format) in the @font-face block.
  3. Keep font-family: 'retro' unchanged so that all style={{ fontFamily: 'retro' }} usages in Home.jsx continue to work — or do a global rename if you prefer a different family name.
src/pages/Home.css
/* Example: switching to a woff2 font */
@font-face {
  font-family: 'retro';
  src: url('../assets/fonts/my-font.woff2') format('woff2'),
       url('../assets/fonts/my-font.ttf')   format('truetype');
  font-display: swap;
}
Adding font-display: swap reduces flash of invisible text during font load — a worthwhile addition.

Public assets and favicons

Favicons and web-app manifest icons are stored in the public/favicon/ folder and referenced in index.html. These are served at the root URL without going through Vite’s module bundler. To regenerate favicons:
1

Create a source image

Prepare a square PNG at least 512 × 512 px with your logo or avatar.
2

Generate favicon files

Use a favicon generator such as realfavicongenerator.net or favicon.io. Download the generated package.
3

Replace the files in public/favicon/

Drop all generated files into public/favicon/, overwriting the existing ones. Common files include:
public/favicon/
├── favicon.ico
├── favicon-16x16.png
├── favicon-32x32.png
├── apple-touch-icon.png
├── android-chrome-192x192.png
├── android-chrome-512x512.png
└── site.webmanifest
4

Verify index.html link tags

Check that the <link> tags in index.html match the filenames in public/favicon/. Update any paths that differ.

Build docs developers (and LLMs) love