<p><strong>Edit:</strong> created a new Codepen that shows the <a href="https://codepen.io/gmiller123456/pen/BaPxLbG" rel="nofollow noreferrer">terminator as a gradient</a>, which eliminates the hard line.</p>
<p><a href="https://i.sstatic.net/SsU4B.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/SsU4B.png" alt="enter image description here" /></a></p>
<p><strong>Rigorous:</strong></p>
<p>For those not wanting to settle for an approximation, rendering a photorealistic, properly shaded (with mountains and craters having shadows) image is pretty easy with existing tools like <a href="https://www.blender.org/" rel="nofollow noreferrer">Blender</a>, and <a href="https://svs.gsfc.nasa.gov/cgi-bin/details.cgi?aid=4720" rel="nofollow noreferrer">NASA's CGI Moon Kit</a>.  Since that's a solved problem, and this question is specifically looking for an approximation, I'll focus on that.  But an example using ThreeJS is <a href="https://codepen.io/g12n/pen/vYBryJW" rel="nofollow noreferrer">here</a>, and a tutorial using Blender is <a href="https://www.youtube.com/watch?v=ySgOcWarNFo" rel="nofollow noreferrer">here</a>.</p>
<p><strong>Approximate:</strong></p>
<p>An approximate method is to imagine a plane intersecting the center of the Moon, perpendicular to the direction of the Sun.  As the phase changes, the plane is rotated about the Y axis.  To keep things simple, we can ignore any perspective distortion (e.g. ignore the Z coordinate), the Y coordinate won't change, leaving only the X coordinate to be computed, and the rotation matrix simplifies to:</p>
<p><span class="math-container">$$
x= radius * \cos(phase)
$$</span></p>
<p>Where <span class="math-container">$phase$</span> is the phase from 0° (new moon) to 360°, and <span class="math-container">$radius$</span> is the radius of the full sphere.</p>
<p>The JavaScript code below expects HTML with a canvas with an ID of &quot;canvas&quot;, and a moon image with ID of &quot;moon&quot;. Here is <a href="https://codepen.io/gmiller123456/pen/eYjMxWv" rel="nofollow noreferrer">a demo in CodePen</a>.  It generates the polygon necessary to fill in the dark side of a full moon image, and renders the moon as it would be seen from the Northern hemisphere.</p>
<p>This generates a pretty harsh edge.  Since the Sun has an apparent size of about 0.5°, it will produce a gradient of that angular size on the Moon.  So it would produce a better result to compute two arcs, one +0.25°  of the current phase, and one -0.25° and fill a linear gradient in between.</p>
<p>Here is an example produced by the code below:</p>
<p><a href="https://i.sstatic.net/2oiXi.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/2oiXi.png" alt="enter image description here" /></a></p>
<pre><code>const rad=Math.PI/180;

const canvas = document.getElementById(&quot;canvas&quot;);
const w=canvas.width;
const h=canvas.height;
const ctx = canvas.getContext(&quot;2d&quot;);
const r=w/2*.91;

