-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathindex.html
More file actions
1204 lines (1130 loc) · 109 KB
/
index.html
File metadata and controls
1204 lines (1130 loc) · 109 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Three.js Visual & Interactive Encyclopedia - A Complete Guide</title>
<meta name="description" content="Every Three.js concept explained visually and interactively - 96 illustrated breakdowns plus hands-on interactive demos covering geometry, materials, cameras, shaders, physics, audio and more. Built for visual learners.">
<meta property="og:title" content="Three.js Visual & Interactive Encyclopedia">
<meta property="og:description" content="96 visual breakdowns plus interactive demos covering every Three.js concept. For visual learners.">
<meta property="og:image" content="images/encyclopedia/01_hero.webp">
<style>
:root {
--bg: #050810;
--bg2: #080c18;
--bg3: #0c1020;
--cyan: #00d4ff;
--magenta: #ff00cc;
--amber: #f5a623;
--green: #00ff88;
--purple: #a855f7;
--text: #f2f6ff;
--muted: #ccdaee;
--subtle: #1e2a42;
--border: rgba(0,212,255,0.12);
--glow-c: 0 0 30px rgba(0,212,255,0.25);
--glow-m: 0 0 30px rgba(255,0,204,0.2);
--glow-a: 0 0 30px rgba(245,166,35,0.2);
}
* { margin:0; padding:0; box-sizing:border-box; }
html { scroll-behavior:smooth; }
body {
background: var(--bg);
color: var(--text);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
line-height: 1.7;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* ─── NAV ─── */
nav {
position: fixed; top:0; left:0; right:0; z-index:200;
background: rgba(5,8,16,0.95);
backdrop-filter: blur(16px);
border-bottom: 1px solid var(--border);
height: 52px;
display: flex; align-items: center; gap: 0;
overflow-x: auto; overflow-y: hidden;
scrollbar-width: none;
}
nav::-webkit-scrollbar { display:none; }
.nav-logo {
padding: 0 1.5rem; font-weight:800; font-size:0.9rem;
color: var(--cyan); white-space:nowrap; letter-spacing:0.05em;
border-right: 1px solid var(--border); height:100%;
display:flex; align-items:center; flex-shrink:0;
}
nav a {
padding: 0 0.9rem; height:100%; display:flex; align-items:center;
color: var(--muted); text-decoration:none; font-size:0.72rem;
letter-spacing:0.06em; text-transform:uppercase; white-space:nowrap;
transition: color 0.2s; border-right: 1px solid rgba(255,255,255,0.03);
}
nav a:hover { color: var(--cyan); }
nav a.active { color: var(--cyan); box-shadow: inset 0 -2px 0 var(--cyan); }
/* ─── HERO ─── */
.hero {
min-height: 100vh; padding: 80px 2rem 5rem;
display: flex; flex-direction:column; align-items:center; justify-content:center;
text-align:center; position:relative;
background: radial-gradient(ellipse 80% 60% at 50% 0%, rgba(0,212,255,0.07) 0%, transparent 70%);
}
.hero-video-wrap {
width: min(960px, 100%);
border-radius: 14px; overflow:hidden;
border: 1px solid rgba(0,212,255,0.25);
box-shadow: var(--glow-c), 0 40px 100px rgba(0,0,0,0.6);
margin-bottom: 3.5rem;
}
.hero-video-wrap video { width:100%; display:block; }
.hero h1 {
font-size: clamp(2.2rem, 6vw, 4.5rem);
font-weight: 900; letter-spacing: -0.03em; line-height: 1.1;
background: linear-gradient(135deg, var(--cyan) 0%, #ffffff 45%, var(--magenta) 100%);
-webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
margin-bottom: 1.25rem;
padding-bottom: 0.08em;
}
.hero-sub {
font-size: clamp(1rem, 2.5vw, 1.3rem); color: #ccdaee;
max-width: 700px; margin: 0 auto 2.5rem; line-height: 1.65;
}
.hero-badges {
display:flex; flex-wrap:wrap; gap:0.6rem; justify-content:center; margin-bottom:2.5rem;
}
.badge {
padding: 0.3rem 1rem; border-radius:99px; font-size:0.78rem;
font-weight:600; letter-spacing:0.04em;
}
.bc { background:rgba(0,212,255,0.1); border:1px solid rgba(0,212,255,0.35); color:var(--cyan); }
.bm { background:rgba(255,0,204,0.1); border:1px solid rgba(255,0,204,0.35); color:var(--magenta); }
.ba { background:rgba(245,166,35,0.1); border:1px solid rgba(245,166,35,0.35); color:var(--amber); }
.bg { background:rgba(0,255,136,0.1); border:1px solid rgba(0,255,136,0.35); color:var(--green); }
.bp { background:rgba(168,85,247,0.1); border:1px solid rgba(168,85,247,0.35); color:var(--purple); }
.hero-cta {
display:flex; gap:1rem; flex-wrap:wrap; justify-content:center;
}
.btn {
display:inline-flex; align-items:center; gap:0.5rem;
padding: 0.8rem 1.8rem; border-radius:9px;
font-weight:700; font-size:0.95rem; text-decoration:none;
transition: all 0.2s; cursor:pointer; border:none;
}
.btn-p { background:var(--cyan); color:#040812; box-shadow: 0 4px 24px rgba(0,212,255,0.5); }
.btn-p:hover { box-shadow: 0 4px 40px rgba(0,212,255,0.8); transform:translateY(-2px); }
.btn-s { background:transparent; color:var(--text); border:1px solid rgba(255,255,255,0.12); }
.btn-s:hover { border-color:var(--cyan); color:var(--cyan); }
.btn-sp {
background: rgba(234, 74, 170, 0.14);
border: 1px solid rgba(234, 74, 170, 0.55);
color: #ffd4ef;
}
.btn-sp:hover {
background: rgba(234, 74, 170, 0.24);
border-color: rgba(234, 74, 170, 0.9);
color: #ffe7f6;
}
/* ─── FULL VIDEO ─── */
.full-video-wrap {
max-width: 1100px; margin: 0 auto; padding: 5rem 2rem;
border-top: 1px solid var(--border);
}
.full-video-wrap h2 {
font-size: clamp(1.4rem, 3vw, 2rem); font-weight:800; margin-bottom:0.5rem;
}
.full-video-wrap p { color:var(--muted); margin-bottom:1.5rem; }
.video-player {
border-radius:12px; overflow:hidden;
border:1px solid var(--border); box-shadow:var(--glow-c);
}
.video-player video { width:100%; display:block; }
/* ─── SECTION BREAK ─── */
.section-break {
max-width: 1200px; margin: 5rem auto 0; padding: 4rem 2rem 0;
border-top: 1px solid var(--border);
}
.section-break-header {
display:flex; align-items:center; gap:1.5rem; margin-bottom:0.75rem;
flex-wrap:wrap;
}
.section-num {
font-size: 0.75rem; font-weight:800; letter-spacing:0.15em;
text-transform:uppercase; padding:0.25rem 0.75rem;
border-radius:4px; flex-shrink:0;
}
.section-break-header h2 {
font-size: clamp(1.8rem, 4vw, 2.8rem); font-weight:900; letter-spacing:-0.02em;
}
.section-intro {
max-width: 860px; color: #d0e0f4; font-size: 1.05rem; line-height: 1.8;
margin-bottom: 1.5rem;
}
.section-links {
display:flex; gap:0.6rem; flex-wrap:wrap; margin-bottom: 3.5rem;
}
.doc-link {
display:inline-flex; align-items:center; gap:0.35rem;
padding:0.3rem 0.85rem; border-radius:6px; font-size:0.78rem; font-weight:500;
background:rgba(0,212,255,0.07); border:1px solid rgba(0,212,255,0.2);
color:var(--cyan); text-decoration:none; transition:all 0.2s;
}
.doc-link:hover { background:rgba(0,212,255,0.16); border-color:rgba(0,212,255,0.5); }
/* ─── IMAGE ENTRY (full width) ─── */
.img-entry {
max-width: 1800px; margin: 0 auto 5rem; padding: 0 1rem;
display: flex; flex-direction: column; align-items: center;
}
.img-entry img {
width: 100%; max-width: 100%; display:block; border-radius:14px;
border: 1px solid var(--border);
box-shadow: 0 8px 60px rgba(0,0,0,0.5);
transition: box-shadow 0.3s, transform 0.3s, opacity 0.4s;
cursor: zoom-in;
aspect-ratio: 16/9;
background: #0a0e1a;
opacity: 1;
}
.img-entry img.lazy-pending { opacity: 0.25; }
.img-entry img:hover {
box-shadow: var(--glow-c), 0 12px 80px rgba(0,0,0,0.7);
transform: translateY(-3px);
}
.img-entry .img-meta {
width: 100%; max-width: 100%;
}
.img-meta {
margin-top: 2rem; padding: 2rem 2.5rem 2rem;
background: var(--bg2); border-radius: 10px;
border: 1px solid var(--border);
}
.img-meta h3 {
font-size: clamp(1.15rem, 2.5vw, 1.5rem); font-weight:800;
margin-bottom: 0.75rem; letter-spacing:-0.01em; color: #ffffff;
}
.img-meta p {
color: #dce8f8; font-size: 1rem; line-height: 1.8;
margin-bottom: 0.75rem;
}
.img-meta p:last-child { margin-bottom:0; }
.key-points {
margin: 1rem 0; padding: 0; list-style:none;
display:flex; flex-wrap:wrap; gap:0.5rem;
}
.key-points li {
background: #1e2a42; border-radius:6px; border: 1px solid rgba(160,180,208,0.15);
padding: 0.3rem 0.85rem; font-size:0.8rem; font-weight:500;
color: #c8daf0; font-family: 'SF Mono', 'Fira Code', monospace;
}
.code-snippet {
margin-top: 1rem; background: #010812;
border: 1px solid rgba(0,212,255,0.12);
border-radius:8px; padding: 1rem 1.25rem;
font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
font-size: 0.82rem; line-height: 1.65; color: #b8cce8;
overflow-x: auto;
}
.code-snippet .kw { color: #00d4ff; }
.code-snippet .fn { color: #7ec8ff; }
.code-snippet .str { color: #7effc8; }
.code-snippet .cm { color: #5a6e8a; }
.img-meta code { background: rgba(0,212,255,0.1); color: #7ef8ff; padding: 0.1em 0.4em; border-radius: 4px; font-size: 0.9em; }
.img-meta strong { color: #ffffff; font-weight: 700; }
.img-doc-links { display:flex; gap:0.5rem; flex-wrap:wrap; margin-top:1.25rem; }
/* ─── DIVIDER ─── */
.divider {
max-width:1200px; margin: 1rem auto 3rem; padding: 0 2rem;
border-top: 1px solid rgba(255,255,255,0.04);
}
/* ─── FOOTER ─── */
footer {
background: var(--bg2); border-top:1px solid var(--border);
padding: 4rem 2rem 3rem; text-align:center;
}
footer img { max-width:min(1100px,100%); border-radius:12px; margin:0 auto 2.5rem; display:block; }
.footer-links { display:flex; gap:2rem; justify-content:center; flex-wrap:wrap; margin-bottom:1.5rem; }
.footer-links a { color:var(--cyan); text-decoration:none; font-size:0.9rem; }
.footer-links a:hover { text-decoration:underline; }
footer p { color:var(--muted); font-size:0.82rem; }
/* ─── LIGHTBOX ─── */
.lb {
display:none; position:fixed; inset:0; z-index:999;
background:rgba(0,0,0,0.95); align-items:center; justify-content:center;
cursor:zoom-out; padding:1rem;
}
.lb.open { display:flex; }
.lb img { max-width:97vw; max-height:95vh; border-radius:8px; object-fit:contain; }
.lb-x {
position:fixed; top:1rem; right:1.25rem; font-size:2rem;
color:rgba(255,255,255,0.6); cursor:pointer; background:none;
border:none; line-height:1; transition:color 0.2s;
}
.lb-x:hover { color:#fff; }
/* ─── SCROLLBAR ─── */
::-webkit-scrollbar { width:5px; }
::-webkit-scrollbar-track { background:var(--bg); }
::-webkit-scrollbar-thumb { background:rgba(0,212,255,0.2); border-radius:3px; }
/* ─── TWITTER CTA ─── */
.twitter-cta {
display: inline-flex; align-items: center; gap: 0.5rem;
padding: 0.8rem 1.8rem; border-radius: 9px;
background: #000; border: 1px solid #333;
color: #fff; font-weight: 700; font-size: 0.95rem;
text-decoration: none; transition: all 0.2s;
}
.twitter-cta:hover { background: #111; border-color: #555; transform: translateY(-2px); }
.twitter-cta svg { flex-shrink: 0; }
.twitter-cta-footer {
background: linear-gradient(135deg, #7c3aed, #a855f7);
border-color: #9333ea;
}
.twitter-cta-footer:hover { background: linear-gradient(135deg, #6d28d9, #9333ea); border-color: #a855f7; }
/* ─── RESPONSIVE ─── */
@media (max-width: 900px) {
.img-entry { padding: 0 1rem; }
.section-break { padding: 3rem 1rem 0; }
.full-video-wrap { padding: 3rem 1rem; }
.img-meta { padding: 1.5rem; }
.section-break-header h2 { font-size: clamp(1.4rem, 5vw, 2.2rem); }
}
@media (max-width: 600px) {
nav { height: 48px; }
.nav-logo { padding: 0 1rem; font-size: 0.8rem; }
nav a { padding: 0 0.6rem; font-size: 0.68rem; }
.hero { padding: 70px 1rem 3rem; }
.hero h1 { font-size: clamp(1.8rem, 8vw, 3rem); }
.img-entry { padding: 0 0.75rem; margin-bottom: 3rem; }
.img-meta { padding: 1.25rem; }
.img-meta h3 { font-size: 1rem; }
.key-points li { font-size: 0.72rem; padding: 0.25rem 0.6rem; }
.code-snippet { font-size: 0.75rem; }
.section-break { padding: 2.5rem 0.75rem 0; }
.section-num { font-size: 0.65rem; }
.btn { padding: 0.65rem 1.3rem; font-size: 0.88rem; }
.hero-badges { gap: 0.4rem; }
.badge { font-size: 0.7rem; padding: 0.25rem 0.75rem; }
}
/* ─── INTERACTIVE GUIDE NAV LINK ─── */
nav a.nav-interactive {
color: var(--green);
font-weight: 700;
background: rgba(0,255,136,0.08);
border-left: 1px solid rgba(0,255,136,0.2);
border-right: 1px solid rgba(0,255,136,0.2);
}
nav a.nav-interactive:hover {
color: #fff;
background: rgba(0,255,136,0.18);
}
/* ─── INTERACTIVE DEMO BUTTON (section headers) ─── */
.demo-link {
display:inline-flex; align-items:center; gap:0.35rem;
padding:0.3rem 0.85rem; border-radius:6px; font-size:0.78rem; font-weight:600;
background:rgba(0,255,136,0.1); border:1px solid rgba(0,255,136,0.3);
color:var(--green); text-decoration:none; transition:all 0.2s;
white-space:nowrap;
}
.demo-link:hover { background:rgba(0,255,136,0.22); border-color:rgba(0,255,136,0.6); color:#fff; }
/* ─── GREEN CTA BUTTON ─── */
.btn-g {
background: var(--green); color: #040812;
box-shadow: 0 4px 24px rgba(0,255,136,0.4);
}
.btn-g:hover {
box-shadow: 0 4px 40px rgba(0,255,136,0.7);
transform: translateY(-2px);
}
</style>
</head>
<body>
<!-- ── NAV ── -->
<nav>
<div class="nav-logo">⬡ THREE.JS</div>
<a href="#video">Video</a>
<a href="#geometry">Geometry</a>
<a href="#materials">Materials</a>
<a href="#lights">Lights</a>
<a href="#objects">Objects</a>
<a href="#cameras">Cameras</a>
<a href="#textures">Textures</a>
<a href="#renderer">Renderer</a>
<a href="#postfx">Post-FX</a>
<a href="#controls">Controls</a>
<a href="#tsl">Node/TSL</a>
<a href="#animation">Animation</a>
<a href="#audio">Audio</a>
<a href="#special">Special</a>
<a href="#loaders">Loaders</a>
<a href="#physics">Physics</a>
<a href="#helpers">Helpers</a>
<a href="#curves">Curves</a>
<a href="#math">Math</a>
<a href="demos/index.html" class="nav-interactive">▷ Interactive Guide</a>
<a href="https://github.com/sponsors/web3dev1337" target="_blank" rel="noopener">Sponsor</a>
</nav>
<!-- ── HERO ── -->
<section class="hero">
<div class="hero-video-wrap">
<video autoplay muted loop playsinline>
<source src="video/intro.mp4" type="video/mp4">
</video>
</div>
<h1>Three.js - A Visual Guide</h1>
<p class="hero-sub">Every concept in Three.js explained visually. 96 illustrated breakdowns covering geometry, materials, cameras, shaders, post-processing, physics, audio and more. No prior 3D experience required - just scroll.</p>
<div class="hero-badges">
<span class="badge bc">96 Visual Breakdowns</span>
<span class="badge bm">r183</span>
<span class="badge ba">WebGL + WebGPU</span>
<span class="badge bg">TSL / Node Shaders</span>
<span class="badge bp">Physics · Audio · Loaders</span>
</div>
<div class="hero-cta">
<a href="#video" class="btn btn-p">▶ Watch Full Video</a>
<a href="demos/index.html" class="btn btn-g">▷ Interactive Guide</a>
<a href="https://x.com/AIOnlyDeveloper" target="_blank" class="twitter-cta">
<svg width="16" height="16" viewBox="0 0 24 24" fill="white"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.747l7.73-8.835L1.254 2.25H8.08l4.259 5.63zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>
Follow for More
</a>
<a href="https://github.com/sponsors/web3dev1337" target="_blank" rel="noopener" class="btn btn-sp">❤ Sponsor This Guide</a>
<a href="https://threejs.org/docs/" target="_blank" class="btn btn-s">📄 Official Docs</a>
<a href="https://github.com/mrdoob/three.js" target="_blank" class="btn btn-s">⬡ GitHub</a>
</div>
</section>
<!-- ── FULL VIDEO ── -->
<div class="full-video-wrap" id="video">
<h2 style="color:var(--cyan)">Full Encyclopedia Video</h2>
<p>All 96 slides in sequence - 7 minutes covering every Three.js concept from geometry to shaders.</p>
<div class="video-player">
<video controls preload="metadata">
<source src="video/full_encyclopedia.mp4" type="video/mp4">
</video>
</div>
</div>
<!-- ══════════════════════════════════════════════
01 - OVERVIEW
══════════════════════════════════════════════ -->
<div class="section-break" id="overview">
<div class="section-break-header">
<span class="section-num bc">01</span>
<h2 style="color:var(--cyan)">Overview & Architecture</h2>
</div>
<p class="section-intro">Three.js is a JavaScript library that wraps WebGL (and now WebGPU) into an approachable scene graph API. The core idea: you describe <em>what</em> you want to show - objects, lights, a camera - and the renderer figures out <em>how</em> to draw it on the GPU. The architecture is simple: a Scene holds Object3Ds, a Camera defines the view, and a Renderer draws it all every frame.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#manual/en/introduction/Creating-a-scene" target="_blank" class="doc-link">↗ Creating a Scene</a>
<a href="https://github.com/mrdoob/three.js" target="_blank" class="doc-link">↗ GitHub Source</a>
<a href="https://threejs.org/examples/" target="_blank" class="doc-link">↗ Official Examples</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/01_hero.webp" alt="Three.js Architecture Overview" onclick="openLb(this)">
<div class="img-meta">
<h3>Three.js - Full Architecture Map</h3>
<p>Every Three.js scene follows the same pattern: create a <strong>Scene</strong>, add <strong>Mesh</strong> objects (Geometry + Material), position a <strong>Camera</strong>, and hand it all to the <strong>Renderer</strong> which sends draw calls to the GPU. The render loop runs at 60fps via <code>requestAnimationFrame</code>.</p>
<p>Understanding this flow is the foundation for everything else in this guide. Every other concept - shaders, post-processing, physics - sits on top of this core loop.</p>
<ul class="key-points">
<li>Scene</li><li>Camera</li><li>Renderer</li><li>Mesh</li>
<li>BufferGeometry</li><li>Material</li><li>Object3D</li><li>requestAnimationFrame</li>
</ul>
<div class="code-snippet">
<span class="cm">// The minimal Three.js scene</span>
<span class="kw">const</span> scene = <span class="kw">new</span> <span class="fn">THREE.Scene</span>();
<span class="kw">const</span> camera = <span class="kw">new</span> <span class="fn">THREE.PerspectiveCamera</span>( <span class="str">75</span>, width/height, <span class="str">0.1</span>, <span class="str">1000</span> );
<span class="kw">const</span> renderer = <span class="kw">new</span> <span class="fn">THREE.WebGLRenderer</span>({ antialias: <span class="str">true</span> });
renderer.<span class="fn">setAnimationLoop</span>( () => renderer.<span class="fn">render</span>( scene, camera ) );
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════
02 - GEOMETRY
══════════════════════════════════════════════ -->
<div class="section-break" id="geometry">
<div class="section-break-header">
<span class="section-num ba">02</span>
<h2 style="color:var(--amber)">Geometry</h2>
<a href="demos/geometry/primitives.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">Geometry defines the shape of a 3D object - the vertices, edges and faces that make up its surface. Under the hood, everything is a <code>BufferGeometry</code>: flat typed arrays of vertex data (position, normal, UV, color, index) sent directly to the GPU. Three.js ships 21 built-in geometry constructors, plus the tools to create your own from scratch or load from files.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/core/BufferGeometry" target="_blank" class="doc-link">↗ BufferGeometry</a>
<a href="https://threejs.org/docs/#api/en/geometries/BoxGeometry" target="_blank" class="doc-link">↗ BoxGeometry</a>
<a href="https://threejs.org/docs/#api/en/geometries/SphereGeometry" target="_blank" class="doc-link">↗ SphereGeometry</a>
<a href="https://threejs.org/examples/#webgl_geometries" target="_blank" class="doc-link">↗ Geometry Examples</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/02_geometry.webp" alt="Three.js Geometry Types" onclick="openLb(this)">
<div class="img-meta">
<h3>All 21 Built-in Geometry Types</h3>
<p>Three.js provides a geometry for almost every common shape out of the box. The primitives - Box, Sphere, Cylinder, Cone, Torus - cover most game and visualisation needs. The parametric types - LatheGeometry, TubeGeometry, ExtrudeGeometry - let you create complex shapes from curves and profiles. The polyhedra - Icosahedron, Dodecahedron, Octahedron - produce mathematically perfect symmetric shapes.</p>
<p>All geometries have a <code>widthSegments</code>/<code>heightSegments</code> parameter that controls polygon density. More segments = smoother shape but higher vertex count. TorusKnotGeometry creates intricate knotted shapes via <code>p</code> and <code>q</code> winding parameters.</p>
<ul class="key-points">
<li>BoxGeometry</li><li>SphereGeometry</li><li>CylinderGeometry</li><li>ConeGeometry</li>
<li>TorusGeometry</li><li>TorusKnotGeometry</li><li>PlaneGeometry</li><li>CircleGeometry</li>
<li>RingGeometry</li><li>CapsuleGeometry</li><li>LatheGeometry</li><li>ExtrudeGeometry</li>
<li>ShapeGeometry</li><li>TubeGeometry</li><li>IcosahedronGeometry</li><li>DodecahedronGeometry</li>
<li>OctahedronGeometry</li><li>TetrahedronGeometry</li><li>EdgesGeometry</li><li>WireframeGeometry</li>
<li>PolyhedronGeometry</li>
</ul>
<div class="code-snippet">
<span class="cm">// Create geometry with detail level</span>
<span class="kw">const</span> geo = <span class="kw">new</span> <span class="fn">THREE.SphereGeometry</span>( radius, widthSegs, heightSegs );
<span class="kw">const</span> knot = <span class="kw">new</span> <span class="fn">THREE.TorusKnotGeometry</span>( <span class="str">10</span>, <span class="str">3</span>, <span class="str">100</span>, <span class="str">16</span>, p, q );
</div>
<div class="img-doc-links">
<a href="https://threejs.org/docs/#api/en/geometries/TorusKnotGeometry" target="_blank" class="doc-link">↗ TorusKnotGeometry</a>
<a href="https://threejs.org/docs/#api/en/geometries/LatheGeometry" target="_blank" class="doc-link">↗ LatheGeometry</a>
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════
03 - MATERIALS
══════════════════════════════════════════════ -->
<div class="section-break" id="materials">
<div class="section-break-header">
<span class="section-num bm">03</span>
<h2 style="color:var(--magenta)">Materials</h2>
<a href="demos/materials/all-materials.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">Materials control how geometry looks when rendered - its colour, shininess, transparency, and how it reacts to light. Three.js has materials for every use case and performance budget: from the cheapest flat <code>MeshBasicMaterial</code> (no lighting) to the fully physics-based <code>MeshPhysicalMaterial</code> with clearcoat, sheen, iridescence, transmission and subsurface scattering. The right material makes the difference between flat and photorealistic.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/materials/MeshStandardMaterial" target="_blank" class="doc-link">↗ MeshStandardMaterial</a>
<a href="https://threejs.org/docs/#api/en/materials/MeshPhysicalMaterial" target="_blank" class="doc-link">↗ MeshPhysicalMaterial</a>
<a href="https://threejs.org/docs/#api/en/materials/ShaderMaterial" target="_blank" class="doc-link">↗ ShaderMaterial</a>
<a href="https://threejs.org/examples/#webgl_materials" target="_blank" class="doc-link">↗ Material Examples</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/03_materials.webp" alt="Three.js Materials" onclick="openLb(this)">
<div class="img-meta">
<h3>All Material Types - From Basic to Physically Based</h3>
<p><strong>MeshBasicMaterial</strong> - No lighting calculation. Always shows flat colour or texture. Zero GPU cost. Use for UI, wireframes, non-lit stylised objects.</p>
<p><strong>MeshLambertMaterial</strong> - Diffuse-only lighting (no specular). Calculated per-vertex, not per-pixel. Fast and decent for matte surfaces. Not realistic but works great for stylised scenes.</p>
<p><strong>MeshPhongMaterial</strong> - Adds a specular highlight (Blinn-Phong model). <code>shininess</code> controls the tightness of the specular spot. Classic 3D look, faster than PBR.</p>
<p><strong>MeshStandardMaterial</strong> - Physically-based rendering (PBR). Metalness/roughness workflow. <code>roughness=0</code> is mirror-like, <code>roughness=1</code> is fully diffuse. Correctly responds to environment maps and IBL lighting.</p>
<p><strong>MeshPhysicalMaterial</strong> - Extends Standard with clearcoat, sheen (velvet), iridescence, transmission (glass), thickness (refraction depth) and anisotropy. The most realistic material.</p>
<p><strong>MeshToonMaterial</strong> - Cel-shaded cartoon look using a gradient map to define the step in shading bands. Combine with an outline pass for a complete anime aesthetic.</p>
<ul class="key-points">
<li>MeshBasicMaterial</li><li>MeshLambertMaterial</li><li>MeshPhongMaterial</li>
<li>MeshStandardMaterial</li><li>MeshPhysicalMaterial</li><li>MeshToonMaterial</li>
<li>MeshNormalMaterial</li><li>MeshDepthMaterial</li><li>MeshMatcapMaterial</li>
<li>LineBasicMaterial</li><li>PointsMaterial</li><li>SpriteMaterial</li>
<li>ShaderMaterial</li><li>RawShaderMaterial</li>
</ul>
<div class="code-snippet">
<span class="cm">// Standard PBR material</span>
<span class="kw">const</span> mat = <span class="kw">new</span> <span class="fn">THREE.MeshStandardMaterial</span>({
color: <span class="str">0xff6600</span>, roughness: <span class="str">0.3</span>, metalness: <span class="str">0.8</span>,
normalMap: normalTex, envMapIntensity: <span class="str">1.5</span>
});
<span class="cm">// Physical material (glass)</span>
<span class="kw">const</span> glass = <span class="kw">new</span> <span class="fn">THREE.MeshPhysicalMaterial</span>({
transmission: <span class="str">1</span>, thickness: <span class="str">0.5</span>, roughness: <span class="str">0</span>, ior: <span class="str">1.5</span>
});
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════
04 - LIGHTS
══════════════════════════════════════════════ -->
<div class="section-break" id="lights">
<div class="section-break-header">
<span class="section-num ba">04</span>
<h2 style="color:var(--amber)">Lighting</h2>
<a href="demos/lights/all-lights.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">Lighting is what makes a 3D scene feel real. A well-lit scene communicates depth, weight, material type and mood. Three.js offers 7 light types - from the ambient fill that eliminates harsh shadows to the precise spotlight casting dramatic shadows. Only DirectionalLight, SpotLight and PointLight can cast shadows; each uses a shadow map technique (rendering the scene from the light's POV to determine occlusion).</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/lights/DirectionalLight" target="_blank" class="doc-link">↗ DirectionalLight</a>
<a href="https://threejs.org/docs/#api/en/lights/PointLight" target="_blank" class="doc-link">↗ PointLight</a>
<a href="https://threejs.org/docs/#api/en/lights/SpotLight" target="_blank" class="doc-link">↗ SpotLight</a>
<a href="https://threejs.org/docs/#api/en/lights/shadows/LightShadow" target="_blank" class="doc-link">↗ Shadows</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/04_lights.webp" alt="Three.js Lighting" onclick="openLb(this)">
<div class="img-meta">
<h3>7 Light Types + Shadow Maps</h3>
<p><strong>AmbientLight</strong> - Adds a flat uniform colour to every surface. No direction, no shadows, no highlights. Use it as a base fill to prevent completely black shadows. Too much makes scenes look flat.</p>
<p><strong>DirectionalLight</strong> - Infinite parallel rays, like the sun. All shadows are parallel (use OrthographicCamera for shadow map). Position sets the direction; target sets what it points at. The workhorse outdoor light.</p>
<p><strong>PointLight</strong> - Radiates in all directions from a point, like a light bulb. Has <code>distance</code> and <code>decay</code> for falloff. Casts shadows in 6 directions (expensive - uses CubeCamera internally).</p>
<p><strong>SpotLight</strong> - Cone-shaped beam, like a flashlight or stage light. <code>angle</code> sets cone width, <code>penumbra</code> softens the edge. Position + target defines the beam direction. Great for dramatic lighting.</p>
<p><strong>HemisphereLight</strong> - Sky colour from above, ground colour from below. Two-colour gradient fill that simulates outdoor ambient light. No shadows. Very cheap and effective for outdoor scenes.</p>
<p><strong>RectAreaLight</strong> - Soft rectangular light source (like a fluorescent tube or window). Works only with MeshStandardMaterial and MeshPhysicalMaterial. Requires RectAreaLightUniformsLib. No shadow support.</p>
<p><strong>LightProbe</strong> - Encodes ambient lighting as spherical harmonics (SH). Low-frequency ambient lighting baked from the environment - smooth, cheap, and great for matching captured real-world lighting.</p>
<div class="code-snippet">
<span class="cm">// Three-point lighting setup</span>
<span class="kw">const</span> key = <span class="kw">new</span> <span class="fn">THREE.DirectionalLight</span>( <span class="str">0xffffff</span>, <span class="str">2</span> );
key.castShadow = <span class="str">true</span>;
key.shadow.mapSize.<span class="fn">set</span>( <span class="str">2048</span>, <span class="str">2048</span> );
<span class="kw">const</span> fill = <span class="kw">new</span> <span class="fn">THREE.HemisphereLight</span>( <span class="str">0x8888ff</span>, <span class="str">0x443322</span>, <span class="str">0.5</span> );
<span class="kw">const</span> rim = <span class="kw">new</span> <span class="fn">THREE.PointLight</span>( <span class="str">0x00ffff</span>, <span class="str">1</span>, <span class="str">50</span> );
</div>
</div>
</div>
<!-- ══════════════════════════════════════════════
05 - OBJECTS
══════════════════════════════════════════════ -->
<div class="section-break" id="objects">
<div class="section-break-header">
<span class="section-num bg">05</span>
<h2 style="color:var(--green)">Scene Objects</h2>
<a href="demos/objects/scene-graph.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">Everything in a Three.js scene is an <code>Object3D</code> - the base class providing position, rotation, scale, visibility, and parent/child hierarchy. From the basic <code>Mesh</code> to the GPU-instanced <code>InstancedMesh</code> that draws 100,000 copies in a single draw call, each object type exists to solve a specific rendering challenge.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/core/Object3D" target="_blank" class="doc-link">↗ Object3D</a>
<a href="https://threejs.org/docs/#api/en/objects/Mesh" target="_blank" class="doc-link">↗ Mesh</a>
<a href="https://threejs.org/docs/#api/en/objects/InstancedMesh" target="_blank" class="doc-link">↗ InstancedMesh</a>
<a href="https://threejs.org/docs/#api/en/objects/Points" target="_blank" class="doc-link">↗ Points</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/05_objects.webp" alt="Three.js Scene Objects" onclick="openLb(this)">
<div class="img-meta">
<h3>All Object Types in the Scene Graph</h3>
<p><strong>Mesh</strong> - The fundamental 3D object: geometry + material. Supports position, rotation, scale, visibility, shadow casting/receiving. Most of your scene will be Meshes.</p>
<p><strong>InstancedMesh</strong> - Renders N copies of the same geometry+material in a single GPU draw call. Set each instance's transform via <code>setMatrixAt(i, matrix)</code>. Renders a forest of 100,000 trees as fast as one tree. Essential for performance.</p>
<p><strong>BatchedMesh</strong> (r159+) - Like InstancedMesh but allows different geometries in the same draw call. Add and remove geometry slots dynamically without recreating the whole buffer.</p>
<p><strong>SkinnedMesh</strong> - A Mesh deformed by a Skeleton (bone hierarchy). Bones are Object3Ds - moving them deforms the mesh via skinning weights stored in the geometry. Used for all character animation.</p>
<p><strong>Points</strong> - Renders each vertex as a screen-aligned point/sprite. Used for particle systems - fire, smoke, stars, galaxy simulations. PointsMaterial controls size, texture, colour and size attenuation with distance.</p>
<p><strong>Line / LineSegments / LineLoop</strong> - Draws line primitives. LineSegments draws disconnected pairs. LineLoop closes the path. Used for debug geometry, wireframes, connector lines, graphs.</p>
<p><strong>Sprite</strong> - A billboard that always faces the camera. Sized in screen space. Used for labels, icons, particle effects and 2D elements in 3D space.</p>
<p><strong>Group</strong> - An empty Object3D used as a parent container. Transforming a Group moves all children together. Fundamental for scene organisation and hierarchical animation.</p>
<p><strong>LOD</strong> - Automatically swaps between high/medium/low poly versions based on camera distance. Add levels with <code>lod.addLevel(mesh, distance)</code>. Essential for large open-world scenes.</p>
<ul class="key-points">
<li>Mesh</li><li>InstancedMesh</li><li>BatchedMesh</li><li>SkinnedMesh</li>
<li>Points</li><li>Line</li><li>LineSegments</li><li>LineLoop</li>
<li>Sprite</li><li>Group</li><li>LOD</li><li>Scene</li>
</ul>
</div>
</div>
<!-- ══════════════════════════════════════════════
07 - CAMERAS
══════════════════════════════════════════════ -->
<div class="section-break" id="cameras">
<div class="section-break-header">
<span class="section-num bc">07</span>
<h2 style="color:var(--cyan)">Cameras</h2>
<a href="demos/cameras/perspective.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">The camera defines how the 3D scene is projected onto your 2D screen. <code>PerspectiveCamera</code> mimics human vision - objects farther away appear smaller. <code>OrthographicCamera</code> has no perspective - objects stay the same size regardless of distance, giving the classic isometric game look. The remaining cameras serve specialised purposes: real-time reflections, multi-viewport, and VR.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/cameras/PerspectiveCamera" target="_blank" class="doc-link">↗ PerspectiveCamera</a>
<a href="https://threejs.org/docs/#api/en/cameras/OrthographicCamera" target="_blank" class="doc-link">↗ OrthographicCamera</a>
<a href="https://threejs.org/docs/#api/en/cameras/CubeCamera" target="_blank" class="doc-link">↗ CubeCamera</a>
<a href="https://threejs.org/docs/#api/en/cameras/ArrayCamera" target="_blank" class="doc-link">↗ ArrayCamera</a>
</div>
</div>
<div class="img-entry">
<img data-src="images/encyclopedia/07a_perspective_camera.webp" alt="PerspectiveCamera FOV" onclick="openLb(this)">
<div class="img-meta">
<h3>PerspectiveCamera - Field of View</h3>
<p>The most common camera in Three.js. Takes four parameters: <code>fov</code> (vertical field of view in degrees), <code>aspect</code> (width/height of the canvas), <code>near</code> (closest visible distance), <code>far</code> (furthest visible distance).</p>
<p><strong>FOV 30°</strong> - Telephoto/sniper zoom. Looks flat, compressed perspective. Objects appear very close together. Used in sniper rifle scopes, architectural renders where you want distortion-free perspective.</p>
<p><strong>FOV 75°</strong> - Standard FPS game feel. Natural perspective, good depth. Most third-person games and 3D web apps use 60–75°.</p>
<p><strong>FOV 120°</strong> - Ultra-wide angle, strong fisheye effect. See a huge amount of the scene but with significant edge distortion. Used for racing cockpits, arena shooters, action games.</p>
<div class="code-snippet">
<span class="kw">const</span> camera = <span class="kw">new</span> <span class="fn">THREE.PerspectiveCamera</span>(
fov, <span class="cm">// field of view in degrees (vertical)</span>
aspect, <span class="cm">// canvas width / canvas height</span>
near, <span class="cm">// near clipping plane (e.g. 0.1)</span>
far <span class="cm">// far clipping plane (e.g. 1000)</span>
);
</div>
</div>
</div>
<div class="divider"></div>
<div class="img-entry">
<img data-src="images/encyclopedia/07b_orthographic_camera.webp" alt="OrthographicCamera" onclick="openLb(this)">
<div class="img-meta">
<h3>OrthographicCamera - Parallel Projection</h3>
<p>No perspective. Objects at the same size remain the same size regardless of distance from camera. This is the camera for isometric strategy games, top-down 2D games, CAD/engineering views, and shadow maps for directional lights. Takes <code>left</code>, <code>right</code>, <code>top</code>, <code>bottom</code>, <code>near</code>, <code>far</code> - defining a box-shaped frustum.</p>
<ul class="key-points"><li>left/right/top/bottom</li><li>near/far</li><li>no perspective distortion</li><li>isometric games</li><li>shadow cameras</li></ul>
</div>
</div>
<div class="divider"></div>
<div class="img-entry">
<img data-src="images/encyclopedia/07c_cube_camera.webp" alt="CubeCamera" onclick="openLb(this)">
<div class="img-meta">
<h3>CubeCamera - 360° Environment Capture</h3>
<p>Renders the scene 6 times (±X, ±Y, ±Z faces) into a WebGLCubeRenderTarget, producing a cubemap texture of the environment. Place it inside/near an object to capture its reflection environment. Update it each frame for dynamic real-time reflections - or capture once and cache for static reflections.</p>
<div class="code-snippet">
<span class="kw">const</span> cubeRT = <span class="kw">new</span> <span class="fn">THREE.WebGLCubeRenderTarget</span>( <span class="str">256</span> );
<span class="kw">const</span> cubeCamera = <span class="kw">new</span> <span class="fn">THREE.CubeCamera</span>( <span class="str">0.1</span>, <span class="str">100</span>, cubeRT );
sphere.material.envMap = cubeRT.texture; <span class="cm">// use as reflection</span>
</div>
</div>
</div>
<div class="divider"></div>
<div class="img-entry">
<img data-src="images/encyclopedia/07d_array_camera.webp" alt="ArrayCamera" onclick="openLb(this)">
<div class="img-meta">
<h3>ArrayCamera - Multiple Viewports</h3>
<p>An array of sub-cameras each defining a viewport region (x, y, width, height in normalised 0–1 coordinates). Used for split-screen multiplayer games, security camera monitor UIs, or rendering the same scene from multiple simultaneous viewpoints. More efficient than rendering multiple separate scenes.</p>
</div>
</div>
<div class="divider"></div>
<div class="img-entry">
<img data-src="images/encyclopedia/07e_stereo_camera.webp" alt="StereoCamera" onclick="openLb(this)">
<div class="img-meta">
<h3>StereoCamera - VR & 3D Anaglyph</h3>
<p>Two cameras separated by an eye offset (<code>eyeSep</code> parameter, default 0.064 metres). Renders left and right eye views side by side. Used with VR headsets (also see XRManager for full WebXR support) or red-cyan anaglyph 3D for classic stereoscopic effect.</p>
</div>
</div>
<!-- ══════════════════════════════════════════════
08 - TEXTURES
══════════════════════════════════════════════ -->
<div class="section-break" id="textures">
<div class="section-break-header">
<span class="section-num bm">08</span>
<h2 style="color:var(--magenta)">Textures</h2>
<a href="demos/textures/normal-maps.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">Textures are images mapped onto geometry surfaces to add visual detail without adding geometry. A UV map on each vertex tells the GPU which part of the texture to sample there. Three.js supports flat colour textures, normal maps for fake surface depth, full PBR texture sets, video textures, HDR environments, and compressed GPU-native formats for 4–8× less VRAM usage.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/textures/Texture" target="_blank" class="doc-link">↗ Texture</a>
<a href="https://threejs.org/docs/#api/en/loaders/TextureLoader" target="_blank" class="doc-link">↗ TextureLoader</a>
<a href="https://threejs.org/docs/#api/en/textures/CompressedTexture" target="_blank" class="doc-link">↗ CompressedTexture</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/08a_texture_basics.webp" alt="Texture Basics" onclick="openLb(this)"><div class="img-meta"><h3>Texture Basics & UV Mapping</h3><p>Every vertex has a UV coordinate (0–1 range) that maps it to a position in a 2D texture. UV 0,0 is bottom-left, 1,1 is top-right. Use <code>texture.repeat</code> to tile, <code>texture.offset</code> to shift, <code>texture.wrapS/T</code> to control how it repeats at edges (ClampToEdge, Repeat, MirroredRepeat).</p><div class="code-snippet"><span class="kw">const</span> tex = <span class="kw">new</span> <span class="fn">THREE.TextureLoader</span>().<span class="fn">load</span>( <span class="str">'wood.jpg'</span> ); tex.repeat.<span class="fn">set</span>( <span class="str">4</span>, <span class="str">4</span> ); tex.wrapS = tex.wrapT = <span class="fn">THREE.RepeatWrapping</span>;</div></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08b_normal_maps.webp" alt="Normal Maps" onclick="openLb(this)"><div class="img-meta"><h3>Normal Maps - Fake Surface Detail</h3><p>An RGB image where each pixel encodes a surface normal direction. The lighting model uses these fake normals to simulate bumps, scratches, fabric weave and detail - without adding a single polygon. The result looks 3D under moving light but the geometry remains flat. Essential for game-quality assets.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08c_pbr_texture_set.webp" alt="PBR Texture Set" onclick="openLb(this)"><div class="img-meta"><h3>PBR Texture Set</h3><p>A full physically-based rendering texture set for MeshStandardMaterial: <strong>Albedo</strong> (base colour, no lighting), <strong>Normal</strong> (surface detail direction), <strong>Roughness</strong> (how blurry reflections are - 0=mirror, 1=fully matte), <strong>Metalness</strong> (is it metal? - 0=non-metal, 1=metal), <strong>AO</strong> (ambient occlusion - contact shadows). Optional: Emissive, Displacement, Opacity.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08d_cube_texture_skybox.webp" alt="Skybox" onclick="openLb(this)"><div class="img-meta"><h3>CubeTexture - Skybox & Environment</h3><p>6 images (±X, ±Y, ±Z) assembled into a cubemap. Set <code>scene.background = cubeTexture</code> for a skybox. Set <code>scene.environment = cubeTexture</code> to use it as IBL (image-based lighting) - it will automatically light all PBR materials, providing realistic reflections and ambient lighting from the environment.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08e_video_texture.webp" alt="Video Texture" onclick="openLb(this)"><div class="img-meta"><h3>VideoTexture - Live Video on Surfaces</h3><p>Maps a playing HTML <code><video></code> element onto a 3D surface in real time. The texture updates every frame to match the video playback. Used for in-game TVs, screens, portals, projectors and video walls. Must call <code>videoTexture.needsUpdate = true</code> each frame.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08f_data_texture.webp" alt="Data Texture" onclick="openLb(this)"><div class="img-meta"><h3>DataTexture - Programmatic Textures</h3><p>Create textures directly from typed arrays in JavaScript - no image file needed. Pass a <code>Uint8Array</code> or <code>Float32Array</code> of pixel values. Used for heatmaps, heightmaps, scientific data visualisation, and GPU-computed textures from compute shaders.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08g_hdr_environment.webp" alt="HDR Environment" onclick="openLb(this)"><div class="img-meta"><h3>HDR / EXR Environment Maps</h3><p>High dynamic range images store light values far above 1.0, capturing the full range from deep shadow to bright sun. Load .hdr (RGBE format) with RGBELoader or .exr with EXRLoader, then pass to PMREMGenerator to prefilter for PBR rendering. The result: metal surfaces reflect actual sunlight, not just a flat colour.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/08h_compressed_textures.webp" alt="Compressed Textures" onclick="openLb(this)"><div class="img-meta"><h3>Compressed Textures - KTX2 / Basis</h3><p>GPU-native compressed formats stay compressed in VRAM - 4–8× less memory than PNG. KTX2 with Basis supercompression is the modern standard: a single .ktx2 file transcodes to the best format per device (DXT/BC for desktop, ETC for Android, ASTC for iOS). Use KTX2Loader + MSDF worker. Critical for mobile performance.</p></div></div>
<!-- ══════════════════════════════════════════════
09 - RENDERER
══════════════════════════════════════════════ -->
<div class="section-break" id="renderer">
<div class="section-break-header">
<span class="section-num bc">09</span>
<h2 style="color:var(--cyan)">Renderer Features</h2>
<a href="demos/renderer/shadow-types.html" class="demo-link">▷ Try Interactive Demo</a>
</div>
<p class="section-intro">The renderer transforms your scene into pixels. Three.js has WebGLRenderer (the proven standard, works everywhere) and WebGPURenderer (the modern future, compute shaders, better performance). Both share a common abstraction layer so most code runs on either. Key features: shadow maps, environment mapping, tone mapping, anti-aliasing, and render targets for off-screen rendering.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/renderers/WebGLRenderer" target="_blank" class="doc-link">↗ WebGLRenderer</a>
<a href="https://threejs.org/docs/#api/en/renderers/WebGPURenderer" target="_blank" class="doc-link">↗ WebGPURenderer</a>
<a href="https://threejs.org/docs/#api/en/renderers/WebGLRenderTarget" target="_blank" class="doc-link">↗ RenderTarget</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/09a_shadow_types.webp" alt="Shadow Types" onclick="openLb(this)"><div class="img-meta"><h3>Shadow Map Types</h3><p><strong>BasicShadowMap</strong> - Fastest, hard edges. <strong>PCFShadowMap</strong> - Percentage-closer filtering, smoother edges. <strong>PCFSoftShadowMap</strong> - Softer PCF with kernel blur. <strong>VSMShadowMap</strong> - Variance shadow maps, very soft, no peter-panning artifact, but has light bleeding on transparent objects. Set via <code>renderer.shadowMap.type = THREE.PCFSoftShadowMap</code>.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09b_environment_mapping.webp" alt="Environment Mapping" onclick="openLb(this)"><div class="img-meta"><h3>Environment Mapping & IBL</h3><p>Set <code>scene.environment = pmremTexture</code> to enable image-based lighting for all PBR materials simultaneously. Metal objects reflect the environment, rough objects receive diffuse IBL. envMapIntensity scales the strength. Combine with a visible skybox for complete immersive environments.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09c_tone_mapping.webp" alt="Tone Mapping" onclick="openLb(this)"><div class="img-meta"><h3>Tone Mapping</h3><p>HDR rendering produces light values above 1.0. Tone mapping squashes the full HDR range into the 0–1 display range. <strong>NoToneMapping</strong> clips. <strong>ReinhardToneMapping</strong> is photographic. <strong>ACESFilmicToneMapping</strong> gives a cinematic S-curve look (most popular). <strong>AgXToneMapping</strong> (r158+) is physically accurate with correct hue preservation.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09d_anti_aliasing.webp" alt="Anti-Aliasing" onclick="openLb(this)"><div class="img-meta"><h3>Anti-Aliasing</h3><p>Built-in MSAA: pass <code>antialias: true</code> to WebGLRenderer. Post-process options: FXAA (fast, slight blur), SMAA (better quality, two-pass). TAA (temporal AA) provides highest quality by accumulating sub-pixel samples over multiple frames - only works on static or slow-moving scenes.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09e_render_targets.webp" alt="Render Targets" onclick="openLb(this)"><div class="img-meta"><h3>Render Targets - Off-screen Rendering</h3><p>WebGLRenderTarget redirects render output to a texture instead of the screen. That texture can then be applied to a 3D surface (a TV showing another camera), used as input to post-processing, or read back to CPU. The basis for all multi-pass rendering techniques.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09f_webgl_vs_webgpu.webp" alt="WebGL vs WebGPU" onclick="openLb(this)"><div class="img-meta"><h3>WebGL vs WebGPU</h3><p><strong>WebGL</strong>: Based on OpenGL ES 2.0/3.0. ~98% browser support. Proven, stable. Limited to graphics pipeline. <strong>WebGPU</strong>: Modern explicit GPU API. Compute shaders, better multi-threading, lower driver overhead. ~70% browser support (2024). Three.js wraps both behind the same API - switch with <code>import WebGPURenderer from 'three/webgpu'</code>.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09g_compute_shaders.webp" alt="Compute Shaders" onclick="openLb(this)"><div class="img-meta"><h3>Compute Shaders (WebGPU only)</h3><p>GPU programs running outside the graphics pipeline. Simulate millions of particles, fluid dynamics, cloth, or crowds entirely on the GPU - reading and writing storage buffers. Available via WebGPURenderer with TSL's <code>compute()</code> function. Orders of magnitude faster than CPU for parallelisable problems.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/09h_render_pipeline.webp" alt="Render Pipeline" onclick="openLb(this)"><div class="img-meta"><h3>Render Pipeline - Frame by Frame</h3><p>Scene graph → frustum culling → sort render list by material (opaque first, transparent last, by z-depth) → set render state → GPU: vertex shader (transforms positions to clip space) → rasterisation (converts triangles to fragments) → fragment shader (computes pixel colour) → framebuffer → screen. Understanding this helps diagnose performance and visual issues.</p></div></div>
<!-- ══════════════════════════════════════════════
10 - POST-PROCESSING
══════════════════════════════════════════════ -->
<div class="section-break" id="postfx">
<div class="section-break-header">
<span class="section-num bm">10</span>
<h2 style="color:var(--magenta)">Post-Processing Effects</h2>
</div>
<p class="section-intro">Post-processing applies screen-space effects after the scene is rendered to a texture. EffectComposer chains passes together - the output of one feeds into the next. Three.js ships 20+ built-in passes and you can write custom fullscreen shader passes. The difference between a raw render and a cinematic scene is almost entirely post-processing.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#examples/en/postprocessing/EffectComposer" target="_blank" class="doc-link">↗ EffectComposer</a>
<a href="https://threejs.org/examples/#webgl_postprocessing" target="_blank" class="doc-link">↗ Post-FX Examples</a>
<a href="https://github.com/pmndrs/postprocessing" target="_blank" class="doc-link">↗ pmndrs/postprocessing</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/10a_effect_composer.webp" alt="EffectComposer" onclick="openLb(this)"><div class="img-meta"><h3>EffectComposer - The Post-Processing Pipeline</h3><p>RenderPass renders the scene to a texture. Each subsequent pass reads from the previous pass's texture, applies an effect, and writes to the next. OutputPass or RenderPixelatedPass writes to screen. The order matters - bloom after SSAO, before colour grading.</p><div class="code-snippet"><span class="kw">const</span> composer = <span class="kw">new</span> <span class="fn">EffectComposer</span>( renderer );<br>composer.<span class="fn">addPass</span>( <span class="kw">new</span> <span class="fn">RenderPass</span>( scene, camera ) );<br>composer.<span class="fn">addPass</span>( <span class="kw">new</span> <span class="fn">UnrealBloomPass</span>( resolution, strength, radius, threshold ) );<br>composer.<span class="fn">addPass</span>( <span class="kw">new</span> <span class="fn">OutputPass</span>() );</div></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10b_bloom.webp" alt="Bloom" onclick="openLb(this)"><div class="img-meta"><h3>Bloom / UnrealBloomPass</h3><p>Bright areas bleed glow into surrounding pixels, simulating the way intense light overloads a camera lens or your eyes. Adjust <code>threshold</code> (minimum brightness to bloom), <code>strength</code> (intensity), <code>radius</code> (spread distance). Selective bloom: use two scenes - one with only emissive objects, run bloom on that, composite back.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10c_ssao.webp" alt="SSAO" onclick="openLb(this)"><div class="img-meta"><h3>SSAO - Screen-Space Ambient Occlusion</h3><p>Darkens concave areas - crevices, corners, where surfaces meet - to simulate ambient light being blocked. Adds ground and weight to objects. Computed entirely from the depth buffer in screen space, so it's cheap and doesn't require ray-tracing. SAOPass in Three.js examples.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10d_depth_of_field.webp" alt="Depth of Field" onclick="openLb(this)"><div class="img-meta"><h3>Depth of Field (Bokeh)</h3><p>Objects outside the focal plane blur with characteristic disc-shaped bokeh, mimicking a real camera lens with a narrow depth of field. <code>focus</code> sets focal distance, <code>aperture</code> controls blur amount, <code>maxblur</code> clamps the maximum. Draws the viewer's eye to the focal point.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10e_film_grain.webp" alt="Film Grain" onclick="openLb(this)"><div class="img-meta"><h3>Film Grain & Noise</h3><p>Adds time-varying noise to every pixel, simulating photographic film grain or sensor noise. Softens the overly-clean look of CGI and adds cinematic character. FilmPass in Three.js adds grain + optional scanlines. Animated per-frame so it looks organic, not like a static texture overlay.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10f_glitch.webp" alt="Glitch Effect" onclick="openLb(this)"><div class="img-meta"><h3>Glitch Effect</h3><p>Digital corruption: random horizontal band shifts, RGB channel separation, noise blocks. GlitchPass triggers random glitch bursts at <code>goWild</code> intensity, or stays subtle at low settings. Perfect for cyberpunk, horror, hack/error UI moments, and sci-fi transitions.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10g_outline.webp" alt="Outline" onclick="openLb(this)"><div class="img-meta"><h3>Outline - Selection Highlight</h3><p>OutlinePass renders selected objects with a coloured edge glow. Objects added to <code>selectedObjects</code> array get outlined. Control colour, thickness (edgeThickness) and glow (edgeStrength). Essential for game selection UIs, hover highlighting, and emphasising interactive objects.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10h_color_grading.webp" alt="Color Grading" onclick="openLb(this)"><div class="img-meta"><h3>Color Grading / LUT</h3><p>A 3D Look-Up Table (LUT) remaps the output colours of the entire frame - like an Instagram filter but for your 3D scene. LUTPass loads a .cube or .png LUT file. Transform any scene: warm cinematic orange-teal, cold horror blue, vintage sepia, crushed blacks. Industry standard.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10i_motion_blur.webp" alt="Motion Blur" onclick="openLb(this)"><div class="img-meta"><h3>Motion Blur</h3><p>Blurs fast-moving objects along their trajectory, as a real camera shutter would capture during exposure. Gives movement weight, speed and physicality. Can be per-object (accumulate velocity vectors) or full-screen camera motion blur. Makes action scenes feel kinetic.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10j_god_rays.webp" alt="God Rays" onclick="openLb(this)"><div class="img-meta"><h3>God Rays - Volumetric Light Shafts</h3><p>Visible shafts of light when a bright source is partially occluded - sun through clouds, lamp through fog. GodraysPass renders the scene silhouette from the light position, then applies radial blur outward. The result: volumetric-looking light without actual volumetric simulation.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10k_chromatic_aberration.webp" alt="Chromatic Aberration" onclick="openLb(this)"><div class="img-meta"><h3>Chromatic Aberration</h3><p>Offsets the R, G and B colour channels by slightly different amounts in screen space, creating colour fringing at high-contrast edges. Mimics cheap, damaged or fisheye camera lenses. A staple of lo-fi, retro, horror and vaporwave aesthetics. Subtle amounts add believable lens character.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/10l_pixel_retro.webp" alt="Pixel Retro" onclick="openLb(this)"><div class="img-meta"><h3>Pixel / Retro Effect</h3><p>Renders the scene at a low resolution (e.g. 320×240) then upscales with nearest-neighbour filtering. The result looks like an old video game - blocky pixels, visible colour banding. RenderPixelatedPass in Three.js. Combine with a dithering shader and limited colour palette for a full Game Boy or NES aesthetic.</p></div></div>
<!-- ══════════════════════════════════════════════
11 - CONTROLS
══════════════════════════════════════════════ -->
<div class="section-break" id="controls">
<div class="section-break-header">
<span class="section-num bg">11</span>
<h2 style="color:var(--green)">Controls</h2>
</div>
<p class="section-intro">Controls translate user input (mouse, keyboard, touch, gamepad) into camera or object movement. Three.js ships 8+ control types in the addons (<code>jsm/controls/</code>). The right choice depends entirely on the use case - don't use OrbitControls for an FPS game, don't use PointerLockControls for a 3D product viewer.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#examples/en/controls/OrbitControls" target="_blank" class="doc-link">↗ OrbitControls</a>
<a href="https://threejs.org/docs/#examples/en/controls/TransformControls" target="_blank" class="doc-link">↗ TransformControls</a>
<a href="https://threejs.org/docs/#examples/en/controls/PointerLockControls" target="_blank" class="doc-link">↗ PointerLockControls</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/11a_orbit_controls.webp" alt="OrbitControls" onclick="openLb(this)"><div class="img-meta"><h3>OrbitControls - Camera Around Target</h3><p>The default for 3D model viewers and product configurators. Left-drag orbits, right-drag pans, scroll zooms. Set <code>target</code> to the point the camera orbits around. <code>enableDamping=true</code> adds smooth deceleration. <code>autoRotate</code> for hands-free spinning displays.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/11b_first_person_controls.webp" alt="FirstPersonControls" onclick="openLb(this)"><div class="img-meta"><h3>FirstPersonControls - WASD + Mouse Look</h3><p>WASD movement through the scene, mouse movement rotates the view. Camera can move through the scene freely (no collision). Note: PointerLockControls is preferred for games as it locks/hides the cursor. FirstPersonControls is better for architectural walk-throughs where you still want a visible cursor.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/11c_fly_controls.webp" alt="FlyControls" onclick="openLb(this)"><div class="img-meta"><h3>FlyControls - 6 Degrees of Freedom</h3><p>Full 6DOF flight - move forward/back, strafe left/right, ascend/descend, yaw, pitch, roll. No ground plane constraint. Ideal for space games, drone simulators, and exploring large 3D environments from any angle. Use <code>movementSpeed</code> and <code>rollSpeed</code> to tune feel.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/11d_map_controls.webp" alt="MapControls" onclick="openLb(this)"><div class="img-meta"><h3>MapControls - Top-Down Map</h3><p>Variant of OrbitControls optimised for top-down map navigation. Right-drag rotates, left-drag pans the ground plane, scroll zooms. The camera always points roughly downward. Perfect for strategy games, GIS applications, city planners and data visualisation maps.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/11e_transform_controls.webp" alt="TransformControls" onclick="openLb(this)"><div class="img-meta"><h3>TransformControls - 3D Object Gizmo</h3><p>Attach to any Object3D to show a manipulator gizmo - arrows for translation, rings for rotation, handles for scale. Press T/R/S to switch modes. Drag axes to constrain to a single axis. Essential for any in-browser 3D editor or level editor. Fire <code>objectChange</code> event to react to modifications.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/11f_pointer_lock_controls.webp" alt="PointerLockControls" onclick="openLb(this)"><div class="img-meta"><h3>PointerLockControls - FPS Camera</h3><p>Locks and hides the mouse cursor (browser Pointer Lock API). All mouse delta movement directly rotates the camera - no cursor visible, no screen edge limits. Call <code>controls.lock()</code> on a user click gesture. Standard for first-person games. Combine with WASD keyboard handler for full FPS controls.</p></div></div>
<!-- ══════════════════════════════════════════════
12 - NODE / TSL
══════════════════════════════════════════════ -->
<div class="section-break" id="tsl">
<div class="section-break-header">
<span class="section-num bc">12</span>
<h2 style="color:var(--cyan)">Node System / TSL - Three Shading Language</h2>
</div>
<p class="section-intro">TSL is Three.js's shader authoring system written entirely in JavaScript. Instead of writing GLSL strings, you compose shader graphs from function nodes - <code>color()</code>, <code>texture()</code>, <code>add()</code>, <code>normalMap()</code>, <code>noise()</code> - and TSL compiles them to GLSL for WebGL or WGSL for WebGPU automatically. No raw shader strings, no manual uniform management, no platform-specific code.</p>
<div class="section-links">
<a href="https://github.com/mrdoob/three.js/wiki/Three.js-Shading-Language" target="_blank" class="doc-link">↗ TSL Wiki</a>
<a href="https://threejs.org/docs/#api/en/materials/NodeMaterial" target="_blank" class="doc-link">↗ NodeMaterial</a>
<a href="https://threejs.org/examples/#webgpu_tsl_editor" target="_blank" class="doc-link">↗ TSL Live Editor</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/12a_tsl_concept.webp" alt="TSL Concept" onclick="openLb(this)"><div class="img-meta"><h3>What is TSL?</h3><p>Write shaders in JavaScript, run on GPU. Assign any node expression to material properties: <code>material.colorNode</code>, <code>material.emissiveNode</code>, <code>material.positionNode</code>. The node graph compiles to the correct shader language at runtime.</p><div class="code-snippet"><span class="kw">import</span> { color, texture, mix, uv, time } <span class="kw">from</span> <span class="str">'three/tsl'</span>;<br><span class="kw">const</span> mat = <span class="kw">new</span> <span class="fn">MeshStandardNodeMaterial</span>();<br>mat.colorNode = <span class="fn">mix</span>( <span class="fn">color</span>(<span class="str">0xff0000</span>), <span class="fn">color</span>(<span class="str">0x0000ff</span>), <span class="fn">sin</span>( time ) );</div></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12b_noise_functions.webp" alt="Noise Functions" onclick="openLb(this)"><div class="img-meta"><h3>Noise Functions</h3><p>TSL includes several GPU noise functions: <code>mx_noise_float()</code> for Perlin-style smooth noise, <code>mx_worley_noise()</code> for cellular/Voronoi patterns, <code>checker()</code>, <code>mx_fractal_noise()</code> for fBm (fractal Brownian motion). All run on GPU - perfect for animated terrain, clouds, fire, water, procedural textures.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12c_tsl_math_ops.webp" alt="TSL Math Operations" onclick="openLb(this)"><div class="img-meta"><h3>Math Operations in TSL</h3><p>All standard shader math functions available as TSL nodes: <code>add()</code>, <code>sub()</code>, <code>mul()</code>, <code>div()</code>, <code>mix()</code>, <code>clamp()</code>, <code>smoothstep()</code>, <code>pow()</code>, <code>abs()</code>, <code>sin()</code>, <code>cos()</code>, <code>floor()</code>, <code>fract()</code>, <code>length()</code>, <code>dot()</code>, <code>cross()</code>, <code>normalize()</code>. Chain them to build any mathematical shader effect.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12d_tsl_fresnel.webp" alt="Fresnel" onclick="openLb(this)"><div class="img-meta"><h3>Fresnel / Rim Lighting</h3><p>The Fresnel effect: surfaces become more reflective at glancing angles (edge of a sphere vs centre). Water, glass, car paint, skin all exhibit this. In TSL: <code>fresnel()</code> outputs 0 at the centre (facing camera) and 1 at the edge. Mix it into emissive or colour for rim glow effects.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12e_tsl_displacement.webp" alt="Displacement" onclick="openLb(this)"><div class="img-meta"><h3>Vertex Displacement</h3><p>Assign a TSL expression to <code>material.positionNode</code> to move vertices in the vertex shader. Animate terrain from a heightmap, make ocean waves from sine functions, breathe life into characters, create plasma sphere effects - all on GPU with zero CPU overhead.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12f_tsl_triplanar.webp" alt="Triplanar" onclick="openLb(this)"><div class="img-meta"><h3>Triplanar Mapping</h3><p>Projects a texture from X, Y and Z axes simultaneously and blends them based on the surface normal. The result: any shape gets correctly textured without UV unwrapping. <code>triplanarTexture()</code> in TSL. Essential for terrain, caves, organic shapes and anything where UV mapping is impractical.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12g_tsl_pbr_breakdown.webp" alt="PBR Node Breakdown" onclick="openLb(this)"><div class="img-meta"><h3>PBR Node Breakdown</h3><p>How TSL texture nodes wire into a full PBR material: <code>texture(albedoMap)</code> → <code>colorNode</code>, <code>normalMap(normalTex)</code> → <code>normalNode</code>, <code>texture(roughTex).r</code> → <code>roughnessNode</code>, <code>texture(metalTex).b</code> → <code>metalnessNode</code>. Each property accepts any node expression.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12h_tsl_gpgpu.webp" alt="GPGPU" onclick="openLb(this)"><div class="img-meta"><h3>GPGPU - GPU Particle Simulation</h3><p>Use <code>compute()</code> nodes (WebGPU only) to simulate millions of particles entirely on the GPU. Each particle's position and velocity is stored in a storage buffer. The compute shader updates all particles in parallel. Results feed directly into InstancedMesh matrices - no CPU data transfer each frame.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12i_tsl_procedural.webp" alt="Procedural Shaders" onclick="openLb(this)"><div class="img-meta"><h3>Procedural Shaders</h3><p>Generate every pixel purely from mathematics - no textures, no files, no loading time. Checkerboard, gradient, polar coordinates, mandelbrot, voronoi, plasma, sine wave patterns. All computed per-pixel at 60fps on GPU. Combine noise + trig functions for infinite detail at any scale.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/12j_tsl_custom_shader.webp" alt="Custom Shader" onclick="openLb(this)"><div class="img-meta"><h3>Custom Shader - Full Creative Control</h3><p>Assign any TSL expression to any material property. Combine noise, math, time, UV coordinates and texture samples in any way you imagine. Or use raw ShaderMaterial/RawShaderMaterial with hand-written GLSL for absolute control. This is where Three.js becomes a creative coding environment.</p></div></div>
<!-- ══════════════════════════════════════════════
13 - ANIMATION
══════════════════════════════════════════════ -->
<div class="section-break" id="animation">
<div class="section-break-header">
<span class="section-num ba">13</span>
<h2 style="color:var(--amber)">Animation</h2>
</div>
<p class="section-intro">Three.js includes a complete keyframe animation system. AnimationClip stores named tracks of keyframed values. AnimationMixer plays clips on an object, handling speed, looping, blending and crossfading between multiple clips. Used for everything from a spinning cube to fully rigged character animation.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/animation/AnimationMixer" target="_blank" class="doc-link">↗ AnimationMixer</a>
<a href="https://threejs.org/docs/#api/en/animation/AnimationClip" target="_blank" class="doc-link">↗ AnimationClip</a>
<a href="https://threejs.org/docs/#api/en/objects/SkinnedMesh" target="_blank" class="doc-link">↗ SkinnedMesh</a>
<a href="https://threejs.org/docs/#api/en/animation/AnimationAction" target="_blank" class="doc-link">↗ AnimationAction</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/13a_keyframes.webp" alt="Keyframes" onclick="openLb(this)"><div class="img-meta"><h3>Keyframes & Tracks</h3><p>A KeyframeTrack stores the property name (<code>.position[x]</code>), an array of times (seconds), and an array of values. Multiple tracks form an AnimationClip. The interpolant (linear, smooth cubic, or discrete step) fills values between keyframes. Any Object3D property can be animated: position, rotation, scale, material colour, morph weight.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13b_walk_cycle.webp" alt="Walk Cycle" onclick="openLb(this)"><div class="img-meta"><h3>Walk Cycle</h3><p>~8 key poses timed so the last frame flows back into the first. The mixer loops the clip and the character walks indefinitely. Walk cycles are the foundation of character animation - everything else (run, jump, combat) layers on top or crossfades from it.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13c_blend_crossfade.webp" alt="Blend / Crossfade" onclick="openLb(this)"><div class="img-meta"><h3>Blend & Crossfade</h3><p>AnimationMixer blends multiple simultaneous actions by their <code>weight</code> property. <code>action.crossFadeTo(otherAction, duration)</code> smoothly transitions weight from one clip to another over the duration - walk smoothly becomes run, idle flows into attack, land fades from falling.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13d_morph_targets.webp" alt="Morph Targets" onclick="openLb(this)"><div class="img-meta"><h3>Morph Targets - Blend Shapes</h3><p>Pre-baked vertex positions stored in geometry. <code>mesh.morphTargetInfluences[i] = 0..1</code> blends between base geometry and a target shape. Blend multiple targets simultaneously. Used for facial expressions, lip-sync, secondary deformations, and smooth shape transformations. Common in glTF character files.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13e_skeletal_animation.webp" alt="Skeletal Animation" onclick="openLb(this)"><div class="img-meta"><h3>Skeletal Animation - Bone Rigs</h3><p>A Skeleton is a hierarchy of Bone objects (Object3Ds). Each vertex in the SkinnedMesh is influenced by 1–4 bones with blend weights (stored as <code>skinIndex</code> and <code>skinWeight</code> attributes). Move/rotate bones and the mesh follows. The complete character animation pipeline used in games.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13f_additive_animation.webp" alt="Additive Animation" onclick="openLb(this)"><div class="img-meta"><h3>Additive Animation</h3><p>An additive layer adds its delta values on top of a base pose instead of replacing it. Set <code>action.blendMode = THREE.AdditiveAnimationBlendMode</code>. Breathing, head-look, flinch reactions and facial emotions can all be independent additive layers playing simultaneously on top of locomotion.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13g_animation_curves.webp" alt="Animation Curves" onclick="openLb(this)"><div class="img-meta"><h3>Animation Curves - Interpolation</h3><p>How values change between keyframes: <strong>InterpolateLinear</strong> (straight line, robotic), <strong>InterpolateSmooth</strong> (cubic Catmull-Rom, natural), <strong>InterpolateDiscrete</strong> (instant step, snappy). Ease-in/ease-out curves make animations feel physical - things accelerate and decelerate rather than moving at constant speed.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/13h_animation_mixer_concept.webp" alt="AnimationMixer" onclick="openLb(this)"><div class="img-meta"><h3>AnimationMixer Concept</h3><p>One mixer per animated object. <code>mixer.clipAction(clip)</code> returns an AnimationAction. Set <code>action.play()</code>, <code>action.weight</code> (blend amount), <code>action.timeScale</code> (speed). Call <code>mixer.update(delta)</code> every frame in the render loop. Multiple actions blend automatically by their weights.</p></div></div>
<!-- ══════════════════════════════════════════════
14 - AUDIO
══════════════════════════════════════════════ -->
<div class="section-break" id="audio">
<div class="section-break-header">
<span class="section-num bm">14</span>
<h2 style="color:var(--magenta)">Audio</h2>
</div>
<p class="section-intro">Three.js integrates the Web Audio API into the scene graph. AudioListener attaches to the camera and acts as the player's ears. PositionalAudio attaches to 3D objects and automatically adjusts volume and stereo panning based on distance and angle from the listener - walk towards an explosion and it gets louder, walk past it and it pans side to side.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#api/en/audio/AudioListener" target="_blank" class="doc-link">↗ AudioListener</a>
<a href="https://threejs.org/docs/#api/en/audio/PositionalAudio" target="_blank" class="doc-link">↗ PositionalAudio</a>
<a href="https://threejs.org/docs/#api/en/audio/AudioAnalyser" target="_blank" class="doc-link">↗ AudioAnalyser</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/14a_spatial_audio.webp" alt="Spatial Audio" onclick="openLb(this)"><div class="img-meta"><h3>Spatial Audio - 3D Positioning</h3><p>AudioListener on the camera = the player's ears. PositionalAudio on a 3D object = a sound source in the world. The Web Audio PannerNode automatically computes volume, left/right panning, and doppler shift from the relative positions and velocities. Walk through a scene and sounds change as expected.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/14b_audio_falloff.webp" alt="Audio Falloff" onclick="openLb(this)"><div class="img-meta"><h3>Audio Falloff - Distance Curves</h3><p><code>rolloffFactor</code> controls how fast volume drops. <code>distanceModel</code>: <strong>linear</strong> (even drop to maxDistance), <strong>inverse</strong> (halves every doubling of distance - physically correct), <strong>exponential</strong> (extreme drop off). <code>refDistance</code> is where attenuation begins; <code>maxDistance</code> is where volume hits 0.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/14c_audio_analyser.webp" alt="AudioAnalyser" onclick="openLb(this)"><div class="img-meta"><h3>AudioAnalyser - Frequency Visualisation</h3><p>Wraps Web Audio's AnalyserNode. Call <code>analyser.getFrequencyData()</code> each frame - returns a Uint8Array of FFT frequency bins from bass to treble. Use those 128/256 values to drive anything: geometry heights, emissive intensity, particle velocities, colour shifts. Music-reactive visuals.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/14d_audio_cones.webp" alt="Audio Cones" onclick="openLb(this)"><div class="img-meta"><h3>Audio Cones - Directional Sound</h3><p>PositionalAudio supports directionality via inner/outer cone angles. <code>coneInnerAngle</code>: full volume zone. <code>coneOuterAngle</code>: transition zone. <code>coneOuterGain</code>: volume at and beyond outer cone. Perfect for NPCs, speakers pointing in a direction, vehicle exhausts, vents.</p></div></div>
<!-- ══════════════════════════════════════════════
15 - SPECIAL OBJECTS
══════════════════════════════════════════════ -->
<div class="section-break" id="special">
<div class="section-break-header">
<span class="section-num bg">15</span>
<h2 style="color:var(--green)">Special Objects & Effects</h2>
</div>
<p class="section-intro">Three.js addons include high-level pre-built objects for visual needs that would take weeks to build from scratch - animated ocean water, procedural sky, real-time mirror reflections, lens flares, HTML elements in 3D space, and GPU-instanced forests. All in <code>jsm/objects/</code> and ready to drop into any scene.</p>
<div class="section-links">
<a href="https://threejs.org/examples/#webgl_shaders_ocean" target="_blank" class="doc-link">↗ Water Example</a>
<a href="https://threejs.org/examples/#webgl_mirror" target="_blank" class="doc-link">↗ Reflector Example</a>
<a href="https://threejs.org/examples/#webgl_instancing_performance" target="_blank" class="doc-link">↗ Instancing Example</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/15a_water.webp" alt="Water" onclick="openLb(this)"><div class="img-meta"><h3>Water - Ocean Surface</h3><p>Animated water surface using two normal map textures scrolling at different speeds and angles for complex wave patterns. Reflects the sky, refracts the scene below, and responds to <code>sunDirection</code> for specular sun glints. Water2 adds more complex dual-normal wave patterns for rivers, pools and oceans.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15b_sky.webp" alt="Sky" onclick="openLb(this)"><div class="img-meta"><h3>Sky - Procedural Preetham Model</h3><p>A physically-based sky shader (Preetham 1999 atmospheric scattering model). Parameters: <code>turbidity</code> (haze), <code>rayleigh</code> (blue sky scattering), <code>mieCoefficient</code>/<code>mieDirectionalG</code> (sun halo size), <code>sunPosition</code>. No textures needed - full dawn-to-dusk cycle in real-time from equations alone.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15c_reflector.webp" alt="Reflector" onclick="openLb(this)"><div class="img-meta"><h3>Reflector - Real-Time Mirror</h3><p>Renders the scene from a reflected camera perspective into a texture, then applies that texture to the reflective plane - a real-time mirror. Used for glossy floors, mirrors, calm water. ReflectorForSSRPass adds screen-space reflections for any surface (not just flat planes).</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15d_lensflare.webp" alt="Lensflare" onclick="openLb(this)"><div class="img-meta"><h3>Lensflare</h3><p>Adds hexagonal aperture flare artefacts along the axis from a bright light to screen centre - mimicking a camera lens. Attach Lensflare to any light/object and add textured flare elements at different screen distances. Occlusion-tested: disappears when the light source is hidden.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15e_css3d.webp" alt="CSS3D" onclick="openLb(this)"><div class="img-meta"><h3>CSS3DObject - HTML Elements in 3D</h3><p>CSS3DRenderer overlays a DOM layer perfectly aligned with the WebGL scene. CSS3DObject wraps any HTML element (including live iframes, video, interactive UI) and positions it in 3D space. The CSS transform matches Three.js camera perspective exactly. Combine with WebGL renderer for mixed HTML/3D experiences.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15f_instancing.webp" alt="Instancing" onclick="openLb(this)"><div class="img-meta"><h3>Instancing - One Draw Call, 100,000 Objects</h3><p>InstancedMesh renders N copies of the same geometry+material in a single GPU draw call. Each instance has its own 4×4 transform matrix (position, rotation, scale) and optional per-instance colour. Rendering a forest of 100,000 trees takes the same CPU time as rendering one tree.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15g_lod.webp" alt="LOD" onclick="openLb(this)"><div class="img-meta"><h3>LOD - Level of Detail</h3><p>LOD.addLevel(mesh, distance) - the closest level shows full detail; as camera distance increases, lower-poly versions swap in automatically. Halving polygon count at double distance maintains visual quality while dramatically reducing GPU load. Essential for open worlds and large scenes.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15h_particles.webp" alt="Particles" onclick="openLb(this)"><div class="img-meta"><h3>Sprite Particles - Points System</h3><p>Points geometry + PointsMaterial renders each vertex as a screen-aligned billboard. <code>size</code> controls point size, <code>sizeAttenuation</code> enables perspective scaling, <code>map</code> applies a texture, <code>vertexColors</code> allows per-particle colour. For millions of particles, use GPU simulation via GPGPU (Section 12h).</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15i_raycaster.webp" alt="Raycaster" onclick="openLb(this)"><div class="img-meta"><h3>Raycaster - Mouse Picking & Interaction</h3><p>Cast a mathematical ray from the camera through the mouse pointer into the scene. <code>raycaster.setFromCamera(pointer, camera)</code> then <code>intersectObjects(meshArray)</code> returns all hit objects sorted by distance, each with exact hit point, normal, UV, and face index. The foundation for all 3D clicking, hovering, and dragging.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/15j_clipping_planes.webp" alt="Clipping Planes" onclick="openLb(this)"><div class="img-meta"><h3>Clipping Planes - Cross-Sections</h3><p>Discard all fragments on one side of a mathematical plane (Plane: normal + constant). <code>renderer.clippingPlanes</code> clips globally. <code>material.clippingPlanes</code> clips per-material. Animate the plane to create a cutting animation. Multiple planes create complex cross-section views - medical, architectural, CAD visualisations.</p></div></div>
<!-- ══════════════════════════════════════════════
16 - LOADERS
══════════════════════════════════════════════ -->
<div class="section-break" id="loaders">
<div class="section-break-header">
<span class="section-num bc">16</span>
<h2 style="color:var(--cyan)">Loaders</h2>
</div>
<p class="section-intro">Loaders import external assets - 3D models, textures, environments. Three.js ships a base Loader class and dozens of format-specific loaders in the addons. Use GLTFLoader for 3D models - it's the "JPEG of 3D", compact and feature-complete. Use LoadingManager to track combined loading progress across all assets.</p>
<div class="section-links">
<a href="https://threejs.org/docs/#examples/en/loaders/GLTFLoader" target="_blank" class="doc-link">↗ GLTFLoader</a>
<a href="https://threejs.org/docs/#examples/en/loaders/DRACOLoader" target="_blank" class="doc-link">↗ DRACOLoader</a>
<a href="https://threejs.org/docs/#api/en/loaders/LoadingManager" target="_blank" class="doc-link">↗ LoadingManager</a>
</div>
</div>
<div class="img-entry"><img data-src="images/encyclopedia/16a_gltf_loader.webp" alt="GLTF Loader" onclick="openLb(this)"><div class="img-meta"><h3>GLTFLoader - The Standard 3D Format</h3><p><code>.gltf</code> (JSON + separate .bin + images) or <code>.glb</code> (single binary bundle). Supports: PBR materials, skeletal animation, morph targets, multiple meshes/scenes, lights, cameras, custom extensions (KHR_draco_mesh_compression, KHR_materials_transmission, EXT_meshopt_compression). The correct default choice for web delivery.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/16b_fbx_loader.webp" alt="FBX Loader" onclick="openLb(this)"><div class="img-meta"><h3>FBXLoader - Autodesk Format</h3><p>Autodesk FBX is common in game pipelines from Maya, 3ds Max, MotionBuilder and game engines like Unity/Unreal (as export format). FBXLoader supports skeletal animation, morph targets, embedded textures. Files tend to be large - prefer exporting to GLTF from DCC tools where possible, using FBX only when needed.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/16c_obj_loader.webp" alt="OBJ Loader" onclick="openLb(this)"><div class="img-meta"><h3>OBJLoader - Universal Legacy Format</h3><p>The most widely supported 3D format - almost every 3D application can export OBJ. Human-readable text format, paired with .mtl for materials (Phong, no PBR). No animation support. Large file sizes. Good for static geometry interchange and legacy assets. Use GLTF for anything new.</p></div></div>
<div class="divider"></div>
<div class="img-entry"><img data-src="images/encyclopedia/16d_draco_compression.webp" alt="Draco Compression" onclick="openLb(this)"><div class="img-meta"><h3>Draco Compression</h3><p>Google's open-source mesh compression codec reduces geometry file size by 50–90% with minimal visual loss. Embed in GLTF via KHR_draco_mesh_compression extension. Requires DRACOLoader with the decoder WASM loaded from a CDN or bundled. Worth the setup cost for bandwidth-critical apps.</p></div></div>