book rendering for Sources of Light

This commit is contained in:
tmont 2024-11-13 21:15:53 -08:00
commit defe1941ed
15 changed files with 1826 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea
node_modules
rendered

28
README.md Normal file
View File

@ -0,0 +1,28 @@
A small script for generating PDFs for my guitar TAB book for
my album "Sources of Light".
The book was printed through bookbaby.com in November 2024.
HTML files are in `pages/`. All the dimensions are set up properly
in the CSS at 9.25in x 12.25in. This is for a "Large Portrait" size
book that is 9x12. BookBaby requires an extra .25" of margin.
To generate PDFs:
1. `npm install`
2. `mkdir -p rendered`
3. `node index.mjs`
```
tmont@thelio:~/code/sources-of-light (main +) node index.mjs
processing 001-title.html...
generated PDF at /home/tmont/code/sources-of-light/rendered/001-title.pdf
processing 002-title2.html...
generated PDF at /home/tmont/code/sources-of-light/rendered/002-title2.pdf
processing 003-toc.html...
generated PDF at /home/tmont/code/sources-of-light/rendered/003-toc.pdf
processing 197-timeline.html...
generated PDF at /home/tmont/code/sources-of-light/rendered/197-timeline.pdf
```
Rendered pages will be in `rendered/`.

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

View File

