Real-Time 3D Cyclist Characters Creation
Budget / Salary$30–250
TypeFreelance project
LocationRemote
Posted2 hours ago
# 3D Cyclist Characters + Road Bike — Technical Brief
My budget is 60 USD; I'll only place a bid within that amount.
**Project:** real-time indoor-cycling race screen (WebGL2, Android TV box)
**Deliverables:** 4 rigged cyclist characters + 1 road bike, with LODs
---
## 0. Read this first — where these models will run
These are **not** for rendering stills. They run in a live WebGL2 scene on a low-power
Android TV box (PowerVR B-Series BXM-4-64 GPU) at 1920×1080, with **up to 20 cyclists
on screen at once**, at 30 fps.
We have measured this hardware. The numbers below are not guesses:
| what is on screen | triangles/frame | measured fps |
|---|---|---|
| 20 riders @ 113,065 tri each | 2,261,300 | **4.0** |
| 20 riders @ 36,269 tri each | 725,380 | **20.8** |
| 20 riders @ 8,173 tri each | 163,460 | **33.8** |
| empty scene (ceiling) | 0 | 43.0 |
That table is why the polygon budgets in §4 are what they are. A beautiful 200k-triangle
character is unusable here — please do not send one and expect us to decimate it; the
decimation is what the LODs in §4 are for, and **you will do it better than an automatic
tool because you know which silhouette matters.**
---
## 1. Characters required
Four separate characters:
| # | who | notes |
|---|---|---|
| 1 | Male cyclist A | base male |
| 2 | Male cyclist B | **same body, same kit, same rig as #1 — different face and hair only** |
| 3 | Female cyclist A | base female |
| 4 | Female cyclist B | **same body, same kit, same rig as #3 — different face and hair only** |
"Different face" means the two men must be recognisably different people when seen from
2–4 metres in a three-quarter front view. Different facial structure, skin tone, and hair
(a beard on one of them is welcome). Body proportions, clothing geometry and skeleton must
be **identical** between A and B so they stay interchangeable.
Where the difference can be achieved **in the texture rather than in the geometry, prefer
the texture** — it costs us nothing at runtime.
---
## 2. File format
**Primary deliverable: `.glb` (glTF 2.0 binary), one file per model.** This is what the
application loads directly. Please do not substitute another format.
- Textures **embedded inside the .glb**, and also supplied separately as `.png`.
- Also include the editable source (`.blend`, `.max`, `.ma` or `.c4d`) and an `.fbx`, for
future edits. These are archive copies; the `.glb` is the one that ships.
- Please verify each `.glb` opens correctly in a neutral viewer
(https://gltf-viewer.donmccurdy.com) **before delivery**, with the skeleton visible.
---
## 3. Scale, orientation, origin
- **Units: metres, real-world scale.** Male ≈ 1.78 m standing, female ≈ 1.68 m.
Road bike wheel: 700c, **0.67 m outside diameter**.
- **Y up. Character and bike both face +Z.**
- **Origin at (0, 0, 0) on the ground plane**, under the bike's centre — not at the hips,
not at the mesh centre. Lowest vertex of the tyre sits at exactly y = 0.
- No transforms baked into parent nodes: the mesh must be correct with an identity
transform on the root.
---
## 4. Polygon budget and LODs
**Every model must be delivered at three levels of detail**, as three separate `.glb`
files. This is the single most important requirement in this brief.
### Cyclist (body + clothing + helmet + shoes, **excluding** the bike)
| level | file suffix | max triangles | seen at |
|---|---|---|---|
| LOD0 | `_lod0.glb` | **30,000** | close-up camera, one rider fills the screen |
| LOD1 | `_lod1.glb` | **8,000** | the 6 riders nearest the camera |
| LOD2 | `_lod2.glb` | **2,500** | the rest of the pack, 20–40 m away |
### Road bike (separate files — see §6)
| level | file suffix | max triangles |
|---|---|---|
| LOD0 | `_lod0.glb` | **20,000** |
| LOD1 | `_lod1.glb` | **5,000** |
| LOD2 | `_lod2.glb` | **1,500** |
Rules for the LODs:
- **All three levels must keep the same skeleton, the same bone names, and the same
material names.** Only the mesh density changes. If LOD2 has a different rig, it is
unusable.
- LOD2 will be seen at 20–40 m, roughly 60 px tall. Silhouette is everything; surface
detail is invisible. Spend the 2,500 triangles on the outline, the helmet shape and the
legs, not on the face.
- **Do not delete the wheels or thin frame tubes in LOD2 to save budget.** A missing wheel
reads instantly; a chunky one does not.
---
## 5. Rigging — requirements, not preferences
The application drives the legs **live, from the student's real pedalling cadence**. The
model is never played back as a canned animation. So the rig must be usable by code.
**Required:**
- A standard humanoid skeleton, **exported inside the `.glb` with skinning data**
(glTF `skin`, `JOINTS_0`, `WEIGHTS_0`, `inverseBindMatrices`).
A `.glb` whose skeleton exists only in the source file is a failed delivery.
- **Maximum 4 bone influences per vertex** (glTF standard limit).
- **Maximum 64 bones** in the skeleton. Fingers may be a single bone per hand or omitted.
- These bones must exist, with a clean parent chain, on **both legs**:
`hips → thigh → shin → foot`
and on both arms: `chest → shoulder → upperarm → forearm → hand`,
plus `spine`, `chest`, `neck`, `head`.
- **Delivered in the riding pose**, seated on the bike, hands on the hoods, foot on the
pedal — not in a T-pose. The bind pose may be a T-pose; the default node transforms
should place the character on the bike.
- Weights around the **hip and knee** must be clean: the thigh will be rotated through a
full pedal revolution (about 75° of travel) and must not tear or collapse the shorts.
**Not required:** animation clips. If you include a pedalling cycle it is welcome as a
reference, but the application will not play it.
---
## 6. The bike — wheels must be separate, named nodes
**This is worth reading carefully; it is the item that has cost us the most time.**
The bike must be a **separate `.glb`** from the cyclist (we mix riders and bikes and
recolour them independently).
Inside the bike file, the following must be **separate nodes with these exact names**:
| node name | contents | pivot / origin must be |
|---|---|---|
| `roda_dianteira` | front wheel: rim, tyre, spokes, hub, disc | **exactly at the front axle** |
| `roda_traseira` | rear wheel: rim, tyre, spokes, hub, cassette, disc | **exactly at the rear axle** |
| `pedivela` | crank arms, chainring, pedals | **exactly at the bottom-bracket axis** |
| `quadro` | everything else: frame, fork, bars, saddle, seatpost | origin at (0,0,0) |
The wheels are rotated in code every frame. If a wheel's pivot is not at its axle it will
wobble; if frame geometry is inside the wheel node it will be swept around with it and the
bicycle will visibly tear apart. **Nothing that stays still may live inside a wheel node,
and no part of the wheel may live outside it.**
Please also state, in the delivery notes, the **exact wheel radius in metres** and the
**bottom-bracket height and Z position**.
---
## 7. Materials and textures
- **PBR metallic-roughness** (the glTF standard). No Vray / Arnold / Redshift-only setups —
those do not survive the export.
- Texture resolution: **2048×2048 maximum for LOD0**, 1024 for LOD1, 512 for LOD2.
Power-of-two, no overlapping UVs.
### Separate materials required list
The application recolours parts independently, so these must be **distinct materials with
these names**, not merged into one atlas:
`camisa` (jersey) · `bermuda` (shorts) · `capacete` (helmet) · `pele` (skin) ·
`sapato` (shoes) · `cabelo` (hair) · `oculos` (glasses)
and for the bike: `quadro_pintura` (painted frame) · `roda` (rims/tyres) ·
`metal` (chain, cassette, cranks) · `selim` (saddle) · `guidao` (bars/tape).
### Colour: deliver the recolourable parts NEUTRAL
**`camisa`, `bermuda`, `capacete` and `quadro_pintura` must be authored in neutral white
or light grey**, with all the shading, seams, wrinkles, logos and panel lines present but
**no strong hue**.
The application multiplies a per-student colour over these materials at runtime. Starting
from neutral, any colour comes out correctly. Starting from a saturated purple, we can only
shift the hue — purple to blue works, purple to white or yellow does not. Neutral base
textures are what make "any colour, any student" actually possible.
Skin, hair, shoes and metal should be authored in their final colours as normal.
### Branding
No real manufacturer names or logos anywhere on the bike or kit. Invented brand marks are
welcome and add realism.
---
## 8. What must NOT be in the delivered files
We have received models with these problems before; each one costs a round trip.
- ❌ Studio backdrop, ground plane, or any environment geometry.
- ❌ Cameras or lights.
- ❌ N-gons — **triangulate before export**.
- ❌ Overlapping or unwrapped UVs.
- ❌ Loose/orphan vertices, or hundreds of tiny disconnected shells (screws, cable ends,
chain links as separate closed objects). These make automatic simplification impossible.
- ❌ Non-uniform or negative scale on any node.
- ❌ Attribute arrays of mismatched length (`TEXCOORD_0` count must equal `POSITION` count).
## 9. Acceptance checklist
Delivery is accepted:
1. It opens in https://gltf-viewer.donmccurdy.com with no errors or warnings.
2. Triangle count is at or under the budget in §4.
3. The skeleton is present **in the `.glb`** and the leg bones rotate cleanly.
4. LOD0, LOD1 and LOD2 share identical bone names and material names.
5. The bike's `roda_dianteira` and `roda_traseira` rotate about their own axles with no
frame geometry moving and no wheel geometry left behind.
6. `camisa`, `bermuda`, `capacete`, `quadro_pintura` are neutral and take a multiplied
colour correctly.
7. Scale is metric: character height and wheel diameter measure as specified in §3.
8. The two male characters (and the two female) are visibly different people, and their
skeletons and clothing geometry are interchangeable.
---
My budget is 60 USD; I'll only place a bid within that amount.
**Project:** real-time indoor-cycling race screen (WebGL2, Android TV box)
**Deliverables:** 4 rigged cyclist characters + 1 road bike, with LODs
---
## 0. Read this first — where these models will run
These are **not** for rendering stills. They run in a live WebGL2 scene on a low-power
Android TV box (PowerVR B-Series BXM-4-64 GPU) at 1920×1080, with **up to 20 cyclists
on screen at once**, at 30 fps.
We have measured this hardware. The numbers below are not guesses:
| what is on screen | triangles/frame | measured fps |
|---|---|---|
| 20 riders @ 113,065 tri each | 2,261,300 | **4.0** |
| 20 riders @ 36,269 tri each | 725,380 | **20.8** |
| 20 riders @ 8,173 tri each | 163,460 | **33.8** |
| empty scene (ceiling) | 0 | 43.0 |
That table is why the polygon budgets in §4 are what they are. A beautiful 200k-triangle
character is unusable here — please do not send one and expect us to decimate it; the
decimation is what the LODs in §4 are for, and **you will do it better than an automatic
tool because you know which silhouette matters.**
---
## 1. Characters required
Four separate characters:
| # | who | notes |
|---|---|---|
| 1 | Male cyclist A | base male |
| 2 | Male cyclist B | **same body, same kit, same rig as #1 — different face and hair only** |
| 3 | Female cyclist A | base female |
| 4 | Female cyclist B | **same body, same kit, same rig as #3 — different face and hair only** |
"Different face" means the two men must be recognisably different people when seen from
2–4 metres in a three-quarter front view. Different facial structure, skin tone, and hair
(a beard on one of them is welcome). Body proportions, clothing geometry and skeleton must
be **identical** between A and B so they stay interchangeable.
Where the difference can be achieved **in the texture rather than in the geometry, prefer
the texture** — it costs us nothing at runtime.
---
## 2. File format
**Primary deliverable: `.glb` (glTF 2.0 binary), one file per model.** This is what the
application loads directly. Please do not substitute another format.
- Textures **embedded inside the .glb**, and also supplied separately as `.png`.
- Also include the editable source (`.blend`, `.max`, `.ma` or `.c4d`) and an `.fbx`, for
future edits. These are archive copies; the `.glb` is the one that ships.
- Please verify each `.glb` opens correctly in a neutral viewer
(https://gltf-viewer.donmccurdy.com) **before delivery**, with the skeleton visible.
---
## 3. Scale, orientation, origin
- **Units: metres, real-world scale.** Male ≈ 1.78 m standing, female ≈ 1.68 m.
Road bike wheel: 700c, **0.67 m outside diameter**.
- **Y up. Character and bike both face +Z.**
- **Origin at (0, 0, 0) on the ground plane**, under the bike's centre — not at the hips,
not at the mesh centre. Lowest vertex of the tyre sits at exactly y = 0.
- No transforms baked into parent nodes: the mesh must be correct with an identity
transform on the root.
---
## 4. Polygon budget and LODs
**Every model must be delivered at three levels of detail**, as three separate `.glb`
files. This is the single most important requirement in this brief.
### Cyclist (body + clothing + helmet + shoes, **excluding** the bike)
| level | file suffix | max triangles | seen at |
|---|---|---|---|
| LOD0 | `_lod0.glb` | **30,000** | close-up camera, one rider fills the screen |
| LOD1 | `_lod1.glb` | **8,000** | the 6 riders nearest the camera |
| LOD2 | `_lod2.glb` | **2,500** | the rest of the pack, 20–40 m away |
### Road bike (separate files — see §6)
| level | file suffix | max triangles |
|---|---|---|
| LOD0 | `_lod0.glb` | **20,000** |
| LOD1 | `_lod1.glb` | **5,000** |
| LOD2 | `_lod2.glb` | **1,500** |
Rules for the LODs:
- **All three levels must keep the same skeleton, the same bone names, and the same
material names.** Only the mesh density changes. If LOD2 has a different rig, it is
unusable.
- LOD2 will be seen at 20–40 m, roughly 60 px tall. Silhouette is everything; surface
detail is invisible. Spend the 2,500 triangles on the outline, the helmet shape and the
legs, not on the face.
- **Do not delete the wheels or thin frame tubes in LOD2 to save budget.** A missing wheel
reads instantly; a chunky one does not.
---
## 5. Rigging — requirements, not preferences
The application drives the legs **live, from the student's real pedalling cadence**. The
model is never played back as a canned animation. So the rig must be usable by code.
**Required:**
- A standard humanoid skeleton, **exported inside the `.glb` with skinning data**
(glTF `skin`, `JOINTS_0`, `WEIGHTS_0`, `inverseBindMatrices`).
A `.glb` whose skeleton exists only in the source file is a failed delivery.
- **Maximum 4 bone influences per vertex** (glTF standard limit).
- **Maximum 64 bones** in the skeleton. Fingers may be a single bone per hand or omitted.
- These bones must exist, with a clean parent chain, on **both legs**:
`hips → thigh → shin → foot`
and on both arms: `chest → shoulder → upperarm → forearm → hand`,
plus `spine`, `chest`, `neck`, `head`.
- **Delivered in the riding pose**, seated on the bike, hands on the hoods, foot on the
pedal — not in a T-pose. The bind pose may be a T-pose; the default node transforms
should place the character on the bike.
- Weights around the **hip and knee** must be clean: the thigh will be rotated through a
full pedal revolution (about 75° of travel) and must not tear or collapse the shorts.
**Not required:** animation clips. If you include a pedalling cycle it is welcome as a
reference, but the application will not play it.
---
## 6. The bike — wheels must be separate, named nodes
**This is worth reading carefully; it is the item that has cost us the most time.**
The bike must be a **separate `.glb`** from the cyclist (we mix riders and bikes and
recolour them independently).
Inside the bike file, the following must be **separate nodes with these exact names**:
| node name | contents | pivot / origin must be |
|---|---|---|
| `roda_dianteira` | front wheel: rim, tyre, spokes, hub, disc | **exactly at the front axle** |
| `roda_traseira` | rear wheel: rim, tyre, spokes, hub, cassette, disc | **exactly at the rear axle** |
| `pedivela` | crank arms, chainring, pedals | **exactly at the bottom-bracket axis** |
| `quadro` | everything else: frame, fork, bars, saddle, seatpost | origin at (0,0,0) |
The wheels are rotated in code every frame. If a wheel's pivot is not at its axle it will
wobble; if frame geometry is inside the wheel node it will be swept around with it and the
bicycle will visibly tear apart. **Nothing that stays still may live inside a wheel node,
and no part of the wheel may live outside it.**
Please also state, in the delivery notes, the **exact wheel radius in metres** and the
**bottom-bracket height and Z position**.
---
## 7. Materials and textures
- **PBR metallic-roughness** (the glTF standard). No Vray / Arnold / Redshift-only setups —
those do not survive the export.
- Texture resolution: **2048×2048 maximum for LOD0**, 1024 for LOD1, 512 for LOD2.
Power-of-two, no overlapping UVs.
### Separate materials required list
The application recolours parts independently, so these must be **distinct materials with
these names**, not merged into one atlas:
`camisa` (jersey) · `bermuda` (shorts) · `capacete` (helmet) · `pele` (skin) ·
`sapato` (shoes) · `cabelo` (hair) · `oculos` (glasses)
and for the bike: `quadro_pintura` (painted frame) · `roda` (rims/tyres) ·
`metal` (chain, cassette, cranks) · `selim` (saddle) · `guidao` (bars/tape).
### Colour: deliver the recolourable parts NEUTRAL
**`camisa`, `bermuda`, `capacete` and `quadro_pintura` must be authored in neutral white
or light grey**, with all the shading, seams, wrinkles, logos and panel lines present but
**no strong hue**.
The application multiplies a per-student colour over these materials at runtime. Starting
from neutral, any colour comes out correctly. Starting from a saturated purple, we can only
shift the hue — purple to blue works, purple to white or yellow does not. Neutral base
textures are what make "any colour, any student" actually possible.
Skin, hair, shoes and metal should be authored in their final colours as normal.
### Branding
No real manufacturer names or logos anywhere on the bike or kit. Invented brand marks are
welcome and add realism.
---
## 8. What must NOT be in the delivered files
We have received models with these problems before; each one costs a round trip.
- ❌ Studio backdrop, ground plane, or any environment geometry.
- ❌ Cameras or lights.
- ❌ N-gons — **triangulate before export**.
- ❌ Overlapping or unwrapped UVs.
- ❌ Loose/orphan vertices, or hundreds of tiny disconnected shells (screws, cable ends,
chain links as separate closed objects). These make automatic simplification impossible.
- ❌ Non-uniform or negative scale on any node.
- ❌ Attribute arrays of mismatched length (`TEXCOORD_0` count must equal `POSITION` count).
## 9. Acceptance checklist
Delivery is accepted:
1. It opens in https://gltf-viewer.donmccurdy.com with no errors or warnings.
2. Triangle count is at or under the budget in §4.
3. The skeleton is present **in the `.glb`** and the leg bones rotate cleanly.
4. LOD0, LOD1 and LOD2 share identical bone names and material names.
5. The bike's `roda_dianteira` and `roda_traseira` rotate about their own axles with no
frame geometry moving and no wheel geometry left behind.
6. `camisa`, `bermuda`, `capacete`, `quadro_pintura` are neutral and take a multiplied
colour correctly.
7. Scale is metric: character height and wheel diameter measure as specified in §3.
8. The two male characters (and the two female) are visibly different people, and their
skeletons and clothing geometry are interchangeable.
---
Apply on Freelancer →
Project sourced from Freelancer.com. Applications happen directly on the original platform — we never collect your data.