Skip to content

feat: implement 3D trophy achievements system and duel support#82

Open
Manaswin05 wants to merge 2 commits into
Younesfdj:masterfrom
Manaswin05:feat/3d-trophies-system
Open

feat: implement 3D trophy achievements system and duel support#82
Manaswin05 wants to merge 2 commits into
Younesfdj:masterfrom
Manaswin05:feat/3d-trophies-system

Conversation

@Manaswin05

Copy link
Copy Markdown

📝 Overview

Implements a dynamic, interactive 3D Trophy Achievements System for GitFut. Developers earn premium 3D trophies based on their GitHub stats, rendered in real-time WebGL using React Three Fiber. Full integration across individual profiles and VS/Duel matchups.


🚀 Key Features

🏆 Achievements & Awards

  • World Cup Trophy: Overall ≥ 85 (Generational Champion)
  • Golden Boot: SHO ≥ 80 (Elite Star Attraction)
  • Golden Glove: DEF ≥ 60 (Clean Sheet Defender)

📱 Cross-View Integration

  • Profile View: Glassmorphic sidebar panel with spinning 3D trophies
  • Duel View: Matching panel above each player's card; tied stats award both players
  • Interactive Modals: Click any trophy for a context-aware detail popup
  • Custom 3D Cursor: Floating 3D football replaces the default cursor

🛠️ Bug Fixes

Issue Fix
useGLTF in global cursor froze page mount Wrapped in <Suspense fallback={null}>
Three.js scene graph stealing (vanishing trophies) Clone scenes via useMemo(() => scene.clone())
Stat key casing (SHO/DEF vs sho/def) Standardized to lowercase keys