function drawPhase(phase){
    //A rotation matrix, ignoring the Z result, and with Z=0 initially simplifies to cos(phase*360)
    const f=Math.cos(phase*rad);

    ctx.lineWidth=1;
    ctx.beginPath();
    let x=f*r*Math.cos(0)+w/2;
    let y=r*Math.sin(0)+h/2;
    ctx.moveTo(x,y);

    if(phase&lt;=180){
        for(let i=0;i&lt;=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi&gt;0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    } else {
        for(let i=0;i&lt;=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi&lt;0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    }

    ctx.closePath();
    ctx.fill();
}

function display(){
    ctx.fillStyle=&quot;#000000cc&quot;;
    ctx.drawImage(document.getElementById(&quot;moon&quot;), 0, 0);
    
    phase=(phase+1)%360;

    drawPhase(phase);
    window.setTimeout(()=&gt;{
        display();
    },10);
}

let phase=0;
display();
</code></pre>

CC BY-SA 4.0
2023-01-26T07:50:38.220Z
That's pretty cool!  How is the amount of earthlight computed?
Toby Speight
CC BY-SA 4.0
2023-01-26T14:39:00.713Z
No attempt is made to compute the amount of light from Earth, the question asked for an approximate solution that looks right.
Greg Miller
CC BY-SA 4.0
2023-01-26T19:04:23.960Z
It looks like the earthlight is simply setting the brightness to 20%: `ctx.fillStyle="#000000cc"`
Mooing Duck
CC BY-SA 4.0
2023-01-25T06:47:06.713Z
2023-01-26T14:40:44.753Z
2023-01-26T14:40:44.753Z
Greg Miller
<p><a href="https://i.sstatic.net/YgjUQ.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/YgjUQ.png" alt="enter image description here" /></a></p>
<p>You must draw a semicircle of radius R and a semi-ellipse of semi-major axis &quot;R&quot; and semi-minor axis &quot;b&quot;.
To calculate &quot;b&quot; knowing the illuminated ratio &quot;n&quot;:</p>
<p><span class="math-container">$$n=\dfrac{\dfrac{\pi R^2}2+\dfrac{\pi R b}2}{\pi R^2}$$</span></p>
<p>Simplifying:</p>
<p><span class="math-container">$$\boxed{b=(2 n - 1) \ R}$$</span></p>
<p>If &quot;<span class="math-container">$n_{pc}$</span>&quot; is expressed in %</p>
<p><span class="math-container">$$b=(2 n_{pc} - 100) R$$</span></p>
<p>With the values of &quot;R&quot; and &quot;b&quot; it is easy to draw the semi-ellipse of the terminator using, for example, rectangular coordinates:</p>
<p><span class="math-container">$$\boxed{y=\dfrac b R \sqrt{R^2-x^2}}$$</span></p>

CC BY-SA 4.0
2023-01-25T11:24:49.523Z
2023-01-26T12:13:29.987Z
2023-01-26T12:13:29.987Z
Albert
<p>The line is a semi-ellipse. It is formed by projecting the great circle on the moon formed by the terminator to the plane perpendicular to a line going from the observer to the moon.  Projecting a circle to a plane results in an ellipse.</p>
<p>These pictures show simulations of a &quot;thin crescent&quot; or &quot;nearly full gibbous&quot; and &quot;near half moon&quot;  (depending on which part you consider to be lit).</p>
<p><a href="https://i.sstatic.net/vKDFh.png" rel="noreferrer"><img src="https://i.sstatic.net/vKDFh.png" alt="enter image description here" /></a> <a href="https://i.sstatic.net/8248n.png" rel="noreferrer"><img src="https://i.sstatic.net/8248n.png" alt="enter image description here" /></a></p>

CC BY-SA 4.0
2023-01-24T21:11:42.503Z
@WHITECOLOR You might like to play with this Sage / Python code: https://sagecell.sagemath.org/?z=eJw1jtsKwjAMhu8He4cwL0y1HjYQRCgIXgvDF5DaZa4w15IWRZ_eFjEXf0L-L4cZnJiCoSlKuL2hPUNzsdO9LJ6acR7noiyOdorE2sSy6KiHK_pBB1L1Zi8OZQEpelBgXMAGFuBtlkyIn9lm07IZCXErt0JCLWAJXrN-UGRrrn50EbFPc3lJTESwU8qpwPTWyttNIyFr6nwcd8RqJxM8OlYVU1f9T63D4F4ovpyNOpA=&lang=sage
PM 2Ring
CC BY-SA 4.0
2023-01-24T20:45:52.253Z
2023-01-24T20:45:52.253Z
James K
<p>Given that that <code>n%</code> of the moon is illuminated. I want to (approximately, but more or less correctly) draw the the terminator line on the circle (that represents the moon). Orientation is not the case here, just the crescent shape.</p>
<p>What is the best/correct way to determine/calculate/approximate the shape of the terminator line? Is this line actually a chord of a circle, or it is something different?</p>

CC BY-SA 4.0
2023-01-26T07:12:50.530Z
Pedantry: 50% of the moon is illuminated, except during lunar eclipse; we just can't see all of it.  I'll get me coat...
Toby Speight
<moon-phases>
The shape of the moon limb/crescent (terminator line)
WHITECOLOR
# The shape of the moon limb/crescent (terminator line)

(Asked by: username_0 on 2023-01-24)

Given that that `n%` of the moon is illuminated. I want to (approximately, but more or less correctly) draw the the terminator line on the circle (that represents the moon). Orientation is not the case here, just the crescent shape.

What is the best/correct way to determine/calculate/approximate the shape of the terminator line? Is this line actually a chord of a circle, or it is something different?

**Tags:** moon-phases
> **Comments:**
> **username_1**: Pedantry: 50% of the moon is illuminated, except during lunar eclipse; we just can't see all of it.  I'll get me coat...  

---

## 3 answers

### Answer by username_5 on 2023-01-24. Score: 16 | Accepted answer

The line is a semi-ellipse. It is formed by projecting the great circle on the moon formed by the terminator to the plane perpendicular to a line going from the observer to the moon. Projecting a circle to a plane results in an ellipse.

These pictures show simulations of a "thin crescent" or "nearly full gibbous" and "near half moon" (depending on which part you consider to be lit).

[![enter image description here](https://i.sstatic.net/vKDFh.png)](https://i.sstatic.net/vKDFh.png) [![enter image description here](https://i.sstatic.net/8248n.png)](https://i.sstatic.net/8248n.png)

> **Comments:**
> **username_6**: @WHITECOLOR You might like to play with this Sage / Python code: https://sagecell.sagemath.org/?z=eJw1jtsKwjAMhu8He4cwL0y1HjYQRCgIXgvDF5DaZa4w15IWRZ_eFjEXf0L-L4cZnJiCoSlKuL2hPUNzsdO9LJ6acR7noiyOdorE2sSy6KiHK_pBB1L1Zi8OZQEpelBgXMAGFuBtlkyIn9lm07IZCXErt0JCLWAJXrN-UGRrrn50EbFPc3lJTESwU8qpwPTWyttNIyFr6nwcd8RqJxM8OlYVU1f9T63D4F4ovpyNOpA=&lang=sage  

---

### Answer by username_2 on 2023-01-25. Score: 11

Edit: created a new Codepen that shows the terminator as a gradient, which eliminates the hard line.

Rigorous:
For those not wanting to settle for an approximation, rendering a photorealistic, properly shaded (with mountains and craters having shadows) image is pretty easy with existing tools like Blender, and NASA's CGI Moon Kit.  Since that's a solved problem, and this question is specifically looking for an approximation, I'll focus on that.  But an example using ThreeJS is here, and a tutorial using Blender is here.
Approximate:
An approximate method is to imagine a plane intersecting the center of the Moon, perpendicular to the direction of the Sun.  As the phase changes, the plane is rotated about the Y axis.  To keep things simple, we can ignore any perspective distortion (e.g. ignore the Z coordinate), the Y coordinate won't change, leaving only the X coordinate to be computed, and the rotation matrix simplifies to:
$$
x= radius * \cos(phase)
$$
Where $phase$ is the phase from 0° (new moon) to 360°, and $radius$ is the radius of the full sphere.
The JavaScript code below expects HTML with a canvas with an ID of "canvas", and a moon image with ID of "moon". Here is a demo in CodePen.  It generates the polygon necessary to fill in the dark side of a full moon image, and renders the moon as it would be seen from the Northern hemisphere.
This generates a pretty harsh edge.  Since the Sun has an apparent size of about 0.5°, it will produce a gradient of that angular size on the Moon.  So it would produce a better result to compute two arcs, one +0.25°  of the current phase, and one -0.25° and fill a linear gradient in between.
Here is an example produced by the code below:

const rad=Math.PI/180;

const canvas = document.getElementById("canvas");
const w=canvas.width;
const h=canvas.height;
const ctx = canvas.getContext("2d");
const r=w/2*.91;

function drawPhase(phase){
    //A rotation matrix, ignoring the Z result, and with Z=0 initially simplifies to cos(phase*360)
    const f=Math.cos(phase*rad);

    ctx.lineWidth=1;
    ctx.beginPath();
    let x=f*r*Math.cos(0)+w/2;
    let y=r*Math.sin(0)+h/2;
    ctx.moveTo(x,y);

    if(phase<=180){
        for(let i=0;i<=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi>0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    } else {
        for(let i=0;i<=360;i++){
            const cosi=Math.cos(i*rad);
            if(cosi<0){
                x=f*r*Math.cos(i*rad)+w/2;
            } else {
                x=r*Math.cos(i*rad)+w/2;
            }
            y=r*Math.sin(i*rad)+h/2;

            ctx.lineTo(x,y+1);
        }
    }

    ctx.closePath();
    ctx.fill();
}

function display(){
    ctx.fillStyle="#000000cc";
    ctx.drawImage(document.getElementById("moon"), 0, 0);
    
    phase=(phase+1)%360;

    drawPhase(phase);
    window.setTimeout(()=>{
        display();
    },10);
}

let phase=0;
display();

> **Comments:**
> **username_1**: That's pretty cool!  How is the amount of earthlight computed?  
> **username_2**: No attempt is made to compute the amount of light from Earth, the question asked for an approximate solution that looks right.  
> **username_3**: It looks like the earthlight is simply setting the brightness to 20%: `ctx.fillStyle="#000000cc"`  

---

### Answer by username_4 on 2023-01-25. Score: 9

[![enter image description here](https://i.sstatic.net/YgjUQ.png)](https://i.sstatic.net/YgjUQ.png)

You must draw a semicircle of radius R and a semi-ellipse of semi-major axis "R" and semi-minor axis "b".
To calculate "b" knowing the illuminated ratio "n":

$$n=\dfrac{\dfrac{\pi R^2}2+\dfrac{\pi R b}2}{\pi R^2}$$

Simplifying:

$$\boxed{b=(2 n - 1) \ R}$$

If "$n\_{pc}$" is expressed in %

$$b=(2 n\_{pc} - 100) R$$

With the values of "R" and "b" it is easy to draw the semi-ellipse of the terminator using, for example, rectangular coordinates:

$$\boxed{y=\dfrac b R \sqrt{R^2-x^2}}$$


---