@ -0,0 +1,39 @@
/* latin-ext */
@font-face {
font-family: 'Schibsted Grotesk';
font-style: italic;
font-weight: 400 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/schibstedgrotesk/v3/Jqz_5SSPQuCQF3t8uOwiUL-taUTtap9DWyYpchFP.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Schibsted Grotesk';
font-style: italic;
font-weight: 400 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/schibstedgrotesk/v3/Jqz_5SSPQuCQF3t8uOwiUL-taUTtap9DWygpcg.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
font-family: 'Schibsted Grotesk';
font-style: normal;
font-weight: 400 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/schibstedgrotesk/v3/Jqz55SSPQuCQF3t8uOwiUL-taUTtap9Iayoxdg.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Schibsted Grotesk';
font-style: normal;
font-weight: 400 900;
font-display: swap;
src: url(https://fonts.gstatic.com/s/schibstedgrotesk/v3/Jqz55SSPQuCQF3t8uOwiUL-taUTtap9Gayo.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -0,0 +1,39 @@
/* latin-ext */
@font-face {
font-family: 'Sometype Mono';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sometypemono/v1/70lLu745KGk_R3uxyq0WrROhKpGRTW9Gzm8.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Sometype Mono';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sometypemono/v1/70lLu745KGk_R3uxyq0WrROhKpGRQ29G.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
font-family: 'Sometype Mono';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sometypemono/v1/70lVu745KGk_R3uxyq0WrROhKpqhQXdC.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
font-family: 'Sometype Mono';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(https://fonts.gstatic.com/s/sometypemono/v1/70lVu745KGk_R3uxyq0WrROhKpShQQ.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

40
index.mjs Normal file
View File

@ -0,0 +1,40 @@
import fs from 'fs';
import path from 'path';
import puppeteer from 'puppeteer-core';
import {fileURLToPath} from 'url';
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
const renderedDir = path.join(dirname, 'rendered');
fs.mkdirSync(renderedDir, { recursive: true });
const files = fs.readdirSync(path.join(dirname, 'pages'))
.sort()
.map(file => path.join(dirname, 'pages', file));
const browser = await puppeteer.launch({
executablePath: '/usr/bin/google-chrome',
});
const page = await browser.newPage();
for (const file of files) {
const targetFile = path.join(renderedDir, path.basename(file, '.html') + '.pdf');
console.log(`processing ${path.basename(file)}...`);
await page.goto(`file://${file}`, {
waitUntil: 'networkidle0',
});
await page.pdf({
width: '9.25in',
height: '12.25in',
path: targetFile,
printBackground: true,
});
console.log(` generated PDF at ${targetFile}`);
}
await browser.close();

1012
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

10
package.json Normal file
View File

@ -0,0 +1,10 @@
{
"name": "sources-of-light",
"version": "0.0.0",
"dependencies": {
"puppeteer-core": "23.7.1"
},
"scripts": {
}
}

82
pages/001-title.html Normal file
View File

@ -0,0 +1,82 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="../fonts/SchibstedGrotesk/style.css"/>
<style>
body {
margin: 0;
font-family: "Schibsted Grotesk";
}
* {
box-sizing: border-box;
}
#page {
width: 9.25in;
height: 12.25in;
padding: 15mm;
display: flex;
justify-content: center;
align-items: end;
position: relative;
/*background-image: url(../assets/book-cover-front-no-bottom-text-grayscale-2.png);*/
/*background-size: contain;*/
/*background-repeat: no-repeat;*/
}
#image {
position: absolute;
top: .125in;
left: .125in;
width: 9in;
height: 12in;
background-image: url(../assets/book-cover-front-no-bottom-text-grayscale-2.png);
background-size: cover;
background-repeat: no-repeat;
z-index: -1;
}
p {
margin: 0;
text-align: center;
font-size: 12pt;
line-height: 1.5;
}
.copyright {
margin-top: 15mm;
}
.links {
display: flex;
justify-content: center;
gap: 5mm;
}
</style>
</head>
<body>
<div id="page">
<div id="image"></div>
<div>
<p>
Transcribed and engraved by Tommy Montgomery
<br />
Art and design by Joe Montgomery
</p>
<div class="copyright">
<p>
Copyright &copy; 2024 Tommy Montgomery
</p>
<p class="links">
<span>tmont.com</span>
<span>&middot;</span>
<span>wakuine.com</span>
</p>
</div>
</div>
</div>
</body>
</html>

67
pages/002-title2.html Normal file
View File

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title 2</title>
<link rel="stylesheet" href="../fonts/SchibstedGrotesk/style.css"/>
<style>
body {
margin: 0;
font-family: "Schibsted Grotesk";
}
* {
box-sizing: border-box;
}
#page {
width: 9.25in;
height: 12.25in;
/*padding: 15mm;*/
background-color: lightblue;
display: flex;
flex-direction: column;
overflow: hidden;
background-image: url(../assets/tree-and-sky-color-blurred-lightened.jpg);
background-size: cover;
}
.poem {
font-size: 28pt;
text-align: center;
flex: 1;
display: flex;
justify-content: center;
align-items: center;
font-weight: 500;
line-height: 1.5;
text-shadow: .03em .03em #aaaaaa;
}
.image {
flex: 1;
display: inline;
overflow: hidden;
}
.image img {
width: 100%;
height: 100%;
object-fit: cover;
}
</style>
</head>
<body>
<div id="page">
<div class="poem">
I look up to the Heavens<br />
to see the stars live and die<br/>
while sitting on lonely thrones<br/>
in their castles in the sky<br/>
</div>
<!-- <div class="image">-->
<!-- <img src="../assets/battlestation-grayscale.jpeg" />-->
<!-- </div>-->
</div>
</body>
</html>

97
pages/003-toc.html Normal file
View File

@ -0,0 +1,97 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>ToC</title>
<link rel="stylesheet" href="../fonts/SometypeMono/style.css"/>
<style>
body {
margin: 0;
font-family: "Sometype Mono";
}
* {
box-sizing: border-box;
}
#page {
padding: 15mm;
width: 9.25in;
height: 12.25in;
/*background-color: lightblue;*/
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.list-item {
font-size: 24pt;
margin-bottom: 0.5em;
}
.number {
display: inline-block;
text-align: right;
width: 2em;
font-weight: 700;
}
.title {
letter-spacing: -0.04em;
font-weight: 500;
}
#colorstrip {
position: absolute;
left: 0;
top: 0;
background-image: url(../assets/color-strip-vertical-grayscale.jpeg);
width: 0.5in;
height: 100%;
background-size: contain;
}
</style>
</head>
<body>
<div id="page">
<div id="colorstrip"></div>
<div class="list">
<div class="list-item">
<span class="number">4</span>
<span class="title">Calling Out a Name</span>
</div>
<div class="list-item">
<span class="number">34</span>
<span class="title">Waiting for the Stars to Fall</span>
</div>
<div class="list-item">
<span class="number">66</span>
<span class="title">Shine</span>
</div>
<div class="list-item">
<span class="number">83</span>
<span class="title">Castles in the Sky</span>
</div>
<div class="list-item">
<span class="number">103</span>
<span class="title">The Haunted House</span>
</div>
<div class="list-item">
<span class="number">118</span>
<span class="title">Fair-weather Friend</span>
</div>
<div class="list-item">
<span class="number">130</span>
<span class="title">Still Alive</span>
</div>
<div class="list-item">
<span class="number">149</span>
<span class="title">Without You</span>
</div>
</div>
</div>
</body>
</html>

