docs: overhaul SVG diagrams and add style guide
authorSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 14 Apr 2026 21:24:33 +0000 (00:24 +0300)
committerSvjatoslav Agejenko <svjatoslav@svjatoslav.eu>
Tue, 14 Apr 2026 21:24:33 +0000 (00:24 +0300)
- Scale all SVG diagrams to larger dimensions (640x480/640x520) for
  improved visibility
- Enhance shading diagrams with detailed annotations: Lambert cosine
  law angle examples, ambient light comparison panels, distance
  attenuation curve plot
- Create doc/style.css and link from all pages to consolidate shared
  SVG theme and responsive media styles
- Remove completed TODO item for coordinate system diagram
- Fix internal link in index.org to use simpler anchor syntax

18 files changed:
TODO.org
doc/coordinate-system.svg
doc/csg/index.org
doc/edge.svg
doc/face-triangle.svg
doc/frustum-culling/index.org
doc/index.org
doc/mesh.svg
doc/normal-vector.svg
doc/perspective-correct-textures/index.org
doc/point3d-vertex.svg
doc/rendering-loop/index.org
doc/shading/ambient-light-comparison.svg
doc/shading/distance-attenuation.svg
doc/shading/index.org
doc/shading/lambert-cosine-law.svg
doc/style.css [new file with mode: 0644]
doc/winding-order.svg

index ca72dc7..2eab58f 100644 (file)
--- a/TODO.org
+++ b/TODO.org
@@ -2,12 +2,6 @@
 :PROPERTIES:
 :CUSTOM_ID: documentation
 :END:
-** Clarify axis orientation (X, Y, Z) for AI assistants and developers
-:PROPERTIES:
-:CUSTOM_ID: clarify-axis-orientation
-:END:
-Add a coordinate system diagram to the documentation.
-
 ** Document shading
 
 Make separate demo about that with shaded spheres and some light
index 2a7eccb..4497bf3 100644 (file)
@@ -1,18 +1,18 @@
-<svg viewBox="0 0 320 260" width="320" height="260">
-  <rect width="320" height="260" fill="#061018"/>
-  <circle cx="140" cy="130" r="5" fill="rgba(0,0,0,0.1)" stroke="rgba(0,0,0,0.2)" stroke-width="1"/>
-  <line x1="140" y1="130" x2="280" y2="130" stroke="#d04040" stroke-width="2.5"/>
-  <polygon points="280,130 270,125 270,135" fill="#d04040"/>
-  <text x="284" y="134" fill="#d04040" font-size="14" font-weight="700" font-family="monospace">X</text>
-  <text x="200" y="152" fill="#bbb" font-size="9" font-family="monospace">right (+) / left (-)</text>
-  <line x1="140" y1="130" x2="140" y2="240" stroke="#30a050" stroke-width="2.5"/>
-  <polygon points="140,240 135,230 145,230" fill="#30a050"/>
-  <text x="146" y="252" fill="#30a050" font-size="14" font-weight="700" font-family="monospace">Y</text>
-  <text x="146" y="228" fill="#bbb" font-size="9" font-family="monospace">down (+) / up (-)</text>
-  <line x1="140" y1="130" x2="60" y2="70" stroke="#2070c0" stroke-width="2.5"/>
-  <polygon points="60,70 70,72 66,82" fill="#2070c0"/>
-  <text x="42" y="62" fill="#2070c0" font-size="14" font-weight="700" font-family="monospace">Z</text>
-  <text x="60" y="56" fill="#bbb" font-size="9" font-family="monospace">away (+) / towards (-)</text>
-  <text x="150" y="102" fill="#aaa" font-size="11" font-weight="600" font-family="monospace">Origin</text>
-  <text x="147" y="115" fill="#bbb" font-size="9" font-family="monospace">(0, 0, 0)</text>
+<svg viewBox="0 0 640 520" width="640" height="520" xmlns="http://www.w3.org/2000/svg">
+  <rect width="640" height="520" fill="#061018"/>
+  <circle cx="280" cy="260" r="10" fill="rgba(80,96,192,0.1)" stroke="rgba(80,96,192,0.3)" stroke-width="2"/>
+  <line x1="280" y1="260" x2="560" y2="260" stroke="#d04040" stroke-width="5"/>
+  <polygon points="560,260 540,250 540,270" fill="#d04040"/>
+  <text x="568" y="268" fill="#d04040" font-size="28" font-weight="700" font-family="monospace">X</text>
+  <text x="400" y="304" fill="#bbb" font-size="18" font-family="monospace">right (+) / left (-)</text>
+  <line x1="280" y1="260" x2="280" y2="480" stroke="#30a050" stroke-width="5"/>
+  <polygon points="280,480 270,460 290,460" fill="#30a050"/>
+  <text x="292" y="504" fill="#30a050" font-size="28" font-weight="700" font-family="monospace">Y</text>
+  <text x="292" y="456" fill="#bbb" font-size="18" font-family="monospace">down (+) / up (-)</text>
+  <line x1="280" y1="260" x2="120" y2="140" stroke="#2070c0" stroke-width="5"/>
+  <polygon points="120,140 140,144 132,164" fill="#2070c0"/>
+  <text x="84" y="124" fill="#2070c0" font-size="28" font-weight="700" font-family="monospace">Z</text>
+  <text x="120" y="112" fill="#bbb" font-size="18" font-family="monospace">away (+) / towards (-)</text>
+  <text x="300" y="204" fill="#aaa" font-size="22" font-weight="600" font-family="monospace">Origin</text>
+  <text x="294" y="230" fill="#bbb" font-size="18" font-family="monospace">(0, 0, 0)</text>
 </svg>
\ No newline at end of file
index b128990..9428c94 100644 (file)
@@ -8,39 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-  /* === SVG diagram theme === */
-  svg > rect:first-child {
-    fill:  #061018;
-  }
-
-  /* Lighten axis/helper labels that were dark-on-light */
-  svg text[fill="#666"],
-  svg text[fill="#999"] {
-    fill: #aaa !important;
-  }
-
-  /* Lighten dashed axis lines */
-  svg line[stroke="#ccc"] {
-    stroke: #445566 !important;
-  }
-
-</style>
-#+end_export
+#+HTML_HEAD: <link rel="stylesheet" href="../style.css"/>
 
 [[file:../index.org][Back to main documentation]]
 
index 3ef023e..e9af1cf 100644 (file)
@@ -1,12 +1,12 @@
-<svg viewBox="0 0 320 240" width="320" height="240">
-  <rect width="320" height="240" fill="#061018"/>
-  <polygon points="160,50 80,190 240,190" fill="rgba(100,100,200,0.04)" stroke="rgba(100,100,200,0.2)" stroke-width="1"/>
-  <line x1="160" y1="50" x2="240" y2="190" stroke="#5060c0" stroke-width="3" stroke-linecap="round"/>
-  <circle cx="160" cy="50" r="5" fill="#5060c0"/>
-  <circle cx="80" cy="190" r="4" fill="rgba(80,96,192,0.5)"/>
-  <circle cx="240" cy="190" r="5" fill="#5060c0"/>
-  <text x="150" y="40" fill="#aaa" font-size="10" font-family="monospace">V₁</text>
-  <text x="246" y="194" fill="#aaa" font-size="10" font-family="monospace">V₂</text>
-  <text x="60" y="200" fill="#bbb" font-size="10" font-family="monospace">V₃</text>
-  <text x="210" y="110" fill="#5060c0" font-size="12" font-weight="700" font-family="monospace" transform="rotate(30 210 110)">edge</text>
+<svg viewBox="0 0 640 480" width="640" height="480" xmlns="http://www.w3.org/2000/svg">
+  <rect width="640" height="480" fill="#061018"/>
+  <polygon points="320,100 160,380 480,380" fill="rgba(100,100,200,0.04)" stroke="rgba(100,100,200,0.2)" stroke-width="2"/>
+  <line x1="320" y1="100" x2="480" y2="380" stroke="#5060c0" stroke-width="6" stroke-linecap="round"/>
+  <circle cx="320" cy="100" r="10" fill="#5060c0"/>
+  <circle cx="160" cy="380" r="8" fill="rgba(80,96,192,0.5)"/>
+  <circle cx="480" cy="380" r="10" fill="#5060c0"/>
+  <text x="300" y="80" fill="#aaa" font-size="20" font-family="monospace">V₁</text>
+  <text x="492" y="388" fill="#aaa" font-size="20" font-family="monospace">V₂</text>
+  <text x="120" y="400" fill="#bbb" font-size="20" font-family="monospace">V₃</text>
+  <text x="420" y="220" fill="#5060c0" font-size="24" font-weight="700" font-family="monospace" transform="rotate(30 420 220)">edge</text>
 </svg>
