Edit in JSFiddle

```// Dimensions of the whole book
var BOOK_WIDTH = 630;
var BOOK_HEIGHT = 260;

// Dimensions of one page in the book
var PAGE_WIDTH = 300;
var PAGE_HEIGHT = 250;

// Vertical spacing between the top edge of the book and the papers
var PAGE_Y = (BOOK_HEIGHT - PAGE_HEIGHT) / 2;

// The canvas size equals to the book dimensions + this padding

var progress = 1;
var target = -1;

var canvas = document.getElementById("pageflip-canvas");
var context = canvas.getContext("2d");
var fillElt = document.getElementById("fill");
var progressElt = document.getElementById("progress");
var foldWidthElt = document.getElementById("foldWidth");
var foldXElt = document.getElementById("foldX");

// Resize the canvas to match the book size
canvas.width = BOOK_WIDTH;
canvas.height = BOOK_HEIGHT + (CANVAS_PADDING * 2);

function render() {

// Reset all pixels in the canvas
context.clearRect(0, 0, canvas.width, canvas.height);

// Ease progress towards the target value
progress = progressElt.value;
// Strength of the fold is strongest in the middle of the book
var strength = 1 - Math.abs(progress);

// Width of the folded paper
var foldWidth = (PAGE_WIDTH * 0.5) * (1 - progress);

// X position of the folded paper
var foldX = PAGE_WIDTH * progress + foldWidth;

// How far the page should outdent vertically due to perspective
var verticalOutdent = 20 * strength;

foldWidthElt.value = foldWidth;
foldXElt.value = foldX;

context.save();
context.translate((BOOK_WIDTH / 2), PAGE_Y + CANVAS_PADDING);

drawFoldedPaper(foldX, foldWidth, verticalOutdent, fillElt.checked);

}

}

context.restore();
}

// Draw the folded piece of paper
function drawFoldedPaper(foldX, foldWidth, verticalOutdent, fill) {
context.beginPath();
context.moveTo(foldX, 0);
context.lineTo(foldX, PAGE_HEIGHT);
context.quadraticCurveTo(foldX, PAGE_HEIGHT + (verticalOutdent * 2), foldX - foldWidth, PAGE_HEIGHT + verticalOutdent);
context.lineTo(foldX - foldWidth, -verticalOutdent);
context.quadraticCurveTo(foldX, -verticalOutdent * 2, foldX, 0);

if (fill) {
var paperShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(1 - progress, 0.5), 0);
context.fill();
}
context.strokeStyle = 'rgba(0,0,0,0.06)';
context.lineWidth = 2;
context.stroke();
}

// Draw a sharp shadow on the left side of the page
function drawSharpShadow(foldX, foldWidth, verticalOutdent, strength) {
context.strokeStyle = 'rgba(0,0,0,'+(0.05 * strength)+')';
context.lineWidth = 30 * strength;
context.beginPath();
context.moveTo(foldX - foldWidth, -verticalOutdent * 0.5);
context.lineTo(foldX - foldWidth, PAGE_HEIGHT + (verticalOutdent * 0.5));
context.stroke();
}

var rightShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(strength, 0.5), 0);

context.beginPath();
context.moveTo(foldX, 0);
context.lineTo(foldX, PAGE_HEIGHT);
context.fill();

var leftShadowWidth = (PAGE_WIDTH * 0.5) * Math.max(Math.min(strength, 0.5), 0);

context.beginPath();
context.moveTo(foldX - foldWidth - leftShadowWidth, 0);
context.lineTo(foldX - foldWidth, 0);
context.lineTo(foldX - foldWidth, PAGE_HEIGHT);
context.lineTo(foldX - foldWidth - leftShadowWidth, PAGE_HEIGHT);
context.fill();
}```
```<table>
<tr>
<td><label for="progress">Progress</label></td>
<td><input id="progress" type="range" min="-1" max="1" step="0.1" value="1"/></td>
<td ><label for="foldWidth">foldWidth</label></td>
<td><input id="foldWidth" type="text" disabled></td>
<td><label for="foldX">foldX</label></td>
<td><input id="foldX" type="text" disabled></td>
</tr>
<tr>
<td colspan="2"><label for="fill">Fill paper with gradient</label></td>
<td><input id="fill" type="checkbox" checked/>
</tr>
<tr>
</tr>
<tr>
</tr>
</table>
<canvas id="pageflip-canvas"></canvas>

```
```body, h2, p {
margin: 0;
color: white;
}

body {
background-color: #444;

font-family: Helvetica, sans-serif;
}

canvas {
background-color: #e2e2e2;
margin: 20px;
}

td {
}
input[type=range]::before {
content: attr(min);
}
input[type=range]::after {
content: attr(max);
}
```