Overview
When I built the first version of my personal site, I wanted to add something that felt personal, not just text and links.
So I added a small tribute to a car I loved as a kid and still do: the Ferrari F40.
Idea
This was mainly a learning project.
I wanted to understand post-processing, retro-style effects, and shader-based styling, then apply all of that in a real homepage instead of keeping it as an isolated test.
What I Built
- A Three.js scene with the Ferrari F40 model.
- Custom retro/dither effect in the post-processing chain.
- Bloom and lighting tuned for a CRT-like look.
- Basic motion and camera constraints so it still feels alive but controlled.
The visual direction was inspired by Maxime Heckel's article about dithering and retro shading:
https://blog.maximeheckel.com/posts/the-art-of-dithering-and-retro-shading-web/
Technical Notes
The post-processing stack is intentionally small:
<EffectComposer>
<RetroEffect
colorNum={colorNumValue}
pixelSize={pixelSizeValue}
blending={controls.blending}
curve={controls.curve}
/>
<Bloom
intensity={0.3}
luminanceThreshold={0.05}
luminanceSmoothing={0.9}
/>
</EffectComposer>
I also wired loading progress so the scene fades in when assets are ready. Nothing fancy, but it improves how the homepage feels.
Effects and Shader Details
The retro pass is implemented as a custom postprocessing effect with uniforms exposed to tweak the look in realtime:
colorNum: controls color palette (how limited the palette looks).pixelSize: controls pixel size.blending: changes how the CRT mask is mixed with the source color.curve: applies subtle screen curvature.
Inside the shader, the final frame combines:
- Bayer dithering for controlled noise.
- RGB channel separation/mask behavior.
- Scanline modulation.
- Edge attenuation after UV distortion (to emulate screen falloff).
After that pass, bloom is applied.
<Bloom
intensity={0.3}
luminanceThreshold={0.05}
luminanceSmoothing={0.9}
/>
From a performance side, I kept the scene constrained on purpose:
- bounded camera controls and fixed framing,
- a single hero model,
- tuned DPR (
[1, 1.5]) to avoid over-rendering on high density screens, - lightweight animation (rotation and subtle vertical motion),
- no heavy multipass chain beyond retro + bloom.
The goal was to keep the style strong without turning the homepage into a heavy GPU benchmark.
Result
Technically it is pretty basic, but the final look came out better than I expected.
For a first pass, it did exactly what I wanted: learn post-processing and shaders while adding something that actually represents me.