index 8e8eb13..509c841 100644 (file)
@@ -1,14 +1,14 @@
-<svg viewBox="0 0 320 240" width="320" height="240">
-  <rect width="320" height="240" fill="#061018"/>
-  <polygon points="160,40 60,200 260,200" fill="rgba(200,80,140,0.15)" stroke="#c05088" stroke-width="1.5"/>
-  <line x1="100" y1="140" x2="220" y2="140" stroke="rgba(200,80,140,0.1)" stroke-width="0.5"/>
-  <line x1="120" y1="160" x2="200" y2="160" stroke="rgba(200,80,140,0.08)" stroke-width="0.5"/>
-  <line x1="82" y1="180" x2="238" y2="180" stroke="rgba(200,80,140,0.06)" stroke-width="0.5"/>
-  <circle cx="160" cy="40" r="4" fill="#c05088"/>
-  <circle cx="60" cy="200" r="4" fill="#c05088"/>
-  <circle cx="260" cy="200" r="4" fill="#c05088"/>
-  <text x="148" y="30" fill="#c05088" font-size="10" font-weight="700" font-family="monospace">V₁</text>
-  <text x="38" y="210" fill="#c05088" font-size="10" font-weight="700" font-family="monospace">V₂</text>
-  <text x="266" y="210" fill="#c05088" font-size="10" font-weight="700" font-family="monospace">V₃</text>
-  <text x="132" y="150" fill="rgba(192,80,136,0.5)" font-size="14" font-weight="700" font-family="monospace">FACE</text>
+<svg viewBox="0 0 640 480" width="640" height="480" xmlns="http://www.w3.org/2000/svg">
+  <rect width="640" height="480" fill="#061018"/>
+  <polygon points="320,80 120,400 520,400" fill="rgba(200,80,140,0.15)" stroke="#c05088" stroke-width="3"/>
+  <line x1="200" y1="280" x2="440" y2="280" stroke="rgba(200,80,140,0.1)" stroke-width="1"/>
+  <line x1="240" y1="320" x2="400" y2="320" stroke="rgba(200,80,140,0.08)" stroke-width="1"/>
+  <line x1="164" y1="360" x2="476" y2="360" stroke="rgba(200,80,140,0.06)" stroke-width="1"/>
+  <circle cx="320" cy="80" r="8" fill="#c05088"/>
+  <circle cx="120" cy="400" r="8" fill="#c05088"/>
+  <circle cx="520" cy="400" r="8" fill="#c05088"/>
+  <text x="296" y="60" fill="#c05088" font-size="20" font-weight="700" font-family="monospace">V₁</text>
+  <text x="76" y="420" fill="#c05088" font-size="20" font-weight="700" font-family="monospace">V₂</text>
+  <text x="532" y="420" fill="#c05088" font-size="20" font-weight="700" font-family="monospace">V₃</text>
+  <text x="264" y="300" fill="rgba(192,80,136,0.5)" font-size="28" font-weight="700" font-family="monospace">FACE</text>
 </svg>
index 9bd15aa..b349228 100644 (file)
@@ -8,39 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-  /* === SVG diagram theme === */
-  svg > rect:first-child {
-    fill:  #061018;
-  }
-
-  /* Lighten axis/helper labels that were dark-on-light */
-  svg text[fill="#666"],
-  svg text[fill="#999"] {
-    fill: #aaa !important;
-  }
-
-  /* Lighten dashed axis lines */
-  svg line[stroke="#ccc"] {
-    stroke: #445566 !important;
-  }
-
-</style>
-#+end_export
+#+HTML_HEAD: <link rel="stylesheet" href="../style.css"/>
 
 [[file:../index.org][Back to main documentation]]
 
index 181fc4f..0043675 100644 (file)
@@ -8,57 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;            /* activate flexbox */
-    justify-content: center;  /* horizontally center anything inside   */
-  }
-
-  .flex-center video {
-    width: min(90%, 1000px); /* whichever is smaller wins */
-    height: auto;            /* preserve aspect ratio */
-  }
-
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-
-  /* === SVG diagram theme === */
-  svg > rect:first-child {
-    fill:  #061018;
-  }
-
-  /* Lighten axis/helper labels that were dark-on-light */
-  svg text[fill="#666"],
-  svg text[fill="#999"] {
-    fill: #aaa !important;
-  }
-
-  /* Lighten dashed axis lines */
-  svg line[stroke="#ccc"] {
-    stroke: #445566 !important;
-  }
-
-</style>
-#+end_export
-
+#+HTML_HEAD: <link rel="stylesheet" href="style.css"/>
 
 * Introduction
 :PROPERTIES:
@@ -139,7 +89,7 @@ Also add the repository (the library is not on Maven Central):
   [[https://www3.svjatoslav.eu/projects/sixth-3d-demos/#minimal-example][minimal example]] to see the basic boilerplate needed to render a 3D
   scene.
 
-- Study how [[id:4b6c1355-0afe-40c6-86c3-14bf8a11a8d0][Sixth 3D engine]] works.
+- Study [[#defining-scene][how Sixth 3D engine works]].
 - Read online [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/][JavaDoc]].
 - See [[https://www3.svjatoslav.eu/projects/sixth-3d/graphs/][*Sixth 3D* class diagrams]]. (Diagrams were generated by using
   [[https://www3.svjatoslav.eu/projects/javainspect/][JavaInspect]] utility)
index fcca520..8a20f46 100644 (file)
@@ -1,22 +1,22 @@
-<svg viewBox="0 0 320 240" width="320" height="240">
-  <rect width="320" height="240" fill="#061018"/>
-  <ellipse cx="160" cy="120" rx="90" ry="90" fill="none" stroke="rgba(80,96,192,0.1)" stroke-width="0.5"/>
-  <ellipse cx="160" cy="120" rx="90" ry="20" fill="none" stroke="rgba(80,96,192,0.25)" stroke-width="0.8"/>
-  <ellipse cx="160" cy="90" rx="75" ry="16" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="0.6"/>
-  <ellipse cx="160" cy="150" rx="75" ry="16" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="0.6"/>
-  <ellipse cx="160" cy="60" rx="45" ry="10" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="0.5"/>
-  <ellipse cx="160" cy="180" rx="45" ry="10" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="0.5"/>
-  <ellipse cx="160" cy="120" rx="20" ry="90" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="0.6"/>
-  <ellipse cx="160" cy="120" rx="55" ry="90" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="0.5"/>
-  <polygon points="160,30 185,58 140,55" fill="rgba(80,96,192,0.15)" stroke="#5060c0" stroke-width="1"/>
-  <polygon points="185,58 205,88 160,82" fill="rgba(80,96,192,0.1)" stroke="#5060c0" stroke-width="0.8"/>
-  <polygon points="160,82 185,58 140,55" fill="rgba(80,96,192,0.07)" stroke="rgba(80,96,192,0.5)" stroke-width="0.6"/>
-  <circle cx="160" cy="30" r="2.5" fill="#5060c0"/>
-  <circle cx="185" cy="58" r="2.5" fill="#5060c0"/>
-  <circle cx="140" cy="55" r="2.5" fill="#5060c0"/>
-  <circle cx="205" cy="88" r="2.5" fill="#5060c0"/>
-  <circle cx="160" cy="82" r="2.5" fill="#5060c0"/>
-  <text x="218" y="70" fill="#5060c0" font-size="10" font-weight="600" font-family="monospace">triangulated</text>
-  <text x="218" y="82" fill="#5060c0" font-size="10" font-weight="600" font-family="monospace">section</text>
-  <line x1="206" y1="75" x2="214" y2="75" stroke="#5060c0" stroke-width="0.8"/>
+<svg viewBox="0 0 640 480" width="640" height="480" xmlns="http://www.w3.org/2000/svg">
+  <rect width="640" height="480" fill="#061018"/>
+  <ellipse cx="320" cy="240" rx="180" ry="180" fill="none" stroke="rgba(80,96,192,0.1)" stroke-width="1"/>
+  <ellipse cx="320" cy="240" rx="180" ry="40" fill="none" stroke="rgba(80,96,192,0.25)" stroke-width="1.6"/>
+  <ellipse cx="320" cy="180" rx="150" ry="32" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="1.2"/>
+  <ellipse cx="320" cy="300" rx="150" ry="32" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="1.2"/>
+  <ellipse cx="320" cy="120" rx="90" ry="20" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="1"/>
+  <ellipse cx="320" cy="360" rx="90" ry="20" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="1"/>
+  <ellipse cx="320" cy="240" rx="40" ry="180" fill="none" stroke="rgba(80,96,192,0.2)" stroke-width="1.2"/>
+  <ellipse cx="320" cy="240" rx="110" ry="180" fill="none" stroke="rgba(80,96,192,0.15)" stroke-width="1"/>
+  <polygon points="320,60 370,116 280,110" fill="rgba(80,96,192,0.15)" stroke="#5060c0" stroke-width="2"/>
+  <polygon points="370,116 410,176 320,164" fill="rgba(80,96,192,0.1)" stroke="#5060c0" stroke-width="1.6"/>
+  <polygon points="320,164 370,116 280,110" fill="rgba(80,96,192,0.07)" stroke="rgba(80,96,192,0.5)" stroke-width="1.2"/>
+  <circle cx="320" cy="60" r="5" fill="#5060c0"/>
+  <circle cx="370" cy="116" r="5" fill="#5060c0"/>
+  <circle cx="280" cy="110" r="5" fill="#5060c0"/>
+  <circle cx="410" cy="176" r="5" fill="#5060c0"/>
+  <circle cx="320" cy="164" r="5" fill="#5060c0"/>
+  <text x="436" y="140" fill="#5060c0" font-size="20" font-weight="600" font-family="monospace">triangulated</text>
+  <text x="436" y="164" fill="#5060c0" font-size="20" font-weight="600" font-family="monospace">section</text>
+  <line x1="412" y1="150" x2="428" y2="150" stroke="#5060c0" stroke-width="1.6"/>
 </svg>
index ce8aaa1..016136e 100644 (file)
@@ -1,18 +1,18 @@
-<svg viewBox="0 0 320 260" width="320" height="260">
-  <rect width="320" height="260" fill="#061018"/>
-  <polygon points="60,200 160,180 260,200 160,220" fill="rgba(180,150,30,0.1)" stroke="rgba(180,150,30,0.4)" stroke-width="1"/>
-  <line x1="90" y1="198" x2="230" y2="198" stroke="rgba(180,150,30,0.08)" stroke-width="0.5"/>
-  <line x1="110" y1="194" x2="210" y2="194" stroke="rgba(180,150,30,0.06)" stroke-width="0.5"/>
-  <line x1="160" y1="198" x2="160" y2="60" stroke="#b09020" stroke-width="2.5"/>
-  <polygon points="160,60 155,72 165,72" fill="#b09020"/>
-  <path d="M160,198 L160,178 L170,180" fill="none" stroke="rgba(180,150,30,0.5)" stroke-width="1"/>
-  <text x="168" y="56" fill="#b09020" font-size="13" font-weight="700" font-family="monospace">N̂</text>
-  <text x="168" y="72" fill="#bbb" font-size="9" font-family="monospace">unit normal</text>
-  <text x="168" y="86" fill="#bbb" font-size="9" font-family="monospace">(perpendicular</text>
-  <text x="168" y="98" fill="#bbb" font-size="9" font-family="monospace"> to surface)</text>
-  <circle cx="70" cy="60" r="14" fill="rgba(180,150,30,0.08)" stroke="rgba(180,150,30,0.3)" stroke-width="1"/>
-  <circle cx="70" cy="60" r="4" fill="rgba(180,150,30,0.6)"/>
-  <text x="56" y="42" fill="#bbb" font-size="9" font-family="monospace">Light</text>
-  <line x1="80" y1="68" x2="150" y2="170" stroke="rgba(180,150,30,0.2)" stroke-width="1" stroke-dasharray="4 3"/>
-  <text x="82" y="142" fill="rgba(180,150,30,0.5)" font-size="9" font-family="monospace">L · N = brightness</text>
+<svg viewBox="0 0 640 520" width="640" height="520" xmlns="http://www.w3.org/2000/svg">
+  <rect width="640" height="520" fill="#061018"/>
+  <polygon points="120,400 320,360 520,400 320,440" fill="rgba(180,150,30,0.1)" stroke="rgba(180,150,30,0.4)" stroke-width="2"/>
+  <line x1="180" y1="396" x2="460" y2="396" stroke="rgba(180,150,30,0.08)" stroke-width="1"/>
+  <line x1="220" y1="388" x2="420" y2="388" stroke="rgba(180,150,30,0.06)" stroke-width="1"/>
+  <line x1="320" y1="396" x2="320" y2="120" stroke="#b09020" stroke-width="5"/>
+  <polygon points="320,120 310,144 330,144" fill="#b09020"/>
+  <path d="M320,396 L320,356 L340,360" fill="none" stroke="rgba(180,150,30,0.5)" stroke-width="2"/>
+  <text x="336" y="112" fill="#b09020" font-size="26" font-weight="700" font-family="monospace">N̂</text>
+  <text x="336" y="144" fill="#bbb" font-size="18" font-family="monospace">unit normal</text>
+  <text x="336" y="172" fill="#bbb" font-size="18" font-family="monospace">(perpendicular</text>
+  <text x="336" y="196" fill="#bbb" font-size="18" font-family="monospace"> to surface)</text>
+  <circle cx="140" cy="120" r="28" fill="rgba(180,150,30,0.08)" stroke="rgba(180,150,30,0.3)" stroke-width="2"/>
+  <circle cx="140" cy="120" r="8" fill="rgba(180,150,30,0.6)"/>
+  <text x="112" y="84" fill="#bbb" font-size="18" font-family="monospace">Light</text>
+  <line x1="160" y1="136" x2="300" y2="340" stroke="rgba(180,150,30,0.2)" stroke-width="2" stroke-dasharray="8 6"/>
+  <text x="164" y="284" fill="rgba(180,150,30,0.5)" font-size="18" font-family="monospace">L · N = brightness</text>
 </svg>
index a2787ef..1aa4bf8 100644 (file)
@@ -8,39 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-  /* === SVG diagram theme === */
-  svg > rect:first-child {
-    fill:  #061018;
-  }
-
-  /* Lighten axis/helper labels that were dark-on-light */
-  svg text[fill="#666"],
-  svg text[fill="#999"] {
-    fill: #aaa !important;
-  }
-
-  /* Lighten dashed axis lines */
-  svg line[stroke="#ccc"] {
-    stroke: #445566 !important;
-  }
-
-</style>
-#+end_export
+#+HTML_HEAD: <link rel="stylesheet" href="../style.css"/>
 
 [[file:../index.org][Back to main documentation]]
 
index a3e0d16..0954bac 100644 (file)
@@ -1,5 +1,5 @@
-<svg width="100%" viewBox="0 0 680 350" xmlns="http://www.w3.org/2000/svg"><defs><mask id="imagine-text-gaps-eqff6y" maskUnits="userSpaceOnUse"><rect x="0" y="0" width="680" height="350" fill="white"/><rect x="134.36932373046875" y="19.672515869140625" width="71.26135635375977" height="22.184885025024414" fill="black" rx="2"/><rect x="120.89203643798828" y="40.63203048706055" width="98.2159194946289" height="16.12325668334961" fill="black" rx="2"/><rect x="182" y="129.87673950195312" width="78.42510223388672" height="19.42959976196289" fill="black" rx="2"/><rect x="-4.000310796312988" y="66.63202667236328" width="104.23031616210938" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="66.63202667236328" width="62.12955093383789" height="16.12325668334961" fill="black" rx="2"/><rect x="26.07363510131836" y="132.6320343017578" width="44.086368560791016" height="16.12325668334961" fill="black" rx="2"/><rect x="-3.9983373035211116" y="146.6320343017578" width="74.15834045410156" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="140.6320343017578" width="98.2159194946289" height="16.12325668334961" fill="black" rx="2"/><rect x="50.129241943359375" y="198.6320343017578" width="50.10076141357422" height="16.12325668334961" fill="black" rx="2"/><rect x="56.14363479614258" y="212.6320343017578" width="44.086368560791016" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="206.6320343017578" width="74.15834045410156" height="16.12325668334961" fill="black" rx="2"/><rect x="108.86325073242188" y="268.63201904296875" width="122.27349853515625" height="16.12325668334961" fill="black" rx="2"/><rect x="93.82726287841797" y="284.63201904296875" width="152.34547424316406" height="16.12325668334961" fill="black" rx="2"/><rect x="478.88800048828125" y="19.672515869140625" width="62.224021911621094" height="22.184885025024414" fill="black" rx="2"/><rect x="436.83447265625" y="40.63203048706055" width="146.33108520507812" height="16.12325668334961" fill="black" rx="2"/><rect x="414" y="89.52991485595703" width="74.28429412841797" height="17.225370407104492" fill="black" rx="2"/><rect x="544" y="91.18309020996094" width="45.9127311706543" height="15.021142959594727" fill="black" rx="2"/><rect x="352" y="108.28520202636719" width="32.089067459106445" height="13.919028282165527" fill="black" rx="2"/><rect x="402" y="129.52992248535156" width="147.19703674316406" height="17.225370407104492" fill="black" rx="2"/><rect x="402" y="169.52992248535156" width="127.31173706054688" height="17.225370407104492" fill="black" rx="2"/><rect x="402" y="209.52992248535156" width="120.68330383300781" height="17.225370407104492" fill="black" rx="2"/><rect x="594" y="211.18309020996094" width="18.832207679748535" height="15.021142959594727" fill="black" rx="2"/><rect x="402" y="249.52992248535156" width="47.77057647705078" height="17.225370407104492" fill="black" rx="2"/><rect x="473" y="251.18309020996094" width="45.9127311706543" height="15.021142959594727" fill="black" rx="2"/><rect x="612.9194946289062" y="87.18309020996094" width="35.08052062988281" height="15.021142959594727" fill="black" rx="2"/><rect x="607.5033569335938" y="127.18309020996094" width="40.49662780761719" height="15.021142959594727" fill="black" rx="2"/><rect x="612.9194946289062" y="137.18309020996094" width="35.08052062988281" height="15.021142959594727" fill="black" rx="2"/><rect x="629.1677856445312" y="167.18309020996094" width="18.832207679748535" height="15.021142959594727" fill="black" rx="2"/><rect x="607.5033569335938" y="177.18309020996094" width="40.49662780761719" height="15.021142959594727" fill="black" rx="2"/><rect x="647.0900268554688" y="80.28520202636719" width="32.089067459106445" height="13.919028282165527" fill="black" rx="2"/><rect x="647.0900268554688" y="260.2851867675781" width="36.90688133239746" height="13.919028282165527" fill="black" rx="2"/><rect x="385.71209716796875" y="298.63201904296875" width="248.57579040527344" height="16.12325668334961" fill="black" rx="2"/></mask></defs>
-<rect width="680" height="340" rx="8" fill="#061018" style="fill:rgb(6, 16, 24);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<svg width="100%" viewBox="0 0 680 320" xmlns="http://www.w3.org/2000/svg"><rect width="680" height="320" fill="#061018"/><defs><mask id="imagine-text-gaps-eqff6y" maskUnits="userSpaceOnUse"><rect x="0" y="0" width="680" height="350" fill="white"/><rect x="134.36932373046875" y="19.672515869140625" width="71.26135635375977" height="22.184885025024414" fill="black" rx="2"/><rect x="120.89203643798828" y="40.63203048706055" width="98.2159194946289" height="16.12325668334961" fill="black" rx="2"/><rect x="182" y="129.87673950195312" width="78.42510223388672" height="19.42959976196289" fill="black" rx="2"/><rect x="-4.000310796312988" y="66.63202667236328" width="104.23031616210938" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="66.63202667236328" width="62.12955093383789" height="16.12325668334961" fill="black" rx="2"/><rect x="26.07363510131836" y="132.6320343017578" width="44.086368560791016" height="16.12325668334961" fill="black" rx="2"/><rect x="-3.9983373035211116" y="146.6320343017578" width="74.15834045410156" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="140.6320343017578" width="98.2159194946289" height="16.12325668334961" fill="black" rx="2"/><rect x="50.129241943359375" y="198.6320343017578" width="50.10076141357422" height="16.12325668334961" fill="black" rx="2"/><rect x="56.14363479614258" y="212.6320343017578" width="44.086368560791016" height="16.12325668334961" fill="black" rx="2"/><rect x="268" y="206.6320343017578" width="74.15834045410156" height="16.12325668334961" fill="black" rx="2"/><rect x="108.86325073242188" y="268.63201904296875" width="122.27349853515625" height="16.12325668334961" fill="black" rx="2"/><rect x="93.82726287841797" y="284.63201904296875" width="152.34547424316406" height="16.12325668334961" fill="black" rx="2"/><rect x="478.88800048828125" y="19.672515869140625" width="62.224021911621094" height="22.184885025024414" fill="black" rx="2"/><rect x="436.83447265625" y="40.63203048706055" width="146.33108520507812" height="16.12325668334961" fill="black" rx="2"/><rect x="414" y="89.52991485595703" width="74.28429412841797" height="17.225370407104492" fill="black" rx="2"/><rect x="544" y="91.18309020996094" width="45.9127311706543" height="15.021142959594727" fill="black" rx="2"/><rect x="352" y="108.28520202636719" width="32.089067459106445" height="13.919028282165527" fill="black" rx="2"/><rect x="402" y="129.52992248535156" width="147.19703674316406" height="17.225370407104492" fill="black" rx="2"/><rect x="402" y="169.52992248535156" width="127.31173706054688" height="17.225370407104492" fill="black" rx="2"/><rect x="402" y="209.52992248535156" width="120.68330383300781" height="17.225370407104492" fill="black" rx="2"/><rect x="594" y="211.18309020996094" width="18.832207679748535" height="15.021142959594727" fill="black" rx="2"/><rect x="402" y="249.52992248535156" width="47.77057647705078" height="17.225370407104492" fill="black" rx="2"/><rect x="473" y="251.18309020996094" width="45.9127311706543" height="15.021142959594727" fill="black" rx="2"/><rect x="612.9194946289062" y="87.18309020996094" width="35.08052062988281" height="15.021142959594727" fill="black" rx="2"/><rect x="607.5033569335938" y="127.18309020996094" width="40.49662780761719" height="15.021142959594727" fill="black" rx="2"/><rect x="612.9194946289062" y="137.18309020996094" width="35.08052062988281" height="15.021142959594727" fill="black" rx="2"/><rect x="629.1677856445312" y="167.18309020996094" width="18.832207679748535" height="15.021142959594727" fill="black" rx="2"/><rect x="607.5033569335938" y="177.18309020996094" width="40.49662780761719" height="15.021142959594727" fill="black" rx="2"/><rect x="647.0900268554688" y="80.28520202636719" width="32.089067459106445" height="13.919028282165527" fill="black" rx="2"/><rect x="647.0900268554688" y="260.2851867675781" width="36.90688133239746" height="13.919028282165527" fill="black" rx="2"/><rect x="385.71209716796875" y="298.63201904296875" width="248.57579040527344" height="16.12325668334961" fill="black" rx="2"/></mask></defs>
+
 
 <!-- Divider -->
 <line x1="340" y1="30" x2="340" y2="310" stroke="#1a2a38" stroke-width="1" mask="url(#imagine-text-gaps-eqff6y)" style="fill:rgb(0, 0, 0);stroke:rgb(26, 42, 56);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
index 1da5809..b671ad2 100644 (file)
@@ -8,22 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-</style>
-#+end_export
+#+HTML_HEAD: <link rel="stylesheet" href="../style.css"/>
 
 [[file:../index.org][Back to main documentation]]
 
index 9e2f058..ce07a00 100644 (file)
@@ -1,21 +1,51 @@
-<svg viewBox="0 0 320 140" width="320" height="140" xmlns="http://www.w3.org/2000/svg">
-  <rect width="320" height="140" fill="#061018"/>
+<svg viewBox="0 0 640 290" width="640" height="290" xmlns="http://www.w3.org/2000/svg">
+<defs>
+  <filter id="glows"><feGaussianBlur stdDeviation="1.5" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
+<mask id="imagine-text-gaps-2vose8" maskUnits="userSpaceOnUse"><rect x="0" y="0" width="640" height="290" fill="white"/><rect x="261.183349609375" y="6.583333969116211" width="117.63333129882812" height="20.91666603088379" fill="black" rx="2"/><rect x="110.16667175292969" y="26.25" width="419.6666564941406" height="15.083333015441895" fill="black" rx="2"/><rect x="53.083335876464844" y="223.25" width="83.83333587646484" height="15.083333015441895" fill="black" rx="2"/><rect x="54.900001525878906" y="237.6666717529297" width="80.19999694824219" height="16.25" fill="black" rx="2"/><rect x="35.608333587646484" y="252.4166717529297" width="118.78333282470703" height="13.916666984558105" fill="black" rx="2"/><rect x="257.9583435058594" y="223.25" width="100.08333587646484" height="15.083333015441895" fill="black" rx="2"/><rect x="273.9166564941406" y="237.6666717529297" width="68.16666793823242" height="16.25" fill="black" rx="2"/><rect x="267.875" y="252.4166717529297" width="80.25" height="13.916666984558105" fill="black" rx="2"/><rect x="463.8333435058594" y="223.25" width="116.33333587646484" height="15.083333015441895" fill="black" rx="2"/><rect x="487.9166564941406" y="237.6666717529297" width="68.16666793823242" height="16.25" fill="black" rx="2"/><rect x="477.058349609375" y="252.4166717529297" width="89.88333129882812" height="13.916666984558105" fill="black" rx="2"/><rect x="161.86666870117188" y="267.4166564941406" width="316.26666259765625" height="13.916666984558105" fill="black" rx="2"/></mask></defs>
+<rect width="640" height="280" fill="#061018" style="fill:rgb(6, 16, 24);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
 
-  <!-- Dark polygon without ambient -->
-  <polygon points="40,120 140,120 120,40 80,40"
-           fill="rgba(10,10,10,0.8)" stroke="#555" stroke-width="1"/>
-  <text x="85" y="70" fill="#aaa" font-size="9" font-family="monospace" text-anchor="middle">no ambient</text>
-  <text x="85" y="82" fill="#aaa" font-size="8" font-family="monospace" text-anchor="middle">(pure black)</text>
+<text x="320" y="22" fill="#ccc" font-size="14" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)" style="fill:rgb(204, 204, 204);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:14px;font-weight:700;text-anchor:middle;dominant-baseline:auto">Ambient Light</text>
+<text x="320" y="37" fill="#3a4a5a" font-size="9" font-family="monospace" text-anchor="middle" style="fill:rgb(58, 74, 90);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:9px;font-weight:400;text-anchor:middle;dominant-baseline:auto">base illumination applied to all surfaces equally, regardless of orientation</text>
 
-  <!-- Arrow -->
-  <text x="165" y="75" fill="#30a050" font-size="16" font-family="monospace">→</text>
+<line x1="213" y1="42" x2="213" y2="268" stroke="#0c1a26" stroke-width="1.5" mask="url(#imagine-text-gaps-2vose8)" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="427" y1="42" x2="427" y2="268" stroke="#0c1a26" stroke-width="1.5" mask="url(#imagine-text-gaps-2vose8)" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="5" y1="220" x2="208" y2="220" stroke="#0c1a26" stroke-width="1" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="218" y1="220" x2="422" y2="220" stroke="#0c1a26" stroke-width="1" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="432" y1="220" x2="635" y2="220" stroke="#0c1a26" stroke-width="1" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
 
-  <!-- Lit polygon with ambient -->
-  <polygon points="180,120 280,120 260,40 220,40"
-           fill="rgba(48,160,80,0.15)" stroke="#30a050" stroke-width="1"/>
-  <text x="225" y="70" fill="#30a050" font-size="9" font-family="monospace" text-anchor="middle">ambient</text>
-  <text x="225" y="82" fill="#30a050" font-size="8" font-family="monospace" text-anchor="middle="(50,50,50)"></text>
+<!-- PANEL 1: No ambient -->
+<circle cx="30" cy="57" r="7" fill="rgba(255,102,0,0.45)" stroke="#FF6600" stroke-width="1.5" style="fill:rgba(255, 102, 0, 0.45);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="30" y1="48" x2="30" y2="42" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="37" y1="51" x2="42" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="23" y1="51" x2="18" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="22,82 102,70 102,200 22,212" fill="rgba(48,160,80,0.68)" stroke="#30a050" stroke-width="1.5" style="fill:rgba(48, 160, 80, 0.68);stroke:rgb(48, 160, 80);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="102,70 168,85 168,215 102,200" fill="rgba(5,10,7,0.97)" stroke="#1c2820" stroke-width="1.5" style="fill:rgba(5, 10, 7, 0.97);stroke:rgb(28, 40, 32);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<text x="95" y="234" fill="rgba(208,64,64,0.75)" font-size="9" font-family="monospace" text-anchor="middle" style="fill:rgba(208, 64, 64, 0.75);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:9px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Color(0, 0, 0)</text>
+<text x="95" y="249" fill="rgba(208,64,64,0.9)" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)" style="fill:rgba(208, 64, 64, 0.9);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:10px;font-weight:700;text-anchor:middle;dominant-baseline:auto">✗ pure black</text>
+<text x="95" y="262" fill="#3a4a5a" font-size="8" font-family="monospace" text-anchor="middle" style="fill:rgb(58, 74, 90);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:8px;font-weight:400;text-anchor:middle;dominant-baseline:auto">harsh shadows, no depth</text>
 
-  <!-- Formula -->
-  <text x="160" y="135" fill="#bbb" font-size="9" font-family="monospace" text-anchor="middle">ambient provides base illumination</text>
-</svg>
+<!-- PANEL 2: Default ambient (50,50,50) -->
+<circle cx="243" cy="57" r="7" fill="rgba(255,102,0,0.45)" stroke="#FF6600" stroke-width="1.5" style="fill:rgba(255, 102, 0, 0.45);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="243" y1="48" x2="243" y2="42" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="250" y1="51" x2="255" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="236" y1="51" x2="231" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="235,82 315,70 315,200 235,212" fill="rgba(48,160,80,0.68)" stroke="#30a050" stroke-width="1.5" style="fill:rgba(48, 160, 80, 0.68);stroke:rgb(48, 160, 80);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="315,70 381,85 381,215 315,200" fill="rgba(40,75,46,0.75)" stroke="#285c30" stroke-width="1" style="fill:rgba(40, 75, 46, 0.75);stroke:rgb(40, 92, 48);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<text x="308" y="234" fill="#39FF14" font-size="9" font-family="monospace" text-anchor="middle" style="fill:rgb(57, 255, 20);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:9px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Color(50, 50, 50)</text>
+<text x="308" y="249" fill="#39FF14" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)" style="fill:rgb(57, 255, 20);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:10px;font-weight:700;text-anchor:middle;dominant-baseline:auto">✓ balanced</text>
+<text x="308" y="262" fill="#3a4a5a" font-size="8" font-family="monospace" text-anchor="middle" style="fill:rgb(58, 74, 90);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:8px;font-weight:400;text-anchor:middle;dominant-baseline:auto">depth preserved</text>
+
+<!-- PANEL 3: Too much ambient (150,150,150) -->
+<circle cx="457" cy="57" r="7" fill="rgba(255,102,0,0.45)" stroke="#FF6600" stroke-width="1.5" style="fill:rgba(255, 102, 0, 0.45);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="457" y1="48" x2="457" y2="42" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="464" y1="51" x2="469" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<line x1="450" y1="51" x2="445" y2="46" stroke="#FF6600" stroke-width="1.1" opacity="0.6" style="fill:rgb(0, 0, 0);stroke:rgb(255, 102, 0);color:rgb(251, 251, 254);stroke-width:1.1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:0.6;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="449,82 529,70 529,200 449,212" fill="rgba(48,160,80,0.68)" stroke="#30a050" stroke-width="1.5" style="fill:rgba(48, 160, 80, 0.68);stroke:rgb(48, 160, 80);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<polygon points="529,70 595,85 595,215 529,200" fill="rgba(85,145,92,0.72)" stroke="#30a050" stroke-width="1.5" style="fill:rgba(85, 145, 92, 0.72);stroke:rgb(48, 160, 80);color:rgb(251, 251, 254);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<text x="522" y="234" fill="#FF6600" font-size="9" font-family="monospace" text-anchor="middle" style="fill:rgb(255, 102, 0);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:9px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Color(150, 150, 150)</text>
+<text x="522" y="249" fill="#FF6600" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)" style="fill:rgb(255, 102, 0);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:10px;font-weight:700;text-anchor:middle;dominant-baseline:auto">✗ too flat</text>
+<text x="522" y="262" fill="#3a4a5a" font-size="8" font-family="monospace" text-anchor="middle" style="fill:rgb(58, 74, 90);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:8px;font-weight:400;text-anchor:middle;dominant-baseline:auto">no depth contrast</text>
+
+<line x1="20" y1="268" x2="620" y2="268" stroke="#0c1a26" stroke-width="1" mask="url(#imagine-text-gaps-2vose8)" style="fill:rgb(0, 0, 0);stroke:rgb(12, 26, 38);color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
+<text x="320" y="277" fill="#2a3a4a" font-size="8" font-family="monospace" text-anchor="middle" style="fill:rgb(42, 58, 74);stroke:none;color:rgb(251, 251, 254);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:monospace;font-size:8px;font-weight:400;text-anchor:middle;dominant-baseline:auto">lightingManager.setAmbientLight(new Color(50, 50, 50))  ←  default</text>
+</svg>
\ No newline at end of file
index a50c8df..e4f6543 100644 (file)
@@ -1,35 +1,91 @@
-<svg viewBox="0 0 520 180" width="520" height="180" xmlns="http://www.w3.org/2000/svg">
-  <rect width="520" height="180" fill="#061018"/>
-
-  <!-- Light source -->
-  <circle cx="80" cy="90" r="10" fill="rgba(255,102,0,0.3)" stroke="#FF6600" stroke-width="2"/>
-  <text x="92" y="94" fill="#FF6600" font-size="11" font-weight="700" font-family="monospace">Light</text>
-
-  <!-- Distance markers -->
-  <line x1="80" y1="110" x2="450" y2="110" stroke="#555" stroke-width="1" stroke-dasharray="4 3"/>
-  <text x="180" y="125" fill="#aaa" font-size="8" font-family="monospace" text-anchor="middle">d = 100</text>
-  <text x="330" y="125" fill="#aaa" font-size="8" font-family="monospace" text-anchor="middle">d = 250</text>
-
-  <!-- Polygon at close distance -->
-  <polygon points="160,80 200,80 190,50 170,50"
-           fill="rgba(48,160,80,0.25)" stroke="#30a050" stroke-width="1.5"/>
-  <text x="175" y="72" fill="#30a050" font-size="8" font-weight="600" font-family="monospace">bright</text>
-
-  <!-- Polygon at medium distance -->
-  <polygon points="300,80 340,80 330,50 310,50"
-           fill="rgba(48,160,80,0.12)" stroke="#30a050" stroke-width="1"/>
-  <text x="315" y="72" fill="#30a050" font-size="8" font-family="monospace">medium</text>
-
-  <!-- Polygon at far distance -->
-  <polygon points="420,80 450,80 445,55 425,55"
-           fill="rgba(48,160,80,0.06)" stroke="rgba(48,160,80,0.4)" stroke-width="0.8"/>
-  <text x="433" y="72" fill="rgba(48,160,80,0.6)" font-size="8" font-family="monospace">dim</text>
-
-  <!-- Formula -->
-  <rect x="380" y="135" width="120" height="35" rx="3" fill="rgba(32,112,192,0.1)" stroke="#2070c0" stroke-width="1"/>
-  <text x="390" y="155" fill="#2070c0" font-size="9" font-family="monospace">attenuation =</text>
-  <text x="390" y="167" fill="#2070c0" font-size="9" font-family="monospace">1 / (1 + 0.0001·d²)</text>
-
-  <!-- Explanation -->
-  <text x="260" y="175" fill="#bbb" font-size="9" font-family="monospace" text-anchor="middle">Simplified inverse square law avoids harsh cutoffs</text>
+<svg viewBox="0 0 640 295" width="640" height="295" xmlns="http://www.w3.org/2000/svg">
+<defs>
+  <filter id="glows"><feGaussianBlur stdDeviation="1.5" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
+  <marker id="ax" viewBox="0 0 8 8" refX="7" refY="4" markerWidth="5" markerHeight="5" orient="auto">
+    <path d="M 0 0 L 8 4 L 0 8 z" fill="#3a5060"/>
+  </marker>
+</defs>
+<rect width="640" height="295" fill="#061018"/>
+
+<text x="320" y="22" fill="#ccc" font-size="14" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)">Distance Attenuation</text>
+<text x="320" y="37" fill="#3a4a5a" font-size="9" font-family="monospace" text-anchor="middle">light intensity falls off with distance from source</text>
+
+<line x1="400" y1="45" x2="400" y2="282" stroke="#0c1a26" stroke-width="1.5"/>
+
+<!-- Light source -->
+<circle cx="52" cy="110" r="22" fill="rgba(255,102,0,0.06)"/>
+<circle cx="52" cy="110" r="14" fill="rgba(255,102,0,0.2)" stroke="rgba(255,102,0,0.45)" stroke-width="1.5"/>
+<circle cx="52" cy="110" r="6" fill="rgba(255,102,0,0.7)" stroke="#FF6600" stroke-width="1.5"/>
+<line x1="52" y1="92" x2="52" y2="84" stroke="#FF6600" stroke-width="1.1" opacity="0.55"/>
+<line x1="65" y1="97" x2="72" y2="90" stroke="#FF6600" stroke-width="1.1" opacity="0.55"/>
+<line x1="39" y1="97" x2="32" y2="90" stroke="#FF6600" stroke-width="1.1" opacity="0.55"/>
+<line x1="70" y1="110" x2="78" y2="110" stroke="#FF6600" stroke-width="1.1" opacity="0.55"/>
+<line x1="65" y1="123" x2="72" y2="130" stroke="#FF6600" stroke-width="1.1" opacity="0.55"/>
+<text x="52" y="82" fill="#FF6600" font-size="9" font-weight="700" font-family="monospace" text-anchor="middle">Light</text>
+
+<line x1="52" y1="155" x2="380" y2="155" stroke="#1a2a3a" stroke-width="1" stroke-dasharray="4 3"/>
+
+<!-- Surface d=100, att=0.99 -->
+<line x1="65" y1="110" x2="126" y2="110" stroke="#FF6600" stroke-width="1" stroke-dasharray="4 2" opacity="0.40"/>
+<polygon points="128,77 163,77 158,148 133,148" fill="rgba(48,160,80,0.70)" stroke="#30a050" stroke-width="1.5"/>
+<text x="145" y="65" fill="#30a050" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)">0.99</text>
+<line x1="145" y1="152" x2="145" y2="160" stroke="#2a3a4a" stroke-width="1"/>
+<text x="145" y="172" fill="#555" font-size="8" font-family="monospace" text-anchor="middle">d = 100</text>
+
+<!-- Surface d=300, att=0.52 -->
+<line x1="65" y1="110" x2="223" y2="110" stroke="#FF6600" stroke-width="1" stroke-dasharray="4 2" opacity="0.22"/>
+<polygon points="225,77 259,77 255,148 229,148" fill="rgba(48,160,80,0.36)" stroke="rgba(48,160,80,0.65)" stroke-width="1.2"/>
+<text x="242" y="65" fill="rgba(48,160,80,0.8)" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle">0.52</text>
+<line x1="242" y1="152" x2="242" y2="160" stroke="#2a3a4a" stroke-width="1"/>
+<text x="242" y="172" fill="#555" font-size="8" font-family="monospace" text-anchor="middle">d = 300</text>
+
+<!-- Surface d=500, att=0.29 -->
+<line x1="65" y1="110" x2="316" y2="110" stroke="#FF6600" stroke-width="1" stroke-dasharray="4 2" opacity="0.10"/>
+<polygon points="318,77 352,77 349,148 321,148" fill="rgba(48,160,80,0.18)" stroke="rgba(48,160,80,0.38)" stroke-width="1"/>
+<text x="335" y="65" fill="rgba(48,160,80,0.55)" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle">0.29</text>
+<line x1="335" y1="152" x2="335" y2="160" stroke="#2a3a4a" stroke-width="1"/>
+<text x="335" y="172" fill="#555" font-size="8" font-family="monospace" text-anchor="middle">d = 500</text>
+
+<text x="195" y="192" fill="#2a3a4a" font-size="8" font-family="monospace" text-anchor="middle">← attenuation factor shown above each surface →</text>
+
+<!-- Chart -->
+<text x="513" y="57" fill="#aaa" font-size="9" font-weight="700" font-family="monospace" text-anchor="middle">attenuation vs distance</text>
+<line x1="415" y1="210" x2="630" y2="210" stroke="#2a3a4a" stroke-width="1" marker-end="url(#ax)"/>
+<line x1="415" y1="210" x2="415" y2="67" stroke="#2a3a4a" stroke-width="1" marker-end="url(#ax)"/>
+<text x="622" y="222" fill="#3a5060" font-size="8" font-family="monospace">d</text>
+<text x="408" y="65" fill="#3a5060" font-size="8" font-family="monospace" text-anchor="end">att</text>
+<line x1="411" y1="210" x2="419" y2="210" stroke="#2a3a4a" stroke-width="1"/>
+<text x="408" y="213" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="end">0</text>
+<line x1="411" y1="138" x2="419" y2="138" stroke="#2a3a4a" stroke-width="1"/>
+<line x1="415" y1="138" x2="625" y2="138" stroke="#0d1e2e" stroke-width="1"/>
+<text x="408" y="141" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="end">0.5</text>
+<line x1="411" y1="67" x2="419" y2="67" stroke="#2a3a4a" stroke-width="1"/>
+<line x1="415" y1="67" x2="625" y2="67" stroke="#0d1e2e" stroke-width="1"/>
+<text x="408" y="70" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="end">1.0</text>
+<line x1="450" y1="206" x2="450" y2="214" stroke="#2a3a4a" stroke-width="1"/>
+<line x1="450" y1="67" x2="450" y2="210" stroke="#0d1e2e" stroke-width="1" stroke-dasharray="2 4"/>
+<text x="450" y="222" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="middle">100</text>
+<line x1="520" y1="206" x2="520" y2="214" stroke="#2a3a4a" stroke-width="1"/>
+<line x1="520" y1="67" x2="520" y2="210" stroke="#0d1e2e" stroke-width="1" stroke-dasharray="2 4"/>
+<text x="520" y="222" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="middle">300</text>
+<line x1="590" y1="206" x2="590" y2="214" stroke="#2a3a4a" stroke-width="1"/>
+<line x1="590" y1="67" x2="590" y2="210" stroke="#0d1e2e" stroke-width="1" stroke-dasharray="2 4"/>
+<text x="590" y="222" fill="#3a5060" font-size="7" font-family="monospace" text-anchor="middle">500</text>
+<path d="M 415,67 C 430,67 440,68 450,68 C 468,68 492,100 520,136 C 548,170 575,175 625,178"
+      fill="none" stroke="#FF6600" stroke-width="2" opacity="0.85"/>
+<circle cx="415" cy="67" r="3" fill="#FF6600" opacity="0.70"/>
+<circle cx="450" cy="68" r="3" fill="#FF6600" opacity="0.85"/>
+<circle cx="520" cy="136" r="3" fill="#FF6600" opacity="0.85"/>
+<circle cx="590" cy="169" r="3" fill="#FF6600" opacity="0.85"/>
+<text x="453" y="62" fill="rgba(255,102,0,0.75)" font-size="7" font-family="monospace">0.99</text>
+<text x="523" y="131" fill="rgba(255,102,0,0.75)" font-size="7" font-family="monospace">0.52</text>
+<text x="593" y="164" fill="rgba(255,102,0,0.75)" font-size="7" font-family="monospace">0.29</text>
+
+<!-- Formula box -->
+<rect x="405" y="230" width="225" height="46" rx="4" fill="rgba(32,112,192,0.08)" stroke="#2070c0" stroke-width="1.5"/>
+<text x="517" y="249" fill="#2070c0" font-size="10" font-weight="700" font-family="monospace" text-anchor="middle">attenuation =</text>
+<text x="517" y="267" fill="#2070c0" font-size="11" font-family="monospace" text-anchor="middle">1 / (1 + 0.0001 · d²)</text>
+
+<line x1="20" y1="282" x2="620" y2="282" stroke="#0c1a26" stroke-width="1"/>
+<text x="320" y="291" fill="#2a3a4a" font-size="8" font-family="monospace" text-anchor="middle">coefficient 0.0001 was tuned for typical scene scales in Sixth 3D</text>
 </svg>
index 3f9bab6..3a7c96b 100644 (file)
@@ -8,39 +8,7 @@
 #+OPTIONS: H:20 num:20
 #+OPTIONS: author:nil
 
-#+begin_export html
-<style>
-  .flex-center {
-    display: flex;
-    justify-content: center;
-  }
-  .flex-center video {
-    width: min(90%, 1000px);
-    height: auto;
-  }
-  .responsive-img {
-    width: min(100%, 1000px);
-    height: auto;
-  }
-
-  /* === SVG diagram theme === */
-  svg > rect:first-child {
-    fill:  #061018;
-  }
-
-  /* Lighten axis/helper labels that were dark-on-light */
-  svg text[fill="#666"],
-  svg text[fill="#999"] {
-    fill: #aaa !important;
-  }
-
-  /* Lighten dashed axis lines */
-  svg line[stroke="#ccc"] {
-    stroke: #445566 !important;
-  }
-
-</style>
-#+end_export
+#+HTML_HEAD: <link rel="stylesheet" href="../style.css"/>
 
 [[file:../index.org][Back to main documentation]]
 
 #+attr_latex: :width 1000px
 [[file:Shaded sphere.png]]
 
-*Sixth 3D* implements *flat shading* using the Lambert cosine law. Each
-polygon receives a single color based on its orientation relative to
-light sources. This is a simple yet effective lighting model that gives
-3D objects depth and realism.
+*Sixth 3D* implements *flat shading* using the [[https://en.wikipedia.org/wiki/Lambert%27s_cosine_law][Lambert cosine
+law]]. Each polygon receives a single color based on its orientation
+relative to light sources. This is a simple yet effective lighting
+model that gives 3D objects depth and realism.
 
 ** The Lighting Model: Lambert Cosine Law
 :PROPERTIES:
@@ -65,16 +33,34 @@ light sources. This is a simple yet effective lighting model that gives
 
 #+INCLUDE: "lambert-cosine-law.svg" export html
 
-The *Lambert cosine law* states that the brightness of a surface depends
-on the angle between its normal vector and the light direction:
-
-- Surface facing the light (θ = 0°): maximum brightness (=cos(0°) = 1.0=)
-- Surface at 45° angle: moderate brightness (=cos(45°) = 0.71=)
-- Surface perpendicular to light (θ = 90°): no direct light (=cos(90°) = 0.0=)
-
-This is computed as the *dot product* of the unit normal vector (N̂) and
-unit light direction vector (L̂). The dot product automatically gives the
-cosine of the angle between them.
+The *Lambert cosine law* determines how much light a surface receives
+based on its orientation. A surface facing directly toward a light source
+receives maximum illumination; as it tilts away, the illumination decreases
+proportionally until it reaches zero when perpendicular to the light
+direction. This fundamental principle creates the visual cues that make 3D
+objects appear solid and dimensional rather than flat.
+
+The engine implements this law through the dot product of two vectors. The
+[[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/lighting/LightingManager.html][LightingManager]] computes a unit vector pointing from the polygon's center
+to each [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/lighting/LightSource.html][LightSource]], then calculates the dot product with the surface
+normal. When the dot product equals 1.0, the surface faces the light
+directly and receives full brightness. At 0.71 (a 45-degree angle), it
+receives about 71% illumination. At zero or below, the surface faces away
+from the light and receives no direct contribution from that source. The
+implementation in [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/lighting/LightingManager.html#computeLighting()][LightingManager.computeLighting()]] explicitly checks for
+positive dot products before adding light contributions, ensuring that
+back-facing surfaces skip unnecessary calculations.
+
+The surface normal itself is computed by [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/geometry/Plane.html#computeNormal()][Plane.computeNormal()]], which takes
+the first three vertices of a polygon and calculates their cross product to
+find the perpendicular direction. This normal, along with the polygon's
+center point calculated by [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.html][SolidPolygon]], is passed to the lighting manager
+during the [[file:../rendering-loop/][transform phase]] of the rendering loop. Computing lighting
+during this single-threaded phase ensures thread safety and allows the
+result to be cached in the polygon's reusable [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.html#shadedColor][shadedColor]] field, avoiding
+memory allocation during the subsequent multi-threaded paint phase. See the
+[[file:../index.org::#normal-vector][Normal Vector]] section for more details on how normals are computed and used
+throughout the engine.
 
 ** Light Sources
 :PROPERTIES:
@@ -274,4 +260,4 @@ would be prohibitively expensive.
 | [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/lighting/LightSource.html][LightSource]] | Individual light with position, color, intensity |
 | [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/basic/solidpolygon/SolidPolygon.html][SolidPolygon]] | Polygon shape with shading support |
 | [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/renderer/raster/shapes/composite/base/AbstractCompositeShape.html][AbstractCompositeShape]] | Composite shape with shading propagation |
-| [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/gui/ViewPanel.html][ViewPanel]] | Provides access to LightingManager |
\ No newline at end of file
+| [[https://www3.svjatoslav.eu/projects/sixth-3d/apidocs/eu/svjatoslav/sixth/e3d/gui/ViewPanel.html][ViewPanel]] | Provides access to LightingManager |
index 39d2a2e..1f4e216 100644 (file)
@@ -1,43 +1,92 @@
-<svg viewBox="0 0 520 240" width="520" height="240" xmlns="http://www.w3.org/2000/svg">
-  <defs>
-    <marker id="arrow-light" viewBox="0 0 10 10" refX="10" refY="5"
-            markerWidth="7" markerHeight="7" orient="auto-start-reverse">
-      <path d="M 0 0 L 10 5 L 0 10 z" fill="#FF6600"/>
-    </marker>
-  </defs>
-  <rect width="520" height="240" fill="#061018"/>
-
-  <!-- Polygon surface -->
-  <polygon points="80,180 220,180 180,60 120,60"
-           fill="rgba(48,160,80,0.12)" stroke="#30a050" stroke-width="1.5"/>
-
-  <!-- Normal vector (perpendicular to surface) -->
-  <line x1="150" y1="120" x2="150" y2="40" stroke="#30a050" stroke-width="2.5"/>
-  <polygon points="150,40 145,52 155,52" fill="#30a050"/>
-  <text x="158" y="38" fill="#30a050" font-size="12" font-weight="700" font-family="monospace">N̂</text>
-  <text x="158" y="50" fill="#bbb" font-size="9" font-family="monospace">normal</text>
-
-  <!-- Light source -->
-  <circle cx="350" cy="80" r="12" fill="rgba(255,102,0,0.25)" stroke="#FF6600" stroke-width="2"/>
-  <text x="368" y="84" fill="#FF6600" font-size="11" font-weight="700" font-family="monospace">Light</text>
-
-  <!-- Light direction vector -->
-  <line x1="350" y1="80" x2="170" y2="120" stroke="#FF6600" stroke-width="2" stroke-dasharray="5 3" marker-end="url(#arrow-light)"/>
-  <text x="250" y="92" fill="#FF6600" font-size="10" font-family="monospace" text-anchor="middle">L̂</text>
-
-  <!-- Angle arc between normal and light direction -->
-  <path d="M150,60 A60,60 0 0,1 180,80" fill="none" stroke="#b09020" stroke-width="1.5"/>
-  <text x="182" y="75" fill="#b09020" font-size="10" font-weight="700" font-family="monospace">θ</text>
-
-  <!-- Formula box -->
-  <rect x="380" y="140" width="120" height="80" rx="4" fill="rgba(32,112,192,0.1)" stroke="#2070c0" stroke-width="1"/>
-  <text x="390" y="165" fill="#2070c0" font-size="11" font-weight="700" font-family="monospace">brightness =</text>
-  <text x="390" y="185" fill="#2070c0" font-size="11" font-family="monospace">dot(N̂, L̂)</text>
-  <text x="390" y="205" fill="#bbb" font-size="9" font-family="monospace">= cos(θ)</text>
-
-  <!-- Brightness indicator -->
-  <rect x="80" y="200" width="140" height="20" rx="2" fill="rgba(48,160,80,0.3)" stroke="#30a050" stroke-width="1"/>
-  <rect x="80" y="200" width="85" height="20" rx="2" fill="#30a050"/>
-  <text x="85" y="214" fill="#fff" font-size="9" font-weight="600" font-family="monospace">brightness</text>
-  <text x="232" y="214" fill="#bbb" font-size="9" font-family="monospace">← angle determines intensity</text>
+<svg viewBox="0 0 640 480" width="640" height="480" xmlns="http://www.w3.org/2000/svg">
+<defs>
+  <filter id="glow"><feGaussianBlur stdDeviation="2" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
+  <filter id="glows"><feGaussianBlur stdDeviation="1.5" result="blur"/><feMerge><feMergeNode in="blur"/><feMergeNode in="SourceGraphic"/></feMerge></filter>
+  <marker id="an" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#30a050"/></marker>
+  <marker id="al" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M 0 0 L 10 5 L 0 10 z" fill="#FF6600"/></marker>
+</defs>
+<rect width="640" height="480" fill="#061018"/>
+<text x="320" y="30" fill="#ccc" font-size="17" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)">Lambert Cosine Law</text>
+<text x="320" y="48" fill="#3a4a5a" font-size="10" font-family="monospace" text-anchor="middle">how surface orientation determines light intensity</text>
+<line x1="385" y1="58" x2="385" y2="305" stroke="#0c1a26" stroke-width="1.5"/>
+<line x1="20" y1="308" x2="620" y2="308" stroke="#0c1a26" stroke-width="1.5"/>
+<polygon points="60,275 280,255 295,165 75,185" fill="none" stroke="rgba(48,160,80,0.15)" stroke-width="8"/>
+<polygon points="60,275 280,255 295,165 75,185" fill="rgba(48,160,80,0.13)" stroke="#30a050" stroke-width="2"/>
+<circle cx="178" cy="220" r="4" fill="#30a050"/>
+<line x1="178" y1="220" x2="148" y2="75" stroke="#30a050" stroke-width="2.5" marker-end="url(#an)"/>
+<text x="128" y="70" fill="#30a050" font-size="18" font-weight="700" font-family="monospace" filter="url(#glow)">N̂</text>
+<text x="130" y="84" fill="#aaa" font-size="9" font-family="monospace">normal</text>
+<circle cx="345" cy="85" r="28" fill="rgba(255,102,0,0.06)"/>
+<circle cx="345" cy="85" r="17" fill="rgba(255,102,0,0.2)" stroke="rgba(255,102,0,0.45)" stroke-width="1.5"/>
+<circle cx="345" cy="85" r="7" fill="rgba(255,102,0,0.7)" stroke="#FF6600" stroke-width="1.5"/>
+<line x1="345" y1="62" x2="345" y2="52" stroke="#FF6600" stroke-width="1.2" opacity="0.55"/>
+<line x1="362" y1="67" x2="370" y2="60" stroke="#FF6600" stroke-width="1.2" opacity="0.55"/>
+<line x1="328" y1="67" x2="320" y2="60" stroke="#FF6600" stroke-width="1.2" opacity="0.55"/>
+<line x1="368" y1="85" x2="377" y2="85" stroke="#FF6600" stroke-width="1.2" opacity="0.55"/>
+<line x1="322" y1="85" x2="313" y2="85" stroke="#FF6600" stroke-width="1.2" opacity="0.55"/>
+<text x="370" y="89" fill="#FF6600" font-size="11" font-weight="700" font-family="monospace" text-anchor="start">Light</text>
+<line x1="333" y1="97" x2="185" y2="215" stroke="#FF6600" stroke-width="2" stroke-dasharray="6 3" marker-end="url(#al)"/>
+<text x="274" y="147" fill="#FF6600" font-size="15" font-weight="700" font-family="monospace" filter="url(#glow)">L̂</text>
+<path d="M 167,166 A 55,55 0 0,1 221,185" fill="none" stroke="#b09020" stroke-width="2"/>
+<text x="213" y="160" fill="#b09020" font-size="14" font-weight="700" font-family="monospace" filter="url(#glows)">θ</text>
+<text x="178" y="244" fill="rgba(48,160,80,0.6)" font-size="10" font-family="monospace" text-anchor="middle">surface polygon</text>
+<rect x="398" y="68" width="218" height="105" rx="4" fill="rgba(32,112,192,0.08)" stroke="#2070c0" stroke-width="1.5"/>
+<text x="507" y="93" fill="#2070c0" font-size="12" font-weight="700" font-family="monospace" text-anchor="middle">brightness =</text>
+<text x="507" y="118" fill="#2070c0" font-size="16" font-weight="700" font-family="monospace" text-anchor="middle" filter="url(#glows)">dot( N̂ , L̂ )</text>
+<line x1="408" y1="127" x2="606" y2="127" stroke="#2070c0" stroke-width="1" opacity="0.3"/>
+<text x="507" y="152" fill="#2070c0" font-size="13" font-family="monospace" text-anchor="middle">= cos( θ )</text>
+<rect x="398" y="183" width="218" height="115" rx="4" fill="rgba(80,96,192,0.05)" stroke="rgba(80,96,192,0.4)" stroke-width="1"/>
+<text x="412" y="204" fill="#666" font-size="10" font-family="monospace">θ = 0°</text>
+<rect x="458" y="193" width="80" height="13" rx="2" fill="rgba(57,255,20,0.15)" stroke="#39FF14" stroke-width="1"/>
+<rect x="458" y="193" width="80" height="13" rx="2" fill="rgba(57,255,20,0.7)"/>
+<text x="548" y="204" fill="#39FF14" font-size="10" font-weight="700" font-family="monospace">1.00</text>
+<text x="412" y="225" fill="#666" font-size="10" font-family="monospace">θ = 45°</text>
+<rect x="458" y="214" width="80" height="13" rx="2" fill="rgba(48,160,80,0.08)" stroke="#30a050" stroke-width="1"/>
+<rect x="458" y="214" width="57" height="13" rx="2" fill="rgba(48,160,80,0.55)"/>
+<text x="548" y="225" fill="#bbb" font-size="10" font-family="monospace">0.71</text>
+<text x="412" y="246" fill="#666" font-size="10" font-family="monospace">θ = 90°</text>
+<rect x="458" y="235" width="80" height="13" rx="2" fill="rgba(48,160,80,0.04)" stroke="rgba(48,160,80,0.2)" stroke-width="1"/>
+<text x="548" y="246" fill="#555" font-size="10" font-family="monospace">0.00</text>
+<line x1="408" y1="255" x2="606" y2="255" stroke="rgba(80,96,192,0.3)" stroke-width="1"/>
+<text x="412" y="271" fill="#555" font-size="10" font-family="monospace">θ &gt; 90°</text>
+<text x="460" y="271" fill="rgba(208,64,64,0.75)" font-size="10" font-family="monospace">back-face → skip</text>
+<text x="412" y="287" fill="#3a4a5a" font-size="9" font-family="monospace">dot &lt; 0  →  no contribution</text>
+<text x="320" y="326" fill="#2a3a4a" font-size="10" font-family="monospace" text-anchor="middle">— angle examples —</text>
+<g transform="translate(40,338)">
+  <rect x="10" y="78" width="100" height="13" rx="2" fill="rgba(48,160,80,0.25)" stroke="#30a050" stroke-width="1.5"/>
+  <line x1="60" y1="78" x2="60" y2="32" stroke="#30a050" stroke-width="2" marker-end="url(#an)"/>
+  <circle cx="60" cy="13" r="7" fill="rgba(255,102,0,0.5)" stroke="#FF6600" stroke-width="1.5"/>
+  <line x1="60" y1="20" x2="60" y2="34" stroke="#FF6600" stroke-width="2" marker-end="url(#al)"/>
+  <text x="60" y="103" fill="#39FF14" font-size="11" font-weight="700" font-family="monospace" text-anchor="middle">θ = 0°</text>
+  <rect x="10" y="112" width="100" height="11" rx="2" fill="rgba(48,160,80,0.15)" stroke="#30a050" stroke-width="1"/>
+  <rect x="10" y="112" width="100" height="11" rx="2" fill="#30a050"/>
+  <text x="60" y="121" fill="#061018" font-size="8" font-weight="700" font-family="monospace" text-anchor="middle">100%</text>
+</g>
+<g transform="translate(250,338)">
+  <rect x="10" y="78" width="100" height="13" rx="2" fill="rgba(48,160,80,0.15)" stroke="#30a050" stroke-width="1.5"/>
+  <line x1="60" y1="78" x2="60" y2="32" stroke="#30a050" stroke-width="2" marker-end="url(#an)"/>
+  <circle cx="104" cy="34" r="7" fill="rgba(255,102,0,0.5)" stroke="#FF6600" stroke-width="1.5"/>
+  <line x1="99" y1="39" x2="68" y2="70" stroke="#FF6600" stroke-width="2" marker-end="url(#al)"/>
+  <path d="M 60,50 A 28,28 0 0,1 80,58" fill="none" stroke="#b09020" stroke-width="1.5"/>
+  <text x="83" y="51" fill="#b09020" font-size="9" font-weight="700" font-family="monospace">45°</text>
+  <text x="60" y="103" fill="#bbb" font-size="11" font-weight="700" font-family="monospace" text-anchor="middle">θ = 45°</text>
+  <rect x="10" y="112" width="100" height="11" rx="2" fill="rgba(48,160,80,0.08)" stroke="#30a050" stroke-width="1"/>
+  <rect x="10" y="112" width="71" height="11" rx="2" fill="rgba(48,160,80,0.55)"/>
+  <text x="60" y="121" fill="#ccc" font-size="8" font-weight="700" font-family="monospace" text-anchor="middle">71%</text>
+</g>
+<g transform="translate(462,338)">
+  <rect x="10" y="78" width="100" height="13" rx="2" fill="rgba(208,64,64,0.06)" stroke="rgba(208,64,64,0.4)" stroke-width="1.5" stroke-dasharray="4 3"/>
+  <line x1="60" y1="78" x2="60" y2="32" stroke="#30a050" stroke-width="2" marker-end="url(#an)"/>
+  <circle cx="122" cy="78" r="7" fill="rgba(255,102,0,0.5)" stroke="#FF6600" stroke-width="1.5"/>
+  <line x1="115" y1="78" x2="76" y2="78" stroke="#FF6600" stroke-width="2" marker-end="url(#al)"/>
+  <path d="M 60,50 A 28,28 0 0,1 88,78" fill="none" stroke="#b09020" stroke-width="1.5"/>
+  <text x="80" y="57" fill="#b09020" font-size="9" font-weight="700" font-family="monospace">90°</text>
+  <text x="60" y="103" fill="rgba(208,64,64,0.8)" font-size="11" font-weight="700" font-family="monospace" text-anchor="middle">θ = 90°</text>
+  <rect x="10" y="112" width="100" height="11" rx="2" fill="rgba(208,64,64,0.05)" stroke="rgba(208,64,64,0.4)" stroke-width="1" stroke-dasharray="3 2"/>
+  <text x="60" y="121" fill="rgba(208,64,64,0.7)" font-size="8" font-weight="700" font-family="monospace" text-anchor="middle">0%  (skip)</text>
+</g>
+<line x1="40" y1="472" x2="62" y2="472" stroke="#30a050" stroke-width="2"/>
+<text x="68" y="476" fill="#30a050" font-size="9" font-family="monospace">N̂  surface normal</text>
+<line x1="250" y1="472" x2="272" y2="472" stroke="#FF6600" stroke-width="2" stroke-dasharray="5 2"/>
+<text x="278" y="476" fill="#FF6600" font-size="9" font-family="monospace">L̂  light direction</text>
 </svg>
diff --git a/doc/style.css b/doc/style.css
new file mode 100644 (file)
index 0000000..3403e0e
--- /dev/null
@@ -0,0 +1,35 @@
+.flex-center {
+  display: flex;
+  justify-content: center;
+}
+
+.flex-center video {
+  width: min(90%, 1000px);
+  height: auto;
+}
+
+.responsive-img {
+  width: min(100%, 1000px);
+  height: auto;
+}
+
+/* === SVG diagram theme === */
+svg > rect:first-child {
+  fill: #061018;
+}
+
+svg text[fill="#666"],
+svg text[fill="#999"] {
+  fill: #aaa !important;
+}
+
+svg line[stroke="#ccc"] {
+  stroke: #445566 !important;
+}
+
+svg {
+  background-color: #061018;
+  border-radius: 8px;
+  display: block;
+  margin: 0 auto;
+}
\ No newline at end of file
index 9340194..d82048e 100644 (file)
@@ -1,4 +1,4 @@
-<svg viewBox="0 0 320 240" width="320" height="240">
+<svg viewBox="0 0 640 480" width="640" height="480" xmlns="http://www.w3.org/2000/svg">
   <defs>
     <marker id="arrow-green" viewBox="0 0 10 10" refX="10" refY="5"
             markerWidth="8" markerHeight="8" orient="auto-start-reverse">
@@ -9,26 +9,27 @@
       <path d="M 0 0 L 10 5 L 0 10 z" fill="rgba(208,64,64,0.5)"/>
     </marker>
   </defs>
-  <rect width="320" height="240" fill="#061018"/>
+  <rect width="640" height="480" fill="#061018"/>
+
   <!-- Green front-face triangle: V1=top, V2=bottom-left, V3=bottom-right -->
-  <polygon points="80,50 130,180 30,180" fill="rgba(48,160,80,0.15)" stroke="#30a050" stroke-width="1.5"/>
+  <polygon points="160,100 260,360 60,360" fill="rgba(48,160,80,0.15)" stroke="#30a050" stroke-width="3"/>
   <!-- CCW arrow: arc from near V1, curves LEFT and DOWN toward V2 -->
-  <path d="M70,72 A 52,52 0 0,0 37,155" fill="none" stroke="#30a050" stroke-width="1.5" stroke-dasharray="4 2" marker-end="url(#arrow-green)"/>
-  <text x="34" y="120" fill="#30a050" font-size="10" font-weight="700" font-family="monospace">CCW</text>
-  <circle cx="80" cy="50" r="3" fill="#30a050"/>
-  <circle cx="30" cy="180" r="3" fill="#30a050"/>
-  <circle cx="130" cy="180" r="3" fill="#30a050"/>
-  <text x="78" y="44" fill="#aaa" font-size="9" font-family="monospace">V₁</text>
-  <text x="14" y="198" fill="#aaa" font-size="9" font-family="monospace">V₂</text>
-  <text x="132" y="198" fill="#aaa" font-size="9" font-family="monospace">V₃</text>
-  <text x="36" y="220" fill="#30a050" font-size="11" font-weight="700" font-family="monospace">FRONT FACE ✓</text>
+  <path d="M140,144 A 104,104 0 0,0 74,310" fill="none" stroke="#30a050" stroke-width="3" stroke-dasharray="8 4" marker-end="url(#arrow-green)"/>
+  <text x="68" y="240" fill="#30a050" font-size="20" font-weight="700" font-family="monospace">CCW</text>
+  <circle cx="160" cy="100" r="6" fill="#30a050"/>
+  <circle cx="60" cy="360" r="6" fill="#30a050"/>
+  <circle cx="260" cy="360" r="6" fill="#30a050"/>
+  <text x="156" y="88" fill="#aaa" font-size="18" font-family="monospace">V₁</text>
+  <text x="28" y="396" fill="#aaa" font-size="18" font-family="monospace">V₂</text>
+  <text x="264" y="396" fill="#aaa" font-size="18" font-family="monospace">V₃</text>
+  <text x="72" y="440" fill="#30a050" font-size="22" font-weight="700" font-family="monospace">FRONT FACE ✓</text>
   <!-- Red back-face triangle -->
-  <polygon points="240,50 290,180 190,180" fill="rgba(208,64,64,0.06)" stroke="rgba(208,64,64,0.3)" stroke-width="1.5" stroke-dasharray="6 3"/>
+  <polygon points="480,100 580,360 380,360" fill="rgba(208,64,64,0.06)" stroke="rgba(208,64,64,0.3)" stroke-width="3" stroke-dasharray="12 6"/>
   <!-- CW arrow: arc from near V1, curves RIGHT and DOWN -->
-  <path d="M250,72 A 52,52 0 0,1 283,155" fill="none" stroke="rgba(208,64,64,0.5)" stroke-width="1.5" stroke-dasharray="4 2" marker-end="url(#arrow-red)"/>
-  <text x="268" y="120" fill="rgba(208,64,64,0.6)" font-size="10" font-weight="700" font-family="monospace">CW</text>
-  <line x1="228" y1="108" x2="252" y2="132" stroke="rgba(208,64,64,0.4)" stroke-width="3"/>
-  <line x1="252" y1="108" x2="228" y2="132" stroke="rgba(208,64,64,0.4)" stroke-width="3"/>
-  <text x="186" y="220" fill="rgba(208,64,64,0.7)" font-size="11" font-weight="700" font-family="monospace">BACK FACE ✗</text>
-  <text x="195" y="234" fill="#aaa" font-size="9" font-family="monospace">(culled — not drawn)</text>
+  <path d="M500,144 A 104,104 0 0,1 566,310" fill="none" stroke="rgba(208,64,64,0.5)" stroke-width="3" stroke-dasharray="8 4" marker-end="url(#arrow-red)"/>
+  <text x="536" y="240" fill="rgba(208,64,64,0.6)" font-size="20" font-weight="700" font-family="monospace">CW</text>
+  <line x1="456" y1="216" x2="504" y2="264" stroke="rgba(208,64,64,0.4)" stroke-width="6"/>
+  <line x1="504" y1="216" x2="456" y2="264" stroke="rgba(208,64,64,0.4)" stroke-width="6"/>
+  <text x="372" y="440" fill="rgba(208,64,64,0.7)" font-size="22" font-weight="700" font-family="monospace">BACK FACE ✗</text>
+  <text x="390" y="468" fill="#aaa" font-size="18" font-family="monospace">(culled — not drawn)</text>
 </svg>