📁 New Files

  • components/Trophy3D.tsx — Reusable 3D trophy renderer
  • components/CustomPointer.tsx — Site-wide 3D football cursor
  • public/3D-Models/*.glb — 3D model assets

📁 Modified Files

  • ResultView.tsx — Achievements sidebar + award modals
  • DuelView.tsx — Achievements header panel + tie rules + modals
  • layout.tsx — CustomPointer with Suspense
  • Background.tsx — Gold ambient glow
  • globals.css — rise-soft animation keyframes
  • README.md — Documented Achievements system
  • package.json — Added three, @react-three/fiber, @react-three/drei

@Manaswin05

Copy link
Copy Markdown
Author

Here's the Screen recording of the website

Screen.Recording.2026-07-18.203407.mp4

Hope you like this😊

@Younesfdj

Copy link
Copy Markdown
Owner

@Manaswin05 This is so awesome man, really nice work
We will work on this more and merge it ASAP

@Manaswin05

Manaswin05 commented Jul 18, 2026

Copy link
Copy Markdown
Author

Thanks for the compliment. I am interested to see more😊

@Manaswin05

Copy link
Copy Markdown
Author

@Younesfdj I have reviewed and tried to fix the merge conflicts, Hope it works now

@Younesfdj

Copy link
Copy Markdown
Owner

@Manaswin05 Hey again, the implementation had costs, I couldn't ship on a mobile-heavy site: three/fiber/drei added ~273KB gz to every page, the GLBs were 20MB (the cursor ball alone preloaded 5.4MB for every visitor), and the always-on cursor + per-trophy WebGL canvases hurt performance.

So I kept your feature and rebuilt the rendering: the models are now pre-baked into looping sprite sheets (a script renders each GLB's rotation once, headless), so the trophies and ball look the same but cost ~3MB of cached images and zero runtime 3D. The cursor became an opt-in toy. a ball resting in the corner; click to dribble it as your cursor, right-click to put it back. Award logic moved to a single tested module, and in duels each player now showcases the trophies they've earned rather than the duel awarding them.

It lives on #88 the landing commit is authored to you, since the concept and original build are yours. Still polishing the UI before it ships. What do you think of the direction?

@Manaswin05

Manaswin05 commented Jul 21, 2026

Copy link
Copy Markdown
Author

Here I did some study regarding this using AI here's some things i would like to share :

Approach Bundle Cost Runtime Performance Visual Quality Best For
Three.js + GLB ( Current implementation ) High Heavy on mobile Excellent 3D portfolio, games
Sprite Sheets Low Excellent Very good Production websites
Video/WebM loops Very low CPU Excellent Good Hero animations
Lottie Tiny Excellent Vector only Icons/UI animations
CSS + SVG Tiny Excellent Limited UI effects
Model Viewer () Medium Better than Three.js Excellent Product showcases
Progressive Enhancement Variable Excellent Best balance Mixed desktop/mobile

1. Progressive Enhancement (Probably my favorite)

Instead of loading Three.js for everyone,

  • Desktop users with good GPUs get the real GLB.
  • Mobile users automatically get sprites.
  • Slow networks get sprites.
  • Users with reduced motion get static images.

Something like

if (
  window.innerWidth > 1024 &&
  navigator.hardwareConcurrency >= 8 &&
  !matchMedia("(prefers-reduced-motion: reduce)").matches
) {
   loadThreeScene();
} else {
   loadSprite();
}

This gives the best experience without punishing everyone.


2. Lazy Load Everything

One of the biggest issues mentioned was

the cursor ball preloaded 5.4MB for every visitor

That can be avoided.

Instead of

import CursorBall from "./CursorBall";

use

const CursorBall = React.lazy(() => import("./CursorBall"));

or dynamically import the GLB only after the user enables it.

Even better:

Click football
↓

load GLB

initialize Three.js

Now 99% of visitors never download it.


3. One Shared WebGL Canvas

The maintainer also mentioned

per-trophy WebGL canvases

If every trophy creates

Canvas
Renderer
Scene
Camera
Lights
Animation loop

that's expensive.

Instead

One Canvas

render whichever trophy is visible

or

One renderer
↓

multiple scenes

This dramatically reduces memory.


4. Compress GLBs

20MB is huge.

Most GLBs can become

20MB

3MB

1MB

using

  • Draco compression
  • Meshopt compression
  • KTX2 textures

Example

gltf-transform optimize

or

gltfpack

Many production sites do this.


5. Don't Preload

Instead of

preload all trophies

load

Bronze trophy appears

download Bronze

Silver appears

download Silver

using

IntersectionObserver

Users may only ever download one or two trophies.


6. Instancing

If several trophies share geometry,

Three.js supports

InstancedMesh

which renders many copies in one draw call.

Much faster than multiple meshes.


7. Render Only When Needed

Many Three.js apps render

60 FPS forever

Instead

render once

stop

user interacts

render

stop

This saves a lot of battery.


8. <model-viewer>

Google's <model-viewer> component can display GLBs with

  • orbit controls
  • shadows
  • environment maps
  • lazy loading
  • mobile optimizations

without writing a full Three.js scene.

It's still heavier than sprites but lighter than a custom Three.js implementation.


9. The Sprite Sheet Solution

Honestly, this is probably the right production choice.

Why maintainers like it:

  • zero JavaScript rendering
  • zero GPU cost
  • browser caches images well
  • works everywhere
  • no WebGL compatibility issues
  • predictable performance

This is why many AAA game websites and product marketing sites use pre-rendered sequences instead of real-time 3D.

A good response isn't "keep Three.js" or "sprites are the only answer." Instead, acknowledge the constraints and discuss the alternatives.

Here's how I'd break it down.

Approach | Bundle Cost | Runtime Performance | Visual Quality | Best For -- | -- | -- | -- | -- Three.js + GLB (your implementation) | High | Heavy on mobile | Excellent | 3D portfolio, games Sprite Sheets | Low | Excellent | Very good | Production websites Video/WebM loops | Very low CPU | Excellent | Good | Hero animations Lottie | Tiny | Excellent | Vector only | Icons/UI animations CSS + SVG | Tiny | Excellent | Limited | UI effects Model Viewer () | Medium | Better than Three.js | Excellent | Product showcases Progressive Enhancement | Variable | Excellent | Best balance | Mixed desktop/mobile

1. Progressive Enhancement (Probably my favorite)

Instead of loading Three.js for everyone,

  • Desktop users with good GPUs get the real GLB.
  • Mobile users automatically get sprites.
  • Slow networks get sprites.
  • Users with reduced motion get static images.

Something like

if (
  window.innerWidth > 1024 &&
  navigator.hardwareConcurrency >= 8 &&
  !matchMedia("(prefers-reduced-motion: reduce)").matches
) {
   loadThreeScene();
} else {
   loadSprite();
}

This gives the best experience without punishing everyone.


2. Lazy Load Everything

One of the biggest issues mentioned was

the cursor ball preloaded 5.4MB for every visitor

That can be avoided.

Instead of

import CursorBall from "./CursorBall";

use

const CursorBall = React.lazy(() => import("./CursorBall"));

or dynamically import the GLB only after the user enables it.

Even better:

Click football
↓

load GLB

initialize Three.js

Now 99% of visitors never download it.


3. One Shared WebGL Canvas

The maintainer also mentioned

per-trophy WebGL canvases

If every trophy creates

Canvas
Renderer
Scene
Camera
Lights
Animation loop

that's expensive.

Instead

One Canvas

render whichever trophy is visible

or

One renderer
↓

multiple scenes

This dramatically reduces memory.


4. Compress GLBs

20MB is huge.

Most GLBs can become

20MB

3MB

1MB

using

  • Draco compression
  • Meshopt compression
  • KTX2 textures

Example

gltf-transform optimize

or

gltfpack

Many production sites do this.


5. Don't Preload

Instead of

preload all trophies

load

Bronze trophy appears

download Bronze

Silver appears

download Silver

using

IntersectionObserver

Users may only ever download one or two trophies.


6. Instancing

If several trophies share geometry,

Three.js supports

InstancedMesh

which renders many copies in one draw call.

Much faster than multiple meshes.


7. Render Only When Needed

Many Three.js apps render

60 FPS forever

Instead

render once

stop

user interacts

render

stop

This saves a lot of battery.


8. <model-viewer>

Google's <model-viewer> component can display GLBs with

  • orbit controls
  • shadows
  • environment maps
  • lazy loading
  • mobile optimizations

without writing a full Three.js scene.

It's still heavier than sprites but lighter than a custom Three.js implementation.


9. The Sprite Sheet Solution

Honestly, this is probably the right production choice.

Why maintainers like it:

  • zero JavaScript rendering
  • zero GPU cost
  • browser caches images well
  • works everywhere
  • no WebGL compatibility issues
  • predictable performance

This is why many AAA game websites and product marketing sites use pre-rendered sequences instead of real-time 3D.

@Younesfdj

Copy link
Copy Markdown
Owner

@Manaswin05 Really appreciate the breakdown. The sprites are the pre-rendered output of the models, so visual quality is identical at the sizes we display (100–140px).
Right now the trophies are display-only, so desktop users would pay the bundle + model cost for no visible difference, and we'd maintain two pipelines that have to match. If we later add "grab the trophy and spin it" in the details modal, your approach is exactly how I'd build it: sprites as the floor for everyone, real GLB as the upgrade where it earns its cost.

Keeping it sprites-only for this release. Genuinely glad to have you reviewing the PR, and you're more than welcome to jump in on it, or grab anything else that interests you: the trophy system has a real roadmap ahead (repeat trophies, new award types), and I'd be happy to have you build on what you started.

PR #88 is where we will work from now on, it stays as a draft until its ready.

@Manaswin05

Copy link
Copy Markdown
Author

@Younesfdj I got it clearly, just need a clarity of what am I supposed to do there. I am ready to implement it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants