Initial commit: organize Primary song slides repo

One folder per song under songs/. Tracks PPTX slide files and
Python generation scripts. PDFs and videos excluded (too large
for git; originals are in Google Drive).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 21:20:22 -06:00
commit 5a45320057
17 changed files with 788 additions and 0 deletions
@@ -0,0 +1,162 @@
import fitz
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
import io
PDF_PATH = r"C:\Users\jhodgkin\Documents\dev\primary-song-slides\BookOfMormonStories.pdf"
OUT_PATH = r"C:\Users\jhodgkin\Documents\dev\primary-song-slides\BookOfMormonStories.pptx"
DPI = 96
SLIDE_W = Inches(13.333)
SLIDE_H = Inches(7.5)
TEXT_BOX_H = Inches(2.1)
FONT_SIZE = Pt(44)
TEXT_COLOR = RGBColor(0x4A, 0x27, 0x11) # deep warm brown
# PDF pages 0-31 = illustration cards; page 32 = title page (skipped)
# Verse 1 lyrics are from CS 118. Fill in the remaining verses with correct lyrics.
#
# Image guide (0-based page → subject):
# 0 = teacher reading to children (intro)
# 1 = Lehi's family on ancient scroll
# 2 = three men sailing
# 3 = righteous family with halos in jungle
# 4 = large group gathering in jungle
# 5 = lush jungle / hut
# 6 = children springing from open Book of Mormon
# 7 = family with halos (closer)
# 8 = young man in red sash (Nephi? Alma?)
# 9 = angel with wings
# 10 = three men around a fallen figure (Alma struck down)
# 11 = righteous youth with halo in jungle
# 12 = man in chains
# 13 = pile of chains
# 14 = wicked king
# 15 = gravestone with flowers
# 16 = shepherd with sheep and staff
# 17 = flock of many sheep
# 18 = slingshot and sword
# 19 = righteous shepherd with halo
# 20 = four young warriors (shields and spears, no halos)
# 21 = Jesus Christ in red robe, arms open
# 22 = four warriors smiling
# 23 = four warriors with halos in jungle
# 24 = man standing triumphantly on stone wall
# 25 = three arrows flying
# 26 = young man preaching, arms wide
# 27 = young man preaching with halo
# 28 = crucifixion (three crosses)
# 29 = Jesus hugging many children
# 30 = portrait of Jesus Christ
# 31 = five children with halos in jungle
SLIDES = [
# Verse 1 — Lehi's family / ancient Lamanites
(0, "Book of Mormon stories that my teacher tells to me,"),
(1, "Are about the Lamanites in ancient history."),
(2, "Long ago their fathers came from far across the sea,"),
(3, "Giv'n the land if they lived righteously."),
# Verse 2 — Lamanites and others in the promised land
(4, "Lamanites met others who were seeking liberty,"),
(5, "And the land soon welcomed all who wanted to be free."),
(6, "Book of Mormon stories say that we must brothers be,"),
(7, "Giv'n the land if we live righteously."),
# Verse 3 — Alma the Younger
(8, "Alma was rebellious, and he fought against the right."),
(9, "Then one day an angel came to turn him to the light."),
(10, "Struck before his brethren, Alma learned humility."),
(11, "Then he taught in the land righteously."),
# Verse 4 — Abinadi before King Noah
(12, "Don't forget Abinadi, who stood before the king."),
(13, "All chained up from head to toe, the gospel he did bring."),
(14, "If he would deny it, then the king would set him free."),
(15, "He was true, and he died righteously."),
# Verse 5 — Ammon the missionary
(16, "Ammon was a missionary serving Lamanites,"),
(17, "Tending King Lamoni's sheep for several days and nights."),
(18, "Robbers came; he saved the sheep by fighting fearlessly."),
(19, "He had learned he could live righteously."),
# Verse 6 — 2000 Stripling Warriors
# Reordered: warriors (20) -> smiling march (22) -> Christ (21) -> halos (23)
(20, "Once two thousand sons of God were called to fight the foe."),
(22, "Marching as an army into battle they did go."),
(21, "They believed that Christ the Lord their guardian would be."),
(23, "They had learned they should live righteously."),
# Verse 7 — Samuel the Lamanite
# Reordered: wall (24) -> preaching (26) -> arrows (25) -> righteous (27)
(24, "Samuel the Lamanite, high on the city wall,"),
(26, "Came to warn the people, and repentance was his call."),
(25, "Arrows could not hit him, for a man of God was he,"),
(27, "And he taught in the land righteously."),
# Verse 8 — Christ's atonement and visit to the Americas
# Reordered: crucifixion (28) -> portrait (30) -> children (29) -> people (31)
(28, "After Christ was crucified and died for you and me,"),
(30, "He came forth to teach the truth to all who would be free."),
(29, "Hands were laid upon each child. He blessed them tenderly,"),
(31, "And they lived in the land righteously."),
]
def render_page(page):
mat = fitz.Matrix(DPI / 72, DPI / 72)
pix = page.get_pixmap(matrix=mat, alpha=False)
return io.BytesIO(pix.tobytes("jpeg", jpg_quality=85)), pix.width, pix.height
def add_slide(doc, prs, blank_layout, page_idx, lyric):
page = doc[page_idx]
img_bytes, pw, ph = render_page(page)
slide = prs.slides.add_slide(blank_layout)
aspect = pw / ph
h = SLIDE_H
w = int(h * aspect)
if w > SLIDE_W:
w = SLIDE_W
h = int(w / aspect)
left = (SLIDE_W - w) // 2
top = (SLIDE_H - h) // 2
slide.shapes.add_picture(img_bytes, left, top, width=w, height=h)
tb_top = SLIDE_H - TEXT_BOX_H
txBox = slide.shapes.add_textbox(Inches(0.25), tb_top, SLIDE_W - Inches(0.5), TEXT_BOX_H)
tf = txBox.text_frame
tf.word_wrap = True
lines = lyric.split("\n")
for i, line in enumerate(lines):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.alignment = PP_ALIGN.CENTER
run = p.add_run()
run.text = line
run.font.bold = True
run.font.size = FONT_SIZE
run.font.color.rgb = TEXT_COLOR
print(f" Slide {len(prs.slides):2d} (pg {page_idx:2d}): {lyric[:60]}")
def main():
doc = fitz.open(PDF_PATH)
prs = Presentation()
prs.slide_width = SLIDE_W
prs.slide_height = SLIDE_H
blank_layout = prs.slide_layouts[6]
for page_idx, lyric in SLIDES:
add_slide(doc, prs, blank_layout, page_idx, lyric)
prs.save(OUT_PATH)
print(f"\nSaved: {OUT_PATH} ({len(SLIDES)} slides)")
if __name__ == "__main__":
main()