409
pages/197-timeline.html Normal file
View File

@ -0,0 +1,409 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Timeline</title>
<link rel="stylesheet" href="../fonts/SchibstedGrotesk/style.css" />
<style>
body {
margin: 0;
font-family: "Schibsted Grotesk";
font-weight: 400;
}
* {
box-sizing: border-box;
}
#page {
width: 9.25in;
height: 12.25in;
/*background-color: lightblue;*/
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
/*background-image: url(../assets/back-cover-splat-only-grayscale.png);*/
background-image: url(../assets/black-star-clean-lightened-grayscale.jpeg);
background-size: 90%;
background-repeat: no-repeat;
background-position: center center;
position: relative;
}
.vert-line {
width: 0.25em;
background-color: black;
}
.main-height {
height: 75%;
}
.timeline {
display: flex;
height: 12in;
justify-content: center;
align-items: center;
position: relative;
}
.markers {
position: relative;
left: -0.65em;
}
.marker {
width: 1em;
height: 1em;
border-radius: 100%;
border: 0.25em solid black;
background-color: white;
position: absolute;
left: 0;
}
.date-span {
position: absolute;
margin-left: 0.75em;
}
.info {
position: relative;
left: -2.5em;
}
.title {
position: relative;
}
.bracket-container {
position: absolute;
top: 1.5in;
}
.title-container {
position: absolute;
top: 0;
left: -20em;
width: 16.5em;
text-align: right;
}
.date {
position: absolute;
white-space: nowrap;
padding-left: 1.3em;
margin-top: -0.2em;
}
.song {
position: absolute;
}
.box {
white-space: pre;
position: absolute;
font-family: monospace;
font-size: 0.13in;
top: -0.9em;
left: 0;
}
:root {
--calling-start: -1em;
--calling-end: 1.053658536585366in;
--haunted-start: 1.3829268292682926in;
--haunted-end: 2.0195121951219512in;
--friend-start: 2.282926829268293in;
--friend-end: 2.5253048780487806in;
--stars-start: 2.7887195121951223in;
--stars-end: 4.32530487804878in;
--castles-start: 5.049695121951219in;
--castles-end: 5.575609756097561in;
--alive-start: 5.817073170731708in;
--alive-end: 6.278048780487804in;
--without-start: 6.760975609756097in;
--without-end: 8.517073170731706in;
--shine-start: 8.78048780487805in;
--shine-end: 9in;
}
.calling-out-a-name-start {
top: var(--calling-start);
}
.calling-out-a-name-end {
top: var(--calling-end);
}
.haunted-house-start {
top: var(--haunted-start);
}
.haunted-house-end {
top: var(--haunted-end);
}
.fair-weather-friend-start {
top: var(--friend-start);
}
.fair-weather-friend-end {
top: var(--friend-end);
}
.waiting-for-the-stars-to-fall-start {
top: var(--stars-start);
}
.waiting-for-the-stars-to-fall-end {
top: var(--stars-end);
}
.castles-in-the-sky-start {
top: var(--castles-start);
}
.castles-in-the-sky-end {
top: var(--castles-end);
}
.still-alive-start {
top: var(--alive-start);
}
.still-alive-end {
top: var(--alive-end);
}
.without-you-start {
top: var(--without-start);
}
.without-you-end {
top: var(--without-end);
}
.shine-start {
top: var(--shine-start);
}
.shine-end {
top: var(--shine-end);
}
.bracket {
position: absolute;
margin-top: 0.48em;
}
.bracket .top, .bracket .vert, .bracket .middle, .bracket .bottom {
position: absolute;
border: 0 solid black;
}
.bracket .top, .bracket .bottom {
width: 0.75em;
}
.bracket .top {
top: 0;
border-bottom-width: .15em;
}
.bracket .vert {
border-right-width: .15em;
height: 100%;
}
.bracket .middle {
border-bottom-width: .15em;
width: 1.5em;
left: -1.5em;
top: 50%;
}
.bracket .bottom {
border-bottom-width: .15em;
bottom: 0;
}
</style>
</head>
<body>
<div id="page">
<div class="timeline">
<div class="vert-line main-height"></div>
<div class="main-height">
<div class="markers">
<div class="song calling-out-a-name-start">
<div class="marker"></div>
<div class="date">July 20, 2023</div>
</div>
<div class="song calling-out-a-name-end">
<div class="marker"></div>
<div class="date">September 6, 2023</div>
</div>
<div class="song haunted-house-start">
<div class="marker"></div>
<div class="date">September 21, 2023</div>
</div>
<div class="song haunted-house-end">
<div class="marker"></div>
<div class="date">October 20, 2023</div>
</div>
<div class="song fair-weather-friend-start">
<div class="marker"></div>
<div class="date">November 1, 2023</div>
</div>
<div class="song fair-weather-friend-end">
<div class="marker"></div>
<div class="date">November 12, 2023</div>
</div>
<div class="song waiting-for-the-stars-to-fall-start">
<div class="marker"></div>
<div class="date">November 24, 2023</div>
</div>
<div class="song waiting-for-the-stars-to-fall-end">
<div class="marker"></div>
<div class="date">February 2, 2024</div>
</div>
<div class="song castles-in-the-sky-start">
<div class="marker"></div>
<div class="date">March 6, 2024</div>
</div>
<div class="song castles-in-the-sky-end">
<div class="marker"></div>
<div class="date">March 30, 2024</div>
</div>
<div class="song still-alive-start">
<div class="marker"></div>
<div class="date">April 10, 2024</div>
</div>
<div class="song still-alive-end">
<div class="marker"></div>
<div class="date">May 1, 2024</div>
</div>
<div class="song without-you-start">
<div class="marker"></div>
<div class="date">May 23, 2024</div>
</div>
<div class="song without-you-end">
<div class="marker"></div>
<div class="date">August 11, 2024</div>
</div>
<div class="song shine-start">
<div class="marker"></div>
<div class="date">August 23, 2024</div>
</div>
<div class="song shine-end">
<div class="marker"></div>
<div class="date">September 2, 2024</div>
</div>
</div>
<div class="bracket-container">
<div class="title-container">
<div class="title" style="top: 0.42in">Calling Out a Name</div>
<div class="title" style="top: 1.47in">The Haunted House</div>
<div class="title" style="top: 1.96in">Fair-weather Friend</div>
<div class="title" style="top: 2.905in;">Waiting for the Stars to Fall</div>
<div class="title" style="top: 4.46in;">Castles in the Sky</div>
<div class="title" style="top: 4.975in;">Still Alive</div>
<div class="title" style="top: 6.36in;">Without You</div>
<div class="title" style="top: 7.405in;">Shine</div>
</div>
<div class="date-span calling-out-a-name-start">
<div class="info">
<div class="bracket" style="height: calc(var(--calling-end) - var(--calling-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span haunted-house-start">
<div class="info">
<div class="bracket" style="height: calc(var(--haunted-end) - var(--haunted-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span fair-weather-friend-start">
<div class="info">
<div class="bracket" style="height: calc(var(--friend-end) - var(--friend-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span waiting-for-the-stars-to-fall-start">
<div class="info">
<div class="bracket" style="height: calc(var(--stars-end) - var(--stars-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span castles-in-the-sky-start">
<div class="info">
<div class="bracket" style="height: calc(var(--castles-end) - var(--castles-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span still-alive-start">
<div class="info">
<div class="bracket" style="height: calc(var(--alive-end) - var(--alive-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span without-you-start">
<div class="info">
<div class="bracket" style="height: calc(var(--without-end) - var(--without-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
<div class="date-span shine-start">
<div class="info">
<div class="bracket" style="height: calc(var(--shine-end) - var(--shine-start));">
<div class="top"></div>
<div class="vert"></div>
<div class="middle"></div>
<div class="bottom"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>