Three.js From Zero · Article s15-07

Contributing to Three.js Core

Contributing to Three.js Core is Article s15-07 of Three.js From Zero, a MasterAllArts free interactive lesson for artists learning creative 3D on the web.

← Three.js From ZeroS15-07 · Portfolio & Career

Season 15 · Article 07 · Portfolio & Career

A merged PR to mrdoob/three.js is the single most valuable line on a Three.js dev's resume. Three.js is a huge codebase but the contribution path is well-trodden. Find a good-first-issue, ship the PR, learn the maintainer dynamics.

Why this matters

One merged Three.js PR communicates more than 50 portfolio pieces. It says:

  • You can read large codebases.
  • You can write code that matches an existing style.
  • You can take feedback without ego.
  • You understand the library at the source level.

Recruiters look for this. So do other open-source maintainers, who may invite you to their projects.

The contribution path

  1. Clone — fork mrdoob/three.js, clone your fork.
  2. Browse open issues labeled "Good first issue" or "Help wanted."
  3. Pick one that matches your skill. Doc fix is the easiest entry; bug fix in a loader is medium; new feature is hard.
  4. Read the contributing guideCONTRIBUTING.md in the repo. Style rules, PR format.
  5. Write the fix. Don't change unrelated code. Keep diffs minimal.
  6. Add a test or example. Three.js has many examples — yours can be a new one.
  7. Open the PR. Reference the issue. Describe the change. Be patient.

Good entry points

  • Documentation fixes — typos, broken links, outdated examples. Search the issues tracker for "docs" label.
  • Example improvements — broken examples, missing types in TypeScript definitions.
  • Loaders — small bugs in glTF, FBX, OBJ loaders are common. The loaders are well-tested but edge cases sneak through.
  • Math utilities — Vector3, Matrix4, Quaternion. Well-isolated, easy to test.

What to avoid as a first contribution

  • Renderer internals — touches everything. PRs here get scrutinized hard.
  • Architectural changes — "let me refactor this whole module" never gets merged from a new contributor.
  • New features without an issue. Always file an issue first, get maintainer agreement, then PR.

The PR description

## Description

Fixes #12345 — Particles in CocoonRenderTarget appear sized incorrectly
when DPR > 1.

## Cause

The render target wasn't multiplying its dimensions by pixelRatio,
which is what RenderPass.render expects.

## Fix

Apply renderer.getPixelRatio() to the target's width/height in the
constructor.

## Tests

Manually tested at DPR 1, 1.5, 2, 3 using examples/webgl_postprocessing.html.
Visual comparison screenshots attached.

Three sections: what, why, how-tested. Maintainers read 50 PRs a week. Make yours scan-able.

Code style

Three.js has unwritten rules. Match them by reading nearby code:

  • Tabs for indentation (yes, really).
  • Spaces inside parens: if ( x > 0 )
  • Methods on the prototype/class, no arrow functions for methods.
  • ES6 modules, JSDoc types for public API.
  • No semi-colons in some files, semi-colons in others — match the file you're editing.

The waiting game

Average time-to-merge for a "Good first issue" PR: 2-7 days. For a non-trivial change: 2-8 weeks. The maintainers (mrdoob and a small team) are volunteers; review is best-effort.

Don't ping. Don't open a second PR until your first is closed. Don't take silence personally — they're busy. Re-tagging is fine after 2 weeks.

If your PR is rejected

It happens. Common reasons:

  • Out of scope — your feature belongs in three-stdlib or as an example, not core.
  • Style mismatch — easy to fix, push another commit.
  • Breaks something else — you can fix it, or accept the rejection and move on.
  • Maintainer disagrees — sometimes mrdoob has a different vision. Listen, don't argue. Move to a different issue.

Common first-time pitfalls

"PR is too big." Split into 2-3 smaller PRs. One per change. Each independently mergeable.
"Force-pushed after maintainer review." Always add commits instead. Force-push loses the review history.
"Renamed the variable from foo to fooBar because it's better." Out of scope. Don't bundle in cleanup. Submit a separate PR if it really matters.

Exercises

  1. Browse issues for an hour. Don't write any code. Just understand the issue tracker — what gets accepted, what gets closed.
  2. Find 3 candidates. Three issues you could realistically tackle this month. Bookmark them.
  3. Open your first PR. Pick the smallest. Ship it. The first one is the hardest; everything after is muscle memory.