Go to content

SPECIAL PROJECTS - LEEFORDS_V1

Skip menu
Title
Skip menu
Test Configurator
LEEFORDSleefords.it

LEEFORDS Soccer Kit Configurator V8 · leefords.it

Design your bespoke football kit in 2D, add player details and your club/sponsor logo, then send the specification to LEEFORDS.

Jersey

Shorts

Socks

Choosing a lower or upper colour switches from a preset to independent sock layers.

Personalisation

Your logo stays in your browser; it is not uploaded anywhere by this configurator.

Your enquiry

Order hand-off

Use “Copy Specification” to copy the design details, “Email LEEFORDS” to open a ready-addressed enquiry, or “Order & Contacts” to continue on leefords.it.
import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js"; /* ========================================= MODEL LOCATION ========================================= */ const MODEL_URL = "./assets/avatar/M_Avatar.glb"; /* ========================================= HTML ========================================= */ const canvas = document.getElementById("viewer"); const status = document.getElementById("status"); /* ========================================= SCENE ========================================= */ const scene = new THREE.Scene(); scene.background = new THREE.Color(0xeeeeee); /* ========================================= CAMERA ========================================= */ const camera = new THREE.PerspectiveCamera( 35, window.innerWidth / window.innerHeight, 0.001, 100000 ); /* ========================================= RENDERER ========================================= */ const renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true }); renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2 ) ); renderer.setSize( window.innerWidth, window.innerHeight ); renderer.outputColorSpace = THREE.SRGBColorSpace; renderer.toneMapping = THREE.ACESFilmicToneMapping; renderer.toneMappingExposure = 1.2; /* ========================================= LIGHTS ========================================= */ const ambient = new THREE.HemisphereLight( 0xffffff, 0x555555, 3 ); scene.add(ambient); const frontLight = new THREE.DirectionalLight( 0xffffff, 4 ); frontLight.position.set( 3, 5, 5 ); scene.add(frontLight); const sideLight = new THREE.DirectionalLight( 0xffffff, 2 ); sideLight.position.set( -4, 3, 2 ); scene.add(sideLight); /* ========================================= CONTROLS ========================================= */ const controls = new OrbitControls( camera, renderer.domElement ); controls.enableDamping = true; controls.dampingFactor = 0.06; controls.enablePan = false; /* ========================================= LOAD CLO3D GLB ========================================= */ const loader = new GLTFLoader(); loader.load( MODEL_URL, /* SUCCESS */ function (gltf) { console.log( "CLO3D model loaded:", gltf ); const model = gltf.scene; scene.add(model); /* ----------------------------- Calculate REAL CLO dimensions ----------------------------- */ model.updateMatrixWorld(true); const box = new THREE.Box3() .setFromObject(model); const center = box.getCenter( new THREE.Vector3() ); const size = box.getSize( new THREE.Vector3() ); console.log( "CLO model center:", center ); console.log( "CLO model size:", size ); /* ----------------------------- Automatically position camera ----------------------------- */ const maxDimension = Math.max( size.x, size.y, size.z ); const fov = THREE.MathUtils.degToRad( camera.fov ); let distance = maxDimension / ( 2 * Math.tan( fov / 2 ) ); distance *= 1.35; camera.position.set( center.x, center.y, center.z + distance ); camera.near = Math.max( distance / 1000, 0.001 ); camera.far = Math.max( distance * 100, 1000 ); camera.updateProjectionMatrix(); controls.target.copy( center ); controls.update(); status.textContent = "3D model loaded"; /* Hide message after two seconds. */ setTimeout( () => { status.style.display = "none"; }, 2000 ); }, /* PROGRESS */ function (event) { if ( event.total && event.total > 0 ) { const percent = Math.round( event.loaded / event.total * 100 ); status.textContent = "Loading 3D model: " + percent + "%"; } }, /* ERROR */ function (error) { console.error( "GLB LOAD ERROR:", error ); console.error( "Attempted URL:", MODEL_URL ); status.textContent = "ERROR: 3D model could not be loaded."; status.style.background = "#b00020"; } ); /* ========================================= RESIZE ========================================= */ window.addEventListener( "resize", function () { camera.aspect = window.innerWidth / window.innerHeight; camera.updateProjectionMatrix(); renderer.setSize( window.innerWidth, window.innerHeight ); } ); /* ========================================= RENDER ========================================= */ function animate() { requestAnimationFrame( animate ); controls.update(); renderer.render( scene, camera ); } animate();/* ============================================================= LEEFORDS 3D CONFIGURATOR ASSET LOCATION CONFIGURATION ============================================================= */ /* ------------------------------------------------------------- 1. WEBSITE ROOT ------------------------------------------------------------- This is the public address of the website. Do NOT put index.html on the end. */ const WEBSITE_ROOT = "https://leefords.it"; /* ------------------------------------------------------------- 2. MASTER ASSET DIRECTORY ------------------------------------------------------------- ALL configurator assets will be loaded from: https://leefords.it/assets/ This includes: - CLO3D avatar - CLO3D garments - garment colorways - thumbnail images */ const ASSET_ROOT = WEBSITE_ROOT + "/assets"; /* ------------------------------------------------------------- 3. ASSET SUBDIRECTORIES ------------------------------------------------------------- */ const AVATAR_ROOT = ASSET_ROOT + "/avatar"; const GARMENT_ROOT = ASSET_ROOT + "/garments"; const THUMB_ROOT = ASSET_ROOT + "/thumbs"; /* ============================================================= 4. COMPLETE PRODUCT CATALOGUE ============================================================= */ const catalogue = { /* --------------------------------------------------------- AVATAR --------------------------------------------------------- */ avatar: { id: "male-avatar", name: "Male Avatar", /* CLO3D GLB */ model: AVATAR_ROOT + "/M_Avatar.glb", /* Avatar thumbnail */ thumb: THUMB_ROOT + "/Thumb_M Avatar_Black.png" }, /* --------------------------------------------------------- GARMENTS --------------------------------------------------------- */ garments: [ /* ===================================================== VARSITY JACKET ===================================================== */ { id: "varsity-jacket", name: "Varsity Jacket", slot: "upper", /* Main garment thumbnail */ thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Black.png", variants: [ /* BLACK */ { id: "black", name: "Black", model: GARMENT_ROOT + "/varsity-jacket/" + "Varsity Jacket_Black.glb", thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Black.png" }, /* BLUE / COLORWAY 1 */ { id: "blue", name: "Blue", model: GARMENT_ROOT + "/varsity-jacket/" + "Varsity Jacket_Colorway 1.glb", thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Colorway 1.png" }, /* NAVY */ { id: "navy", name: "Navy", model: GARMENT_ROOT + "/varsity-jacket/" + "Varsity Jacket_Navy.glb", thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Navy.png" }, /* RED */ { id: "red", name: "Red", model: GARMENT_ROOT + "/varsity-jacket/" + "Varsity Jacket_Red.glb", thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Red.png" }, /* YELLOW */ { id: "yellow", name: "Yellow", model: GARMENT_ROOT + "/varsity-jacket/" + "Varsity Jacket_Yellow.glb", thumb: THUMB_ROOT + "/Thumb_Varsity Jacket_Yellow.png" } ] }, /* ===================================================== SNAP PANTS ===================================================== */ { id: "snap-pants", name: "Snap Pants", slot: "lower", /* Main garment thumbnail */ thumb: THUMB_ROOT + "/Thumb_Snap Pant_Black.png", variants: [ /* BLACK */ { id: "black", name: "Black", model: GARMENT_ROOT + "/snap-pants/" + "Snap Pants_Black.glb", thumb: THUMB_ROOT + "/Thumb_Snap Pant_Black.png" }, /* BLUE / COLORWAY 1 */ { id: "blue", name: "Blue", model: GARMENT_ROOT + "/snap-pants/" + "Snap Pants_Colorway 1.glb", thumb: THUMB_ROOT + "/Thumb_Snap Pant_Colorway 1.png" }, /* NAVY */ { id: "navy", name: "Navy", model: GARMENT_ROOT + "/snap-pants/" + "Snap Pants_Navy.glb", thumb: THUMB_ROOT + "/Thumb_Snap Pant_Navy.png" }, /* RED */ { id: "red", name: "Red", model: GARMENT_ROOT + "/snap-pants/" + "Snap Pants_Red.glb", thumb: THUMB_ROOT + "/Thumb_Snap Pant_Red.png" }, /* YELLOW */ { id: "yellow", name: "Yellow", model: GARMENT_ROOT + "/snap-pants/" + "Snap Pants_Yellow.glb", thumb: THUMB_ROOT + "/Thumb_Snap Pant_Yellow.png" } ] } ] };
REVISITING CLASSICS
Personal Protection Equipment
Inspired by Sportswear
America's Cup
Performance Wear Concepts.
ADIDAS MEN'S ATLANTA TRACKSUIT
ADIDAS MEN'S SITOR TRACKSUIT
ATLANTA 1996 Olympics Onepiece Suit_V2
MENS & WOMENS NORTON MOTORBIKE GEAR
NEO CLASSIC TRACKSUITS WITH HIGH VIS BANDS
COLOUR-BLOCK TRACKSUITS WITH HIGH VIS BANDS
2026 Winter Olympics BOBSLEIGH SUIT Proposal
Please leave the relevant information so we can contact you
Via Santa Maria, 41
Dolianova,
Sud Sardegna 09041
ITALIA.
+39 3273727605
leeford.grant@gmail.com
Back to content