From c57692d5f8446fe0f06b54022ae4861b8b3c664d Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:27:22 -0700 Subject: [PATCH 1/5] Url arguments for getting clean music pages --- src/index.pug | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/index.pug b/src/index.pug index b1a9f16..a8b91c8 100644 --- a/src/index.pug +++ b/src/index.pug @@ -22,6 +22,8 @@ append head button { margin-right: 1ex } + body.fullscreen .noprint { display: none !important } + @media print { .noprint { display: none !important } } @@ -55,6 +57,10 @@ append body span Show lyrics input#show-lyrics(type="checkbox" checked) span     + label + span Show verses + input#show-verses(type="checkbox" checked) + span     label span Show trumpet fingering input#show-trumpet(type="checkbox") @@ -100,13 +106,16 @@ append body s = song .split /\n/ .filter (line) -> - if m = line.match /^\s*w:(.*)/i + if m = line.match /^\s*w:(.*)/ lyrics = m[1] if lyrics.match /^[\s\d\?]+$/ - # all digits are trumpet fingering, keep those - return $('#show-trumpt').is(':checked') + # all digits are trumpet fingering + return $('#show-trumpet').is(':checked') else return $('#show-lyrics').is(':checked') + else if line.match /^\s*W:/ + # W: lines are the extended verses below the music + return $('#show-verses').is(':checked') else return true .join('\n') @@ -158,7 +167,7 @@ append body $('#toKey').text displayKey() , 500 - $('#show-lyrics, #show-trumpet').on 'change', -> + $('#show-lyrics, #show-verses, #show-trumpet').on 'change', -> setSong byTitle[document.title] $('#show-gtab').on 'change', -> @@ -173,6 +182,17 @@ append body } params = new URLSearchParams(window.location.search) + + isFalse = (v) -> v? and v.toLowerCase() in ['false', '0', 'no', 'off'] + isTrue = (v) -> v? and v.toLowerCase() in ['true', '1', 'yes', 'on'] + + if isTrue params.get('fullscreen') + $('body').addClass 'fullscreen' + if isFalse params.get('lyrics') + $('#show-lyrics').prop 'checked', false + if isFalse params.get('verses') + $('#show-verses').prop 'checked', false + file = params.get('file') title = params.get('title') if file and songs[file] From 2d7cd1fc21d1ba8927308e392f53111976f24f95 Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:27:40 -0700 Subject: [PATCH 2/5] First pass of staff-based music book --- musicbook/all-for-me-grog.html | 3 + musicbook/barretts-privateers.html | 3 + musicbook/book.yaml | 37 ++++ musicbook/bully-boys.html | 3 + musicbook/bully-in-the-alley.html | 3 + musicbook/cover.html | 12 ++ musicbook/drunken-sailor.html | 3 + musicbook/health-to-the-company.html | 3 + musicbook/joli-rouge.html | 3 + musicbook/leave-her-johnny.html | 3 + musicbook/mingulay-boat-song.html | 3 + musicbook/music.css | 56 +++++ musicbook/pages/all-for-me-grog.svg | 1 + musicbook/pages/barretts-privateers.svg | 1 + musicbook/pages/bully-boys.svg | 1 + musicbook/pages/bully-in-the-alley.svg | 1 + musicbook/pages/drunken-sailor.svg | 1 + musicbook/pages/health-to-the-company.svg | 1 + musicbook/pages/joli-rouge.svg | 1 + musicbook/pages/leave-her-johnny.svg | 1 + musicbook/pages/mingulay-boat-song.svg | 1 + musicbook/pages/randy-dandy-o.svg | 1 + .../pages/roll-the-old-chariot-along.svg | 1 + musicbook/pages/south-australia.svg | 1 + musicbook/pages/wellerman.svg | 1 + musicbook/pages/whiskey-johnny.svg | 1 + musicbook/proof.html | 192 ++++++++++++++++++ musicbook/randy-dandy-o.html | 3 + musicbook/roll-the-old-chariot-along.html | 3 + musicbook/sea-shanties-music.html | 189 +++++++++++++++++ musicbook/south-australia.html | 3 + musicbook/wellerman.html | 3 + musicbook/whiskey-johnny.html | 3 + 33 files changed, 542 insertions(+) create mode 100644 musicbook/all-for-me-grog.html create mode 100644 musicbook/barretts-privateers.html create mode 100644 musicbook/book.yaml create mode 100644 musicbook/bully-boys.html create mode 100644 musicbook/bully-in-the-alley.html create mode 100644 musicbook/cover.html create mode 100644 musicbook/drunken-sailor.html create mode 100644 musicbook/health-to-the-company.html create mode 100644 musicbook/joli-rouge.html create mode 100644 musicbook/leave-her-johnny.html create mode 100644 musicbook/mingulay-boat-song.html create mode 100644 musicbook/music.css create mode 100644 musicbook/pages/all-for-me-grog.svg create mode 100644 musicbook/pages/barretts-privateers.svg create mode 100644 musicbook/pages/bully-boys.svg create mode 100644 musicbook/pages/bully-in-the-alley.svg create mode 100644 musicbook/pages/drunken-sailor.svg create mode 100644 musicbook/pages/health-to-the-company.svg create mode 100644 musicbook/pages/joli-rouge.svg create mode 100644 musicbook/pages/leave-her-johnny.svg create mode 100644 musicbook/pages/mingulay-boat-song.svg create mode 100644 musicbook/pages/randy-dandy-o.svg create mode 100644 musicbook/pages/roll-the-old-chariot-along.svg create mode 100644 musicbook/pages/south-australia.svg create mode 100644 musicbook/pages/wellerman.svg create mode 100644 musicbook/pages/whiskey-johnny.svg create mode 100644 musicbook/proof.html create mode 100644 musicbook/randy-dandy-o.html create mode 100644 musicbook/roll-the-old-chariot-along.html create mode 100644 musicbook/sea-shanties-music.html create mode 100644 musicbook/south-australia.html create mode 100644 musicbook/wellerman.html create mode 100644 musicbook/whiskey-johnny.html diff --git a/musicbook/all-for-me-grog.html b/musicbook/all-for-me-grog.html new file mode 100644 index 0000000..d128a26 --- /dev/null +++ b/musicbook/all-for-me-grog.html @@ -0,0 +1,3 @@ +
+ Staff notation for All For Me Grog +
diff --git a/musicbook/barretts-privateers.html b/musicbook/barretts-privateers.html new file mode 100644 index 0000000..7a9420b --- /dev/null +++ b/musicbook/barretts-privateers.html @@ -0,0 +1,3 @@ +
+ Staff notation for Barrett's Privateers +
diff --git a/musicbook/book.yaml b/musicbook/book.yaml new file mode 100644 index 0000000..e57cb11 --- /dev/null +++ b/musicbook/book.yaml @@ -0,0 +1,37 @@ +title: "Sea Shanties — Music" + +# Logical page + margins, matching the lyrics songbook so the two fold alike. +# The physical sheet is derived as two pages wide. +config: + page: + width: 5.5in + height: 8.5in + margins: + inner: 0.75in + outer: 0.5in + top: 0.6in + bottom: 0.6in + signatureSize: all + stylesheet: music.css + +# Staff notation captured from the running site at +# ?file=.txt&fullscreen=true&verses=false +# Each song is a single page (no spreads). Order mirrors the lyrics songbook. +# (skipper-jan-rebec is omitted — it has no ABC/staff notation on the site.) +pages: + - { file: cover.html, showPageNumber: false } + - blank + - { file: all-for-me-grog.html } + - { file: barretts-privateers.html } + - { file: bully-boys.html } + - { file: bully-in-the-alley.html } + - { file: drunken-sailor.html } + - { file: health-to-the-company.html } + - { file: joli-rouge.html } + - { file: leave-her-johnny.html } + - { file: mingulay-boat-song.html } + - { file: randy-dandy-o.html } + - { file: roll-the-old-chariot-along.html } + - { file: south-australia.html } + - { file: wellerman.html } + - { file: whiskey-johnny.html } diff --git a/musicbook/bully-boys.html b/musicbook/bully-boys.html new file mode 100644 index 0000000..74e7751 --- /dev/null +++ b/musicbook/bully-boys.html @@ -0,0 +1,3 @@ +
+ Staff notation for Bully Boys +
diff --git a/musicbook/bully-in-the-alley.html b/musicbook/bully-in-the-alley.html new file mode 100644 index 0000000..fb2c78d --- /dev/null +++ b/musicbook/bully-in-the-alley.html @@ -0,0 +1,3 @@ +
+ Staff notation for Bully in the Alley +
diff --git a/musicbook/cover.html b/musicbook/cover.html new file mode 100644 index 0000000..5fd9ad2 --- /dev/null +++ b/musicbook/cover.html @@ -0,0 +1,12 @@ + +
+
Sea
Shanties
+
Music Edition
+ +
diff --git a/musicbook/drunken-sailor.html b/musicbook/drunken-sailor.html new file mode 100644 index 0000000..b4bc508 --- /dev/null +++ b/musicbook/drunken-sailor.html @@ -0,0 +1,3 @@ +
+ Staff notation for Drunken Sailor +
diff --git a/musicbook/health-to-the-company.html b/musicbook/health-to-the-company.html new file mode 100644 index 0000000..97b2188 --- /dev/null +++ b/musicbook/health-to-the-company.html @@ -0,0 +1,3 @@ +
+ Staff notation for Health to the Company +
diff --git a/musicbook/joli-rouge.html b/musicbook/joli-rouge.html new file mode 100644 index 0000000..467eed8 --- /dev/null +++ b/musicbook/joli-rouge.html @@ -0,0 +1,3 @@ +
+ Staff notation for Joli Rouge +
diff --git a/musicbook/leave-her-johnny.html b/musicbook/leave-her-johnny.html new file mode 100644 index 0000000..f4f87c1 --- /dev/null +++ b/musicbook/leave-her-johnny.html @@ -0,0 +1,3 @@ +
+ Staff notation for Leave Her Johnny +
diff --git a/musicbook/mingulay-boat-song.html b/musicbook/mingulay-boat-song.html new file mode 100644 index 0000000..eee7338 --- /dev/null +++ b/musicbook/mingulay-boat-song.html @@ -0,0 +1,3 @@ +
+ Staff notation for Mingulay Boat Song +
diff --git a/musicbook/music.css b/musicbook/music.css new file mode 100644 index 0000000..42b73ce --- /dev/null +++ b/musicbook/music.css @@ -0,0 +1,56 @@ +/* Sea Shanties — music (staff notation) edition. + Appended after markdown-booklet's base CSS. url() paths resolve relative to + the OUTPUT html file, so build into this folder and keep pages/ as a sibling. */ + +:root { + --display: "Primitive", "UnifrakturCook", "Blackletter", serif; + --body: "Lucida Bright", "Lucida Serif", "Georgia", "Times New Roman", serif; +} + +.page-content { font-family: var(--body); } + +/* ---- Staff pages ------------------------------------------------------- */ +/* Each song page is a single captured abcjs SVG (which already renders the + song title). Fit it within the page content box, preserving aspect ratio. */ +.staff { + height: 100%; + display: flex; + align-items: center; + justify-content: center; +} +.staff img { + max-width: 100%; + max-height: 100%; + width: auto; + height: auto; +} + +/* ---- Cover ------------------------------------------------------------- */ +.cover { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} +.cover-title { + font-family: var(--display); + font-weight: 400; + font-size: 56pt; + line-height: 1.02; +} +.cover-sub { + font-family: var(--body); + font-size: 15pt; + letter-spacing: 0.16em; + text-transform: uppercase; + margin-top: 0.2in; + color: #333; +} +.cover-byline { + font-family: var(--body); + font-size: 13pt; + margin-top: 0.6in; +} +.cover-byline p { margin: 0.06in 0; } diff --git a/musicbook/pages/all-for-me-grog.svg b/musicbook/pages/all-for-me-grog.svg new file mode 100644 index 0000000..554d341 --- /dev/null +++ b/musicbook/pages/all-for-me-grog.svg @@ -0,0 +1 @@ +Sheet Music for "All For Me Grog"All For Me GrogChorusAllCEforEmeDgrogCmeBjol-FAlyBjol-ClyAgrogCGAll12CGfor12Gme12Gbeer12Gand0Fto-2Ebac-2GEco12D  DForEIFspentCGallGmeEtinConCtheBlas-FAsiesBdrin-Ckin'AginCGAndCa-DcrossEtheGwest-FernEo-EceanDICmustBwan-G7DderCC \ No newline at end of file diff --git a/musicbook/pages/barretts-privateers.svg b/musicbook/pages/barretts-privateers.svg new file mode 100644 index 0000000..11b869e --- /dev/null +++ b/musicbook/pages/barretts-privateers.svg @@ -0,0 +1 @@ +Sheet Music for "Barrett's Privateers"Barrett's PrivateersVerseOh,CtheEyearCGwasGse-FFven-FteenEsev-GDen-DtyDeight,CChowGIGwishCGIGwasDm (F?)AinASher-CGbrookeGnow!GDAAlet-CCterCofCmarqueFBcameAfromGGtheE DkingCCtoCtheDscum-Emi-EestEves-DselCI'veCe-EverGseen,FAGodFdamnCEthemGDall!CCChorusICEwasGtoldFAwe'dAcruiseGGtheGseasFAforBA-Bmer-CCi-GcanGgold,FAwe'dFfireCEnoGDguns.CCShedGnoBtears,FCnowGI'mAaBbro-CCkenGmanFAonGaFHal-CEi-EfaxGpier,FAtheAlastDm (F?)AofGBar-Frett'sEpri-GE Dva-CC \ No newline at end of file diff --git a/musicbook/pages/bully-boys.svg b/musicbook/pages/bully-boys.svg new file mode 100644 index 0000000..c5c3f8c --- /dev/null +++ b/musicbook/pages/bully-boys.svg @@ -0,0 +1 @@ +Sheet Music for "Bully Boys"Bully BoysEEADAE= 140AndEit'sFrowCGmeGbul-GlyFboysEwe'reFFinFaFhur-FryEboysDwe'veCEgotEaElongEwayDtoCgoG7DAndGwe'llGsingCGandCwe'llCdanceCandDbidEfare-FFwellEtoDFrance,DrowG7GmeEbul-FlyEboysDrowCCAndSee,AAndGwenow,weeweGsailedhowdramsailedCCa-weofa-Cwayfeastwhis-wayCinonkeyinDthephea-fortheErough-santse-rough-FFestbyver-estEofayofDwa-flock,man,wa-Dter,  ter,CrowrowrowrowCEmemememeEbul-bul-bul-bul-ElylylylyDboysboysboysboysCrowrowrowrowG7DButIt'sAndAndEnowaanowGwelong,bar-weCGre-longrelre-GturnwayofturnGinfromrumandGthetheforsoFmostgruelthelockEro-andshan-upFFyalthe yourE  ty Dquar-stocks, daugh-Dters, man,ters,CrowrowrowrowG7GmemememeEbul-bul-bul-bul-FlylylylyEboysboysboysboysDrowrowrowrowCC \ No newline at end of file diff --git a/musicbook/pages/bully-in-the-alley.svg b/musicbook/pages/bully-in-the-alley.svg new file mode 100644 index 0000000..0373d9a --- /dev/null +++ b/musicbook/pages/bully-in-the-alley.svg @@ -0,0 +1 @@ +Sheet Music for "Bully in the Alley"Bully in the AlleyEEADAE= 150Sal-Se-Sal-WellGGlyven  GislonglyI'llGtheyears leaveDgirlI-BrownSalGthat'veIandAIcourt-tookI'llBloveedagoDdear-Sal-no-sail-Blylytionin'GwaywaywaywayCCheyheyheyheyGBbul-bul-bul-bul-DAlylylylyAininininAthethethetheBal-al-al-al-AleyleyleyleyDSal-AllToLeaveGGlyshesail Gisdid myGthewasa- Dgirldil-crossgalGthatlythisandAIandwideI'llBspliceddal-damngoDnear- oc-whale-Blylyeanin'Gbul-bul-bul-bul-CClylylylyCdowndowndowndownCininininBshin-shin-shin-shin-GDboneboneboneboneD7FalalalalGGSoGGhelpDmeGbaGbaAbul-BlyBinBtheDal-BleyGwayCCheyGBbul-DAlyAinAtheBal-AleyDSoGGhelpDmeGbaGbaAbul-BlyBinBtheDal-BleyGbul-CClyCdownCinBshin-GDboneD7FalGG \ No newline at end of file diff --git a/musicbook/pages/drunken-sailor.svg b/musicbook/pages/drunken-sailor.svg new file mode 100644 index 0000000..1b29441 --- /dev/null +++ b/musicbook/pages/drunken-sailor.svg @@ -0,0 +1 @@ +Sheet Music for "Drunken Sailor"Drunken SailorWhatShavePut himStick himPut himThat'sDmAwillhisinininwhatAwebel-aatheweAdolylongscup-beddoAwithwithboatperwithwithAaa with atheaAdrunk-rust-tillhose-cap-drunk-Aenyhe'spipetainsenDsail-ra-so-bot-daugh-sail-For?zorbertomterorAWhatShavePut himStick himPut himThat'sCGwillhisinininwhatGwebel-aatheweGdolylongscup-beddoGwithwithboatperwithwithGaa with atheaGdrunk-rust-tillhose-cap-drunk-Genyhe'spipetainsenCsail-ra-so-bot-daugh-sail-Eor?zorbertomterorGWhatShavePut himStick himPut himThat'sDmAwillhisinininwhatAwebel-aatheweAdolylongscup-beddoAwithwithboatperwithwithAaa with atheaAdrunk-rust-tillhose-cap-drunk-Aenyhe'spipetainsenBsail-ra-so-bot-daugh-sail-Cor?zorbertomterorDEar-Ear-Ear-Ear-Ear-Ear-FClylylylylylyAininininininCGthethethethethetheEmorn-morn-morn-morn-morn-morn-DmDing!ing!ing!ing!ing!ing!DWayDmAhayAandAupAsheDris-FesAWayCGhayGandGupGsheCris-EesGWayDmAhayAandAupAsheBris-CesDEar-FClyAinCGtheEmorn-DmDing!D \ No newline at end of file diff --git a/musicbook/pages/health-to-the-company.svg b/musicbook/pages/health-to-the-company.svg new file mode 100644 index 0000000..97fe1aa --- /dev/null +++ b/musicbook/pages/health-to-the-company.svg @@ -0,0 +1 @@ +Sheet Music for "Health to the Company"Health to the CompanyEEADAE= 110VerseKindE DfriendsAmEandAcom-Bpan-EmAi-Gons,EcomeGjoinGGmeDinBCrhymeAmAComeA BliftAmCupDyourEvoi-CA GcesEinDchor-AmEusAwithBmineGGAComeA BliftAmCupDyourEvo-CAi-Gces,EallDgriefAmEtoAre-BfrainGGAForEweDmayAmEorAmightBne-EmA GverEallGmeetGGhereDa-BCgainAmA \ No newline at end of file diff --git a/musicbook/pages/joli-rouge.svg b/musicbook/pages/joli-rouge.svg new file mode 100644 index 0000000..c62935e --- /dev/null +++ b/musicbook/pages/joli-rouge.svg @@ -0,0 +1 @@ +Sheet Music for "Joli Rouge"Joli RougeDmDFAFAAmACEDmDFAFAAmACEDmDFAFAAmACEGFromShe'sSoSoDmAFrancecalledturnyouAwetheyourcanAgetDread-sailshaveGthenoughtoveraAmABran-Ci- Mag-Ady,der, nersAfromshe'sandandAMar-pro-bringpourDmAti-perheritGniqueandhardo-Ftheshe'stoverGrumfineporticeAmAASweetAndFindOrDmFredwhen youF thethatcanFCab-daylit-haveCEer-istleaDnetoverstarStrong-C sureandbowCfromIflyifDI-wishstraightit'sDmCta-thatin-sad-DlyshetonessDdoeswerethethat youCcome.mine.Northlike.CD    DButOrTheOrDthe   Efair-inwildjoinDmFestthe usEofdarksunupDthemofup-theFall,win-onri-CEmeter,yourverDboys backandCtheorthewe'llDoneonwindsetFAtoaa-yourGbeatsum-blow-heartFthemer'singa-Aday,evefreeglowCC    C    Cis You'reAndCmadeOneroll-howDmDfromhandingyou'llC  upfeelCap-giv-thewhenFAplesethrivertheGupandboysrealFthetheto Amigh-oth-oldci-C7GtyerChi-derGSa-doescou-startsFgue-re-ti-toEnay.ceive.mi.flow.FFSoSoSoSoAfol-DmAlowAmeAladsAAmcauseAthisAain'tDmAnoGgrogForGaleAmAOneDmFpintF FdownCEyou'llDbeCswing-DmAin'DinD DtheCgaleCDFiveDmFpintsF Fbul-CElyDyou'llCbeDshak-FAin'GinFyourAshoesCC C CWe'reChalf-DmDseasC Cov-FAerGonFtheAJo-CGliCRogue.DmD \ No newline at end of file diff --git a/musicbook/pages/leave-her-johnny.svg b/musicbook/pages/leave-her-johnny.svg new file mode 100644 index 0000000..fe97762 --- /dev/null +++ b/musicbook/pages/leave-her-johnny.svg @@ -0,0 +1 @@ +Sheet Music for "Leave Her Johnny"Leave Her JohnnyIOhIWeC the  DthoughtwindhateswearCEIwastobyEheardfoulsailroteEtheandonforC thethis Doldsearot-wantEmanwastenofDsayhightubmoreCLeaveLeaveLeaveLeaveGDherherherherDJohn-John-John-John-DnynynynyCleaveleaveleaveleaveCEherherherherGTo-SheNoButGmor-shippedgrognowFArowita-we'reAyegreenlowedthroughCGwillandandso we'llEgetnonerot-goGFyerwenttenonFpaybygrubshoreCEandandandandCit'sit'sit'sit'sDtimetimetimetimeEforforforforEususususEtotototoCleaveleaveleaveleaveG7DherherherherCCLeaveGDherDJohn-DnyCleaveCEherGOhC BleaveFAher,AJohn-AnyGleaveCA GherEForCtheBvoyageFAisAlongCGandEtheEwindsGFdon'tFblowCEandCit'sDtimeEforEusEtoCleaveG7DherCC \ No newline at end of file diff --git a/musicbook/pages/mingulay-boat-song.svg b/musicbook/pages/mingulay-boat-song.svg new file mode 100644 index 0000000..942263c --- /dev/null +++ b/musicbook/pages/mingulay-boat-song.svg @@ -0,0 +1 @@ +Sheet Music for "Mingulay Boat Song"Mingulay Boat SongEEADAE= 140ChorusHeaveDDherEho,GGboys,GletDherBgo,B AboysGSwingDherBheadDAroundAin-GtoB AtheGwea-CEtherEHeaveDDherEho,GGboys,GletDherBgo,B AboysGSail-DingBhome-DAwardAtoGMin-Bgu-AlayGGVerseWhatDDcareEwe,GGthough,Gwhi-DteBtheBMinchAis?GWhatDcareBwe,DAboys,AforGwin-BdyA Gweath-CEer?EWhenDDweEknowGGthatGe-Dver-ByBinchAisGSail-DingBhome-DAwardAtoGMin-Bgu-AlayGG \ No newline at end of file diff --git a/musicbook/pages/randy-dandy-o.svg b/musicbook/pages/randy-dandy-o.svg new file mode 100644 index 0000000..1f10578 --- /dev/null +++ b/musicbook/pages/randy-dandy-o.svg @@ -0,0 +1 @@ +Sheet Music for "Randy Dandy-O"Randy Dandy-OEEADAE= 140NowManHeaveWeSoonComeAmCwethea-arewe'llbreastCarestoutway,out-betheCread-caps-bull-wardwarp-barBdy'nies,boundingbull-CtoandyeforheriesBsailheavepar-Vall-outheaveAforwithish-ip-throughwithBtheariggedotheaAHorn,willbumsBaylockswillEWayWayWayWayWayWayAheyheyheyheyheyheyGBrollrollrollrollrollrollAmAandandandandandandGgogogogogogoEOurForTakeGetWhereOhE  your the Fbootssoonhandscrack-pret-soonCGan'we'llfromin',tywe'llAourbeyourmeyoungbeGclothes,driv-pock-lads,girlsroll-Gboys,in'etsit'sallingFarea-andacomeherEallwaydon'thelldowndownGDinupsuckofinthroughDthetheyouratheirtheDpawnhillthumbsway!frocksbayDToToToToToToCmemememememeDrol-rol-rol-rol-rol-rol-AmElick-lick-lick-lick-lick-lick-Fin'in'in'in'in'in'Eran-ran-ran-ran-ran-ran-EdydydydydydyDdan-dan-dan-dan-dan-dan-E7CdydydydydydyAOOOOOOAmAHeaveAmCaCpawlBohBheaveAa-AwayEWayAheyGBrollAmAandGgoETheEFan-CGchor'sAonGboardGandFtheEcab-GDle'sDallDstoredDToCmeDrol-AmElick-FingEran-EdyDdan-E7CdyAOAmA \ No newline at end of file diff --git a/musicbook/pages/roll-the-old-chariot-along.svg b/musicbook/pages/roll-the-old-chariot-along.svg new file mode 100644 index 0000000..5d3b30d --- /dev/null +++ b/musicbook/pages/roll-the-old-chariot-along.svg @@ -0,0 +1 @@ +Sheet Music for "Roll the Old Chariot Along"Roll the Old Chariot AlongEEADAE= 140We'dWe'llWellWellOhFbebeaaaGall-all-nicenightdropDmA  washonofA  bе-theNelson'sFrightrightlowtownbloodDififwould-would-would-Fthewen'tn'tn'tGwindmakedododoAwasitusususAinroundan-an-an-AourTheyyyFsails.Horn.harm.harm.harm.DWe'dWe'llWellWellOhAbebeaaaAall-all-nicenightdropCG  washonofG  bе-theNelson'sErightrightlowtownbloodCififwould-would-would-Ethewen'tn'tn'tFwindmakedododoGwasitusususGinroundan-an-an-GourTheyyyEsails.Horn.harm.harm.harm.CWe'dWe'llWellWellOhGbebeaaaGall-all-nicenightdropDmA  washonofA  bе-theNelson'sFrightrightlowtownbloodDififwould-would-would-Fthewen'tn'tn'tGwindmakedododoAwasitusususAinroundan-an-an-AourTheyyyFsails.Horn.harm.harm.harm.DAndFwe'llGallFAhangGonA7Fbe-Ehind.DmDAndFwe'llGrollDmAtheFoldDchar-Ai-AotAa-FlongD AWe'llCGrollEtheColdGchar-Gi-GotEa-CWe'llGrollDmAtheFoldDcha-Ar-AiotAa-FlongDAndFwe'llAallFAhangGonA7Fbe-EhindDmD \ No newline at end of file diff --git a/musicbook/pages/south-australia.svg b/musicbook/pages/south-australia.svg new file mode 100644 index 0000000..1ded3bc --- /dev/null +++ b/musicbook/pages/south-australia.svg @@ -0,0 +1 @@ +Sheet Music for "South Australia"South AustraliaPart AInBSouthEGAus-Btral-BiaBICwasBborn.BHeaveACa-BwayEBHaulACa-BwayEBHeaveCa-BwayBHaulCa-BwayBInASouthEGAus-Btral-BiaG'roundB7FCapeGHorn,EEWeEareFboundGforBSouthBAus-Gtral-B7Fia.EEboundGforBSouthBAus-Gtral-Fia.EPart BHeaveAEa-Eway,CyouErol-ClingBkings.EBHeaveACa-Bway,EBhaulACa-BwayEBHeaveAEa-Eway,Cyou'llEhearCmeBsing:EBWeEareFboundGforBSouthBAus-Gtral-B7Fia.EE \ No newline at end of file diff --git a/musicbook/pages/wellerman.svg b/musicbook/pages/wellerman.svg new file mode 100644 index 0000000..c6ec366 --- /dev/null +++ b/musicbook/pages/wellerman.svg @@ -0,0 +1 @@ +Sheet Music for "Wellerman"WellermanThereSheBe-NoForAsGoncehadforelinefort-farCmCwasnotthewasyasCa    I'veCshipbeenboatcut,daysheard,CthattwohadnoortheEputweekshitwhaleev-fight'sGtofromthewasenstillGsea,shore,water,freed,more,onGthewhentheTheTheTheGnamedownwhale'scap-lineline'sFmAof theontailtain'swentnotFshiphercamemindslackcutFwasaupwasthenandAthe    theBBillyrightandnottightwhale'sCmCowhalecaughtofoncenotGTea.bore.her.greed.more.gone.GTheTheAllButAllTheGwindscap-handsheboatsWeller-Cblewtainto the side,be-weremanCup,calledhar-longedlost,makesCherallpoonedtotherehisEbowhandsandthewereregularGdippedandfoughtWhaleman'sonlycallGdown.swore:her,creed.four,ToGOh"We'llwhenShebutencourageGblowtakeshetookstilltheGGmythatdivedthatthatcaptainFbullywhaledownshipwhalecrewEboysinbe-indidandDblow.tow".low.tow.go.all.CmCSoonAâ™­CmayCtheAWel-Eâ™­Bler-BmanGcomeGtoGbringFmAusFsu-FgarGandAteaCmGandErumCOneAâ™­CdayCtheAton-Eâ™­BguinBisGdoneGwe'llGtakeGGourFleaveEandDgoCmC \ No newline at end of file diff --git a/musicbook/pages/whiskey-johnny.svg b/musicbook/pages/whiskey-johnny.svg new file mode 100644 index 0000000..2ba3503 --- /dev/null +++ b/musicbook/pages/whiskey-johnny.svg @@ -0,0 +1 @@ +Sheet Music for "Whiskey Johnny"Whiskey JohnnyWhisk-EBeyBisBtheElifeCofAmanBWhisk-Gey,BJohn-Gny!BWhisk-Gey,BJohn-Gny!BI'llDBdrinkBwhisk-BeyCwhileGIFcanEWhisk-ABeyBforBmyCJohn-GnyFOh!EWhisk-BeyBforBmyCJohn-GnyFOh!E \ No newline at end of file diff --git a/musicbook/proof.html b/musicbook/proof.html new file mode 100644 index 0000000..be7fd2d --- /dev/null +++ b/musicbook/proof.html @@ -0,0 +1,192 @@ + + + + + +Sea Shanties — Music + + + +
+
Sea
Shanties
+
Music Edition
+ +
+
+
+
+ Staff notation for All For Me Grog +
+
3
+
+ Staff notation for Barrett's Privateers +
+
4
+
+ Staff notation for Bully Boys +
+
5
+
+ Staff notation for Bully in the Alley +
+
6
+
+ Staff notation for Drunken Sailor +
+
7
+
+ Staff notation for Health to the Company +
+
8
+
+ Staff notation for Joli Rouge +
+
9
+
+ Staff notation for Leave Her Johnny +
+
10
+
+ Staff notation for Mingulay Boat Song +
+
11
+
+ Staff notation for Randy Dandy-O +
+
12
+
+ Staff notation for Roll the Old Chariot Along +
+
13
+
+ Staff notation for South Australia +
+
14
+
+ Staff notation for Wellerman +
+
15
+
+ Staff notation for Whiskey Johnny +
+
16
+ + diff --git a/musicbook/randy-dandy-o.html b/musicbook/randy-dandy-o.html new file mode 100644 index 0000000..3d30144 --- /dev/null +++ b/musicbook/randy-dandy-o.html @@ -0,0 +1,3 @@ +
+ Staff notation for Randy Dandy-O +
diff --git a/musicbook/roll-the-old-chariot-along.html b/musicbook/roll-the-old-chariot-along.html new file mode 100644 index 0000000..9decb12 --- /dev/null +++ b/musicbook/roll-the-old-chariot-along.html @@ -0,0 +1,3 @@ +
+ Staff notation for Roll the Old Chariot Along +
diff --git a/musicbook/sea-shanties-music.html b/musicbook/sea-shanties-music.html new file mode 100644 index 0000000..e8243db --- /dev/null +++ b/musicbook/sea-shanties-music.html @@ -0,0 +1,189 @@ + + + + + +Sea Shanties — Music + + + +
+ Staff notation for Whiskey Johnny +
+
16
+
Sea
Shanties
+
Music Edition
+ +
+
+
+ Staff notation for Wellerman +
+
15
+
+ Staff notation for South Australia +
+
14
+ Staff notation for All For Me Grog +
+
3
+
+ Staff notation for Barrett's Privateers +
+
4
+ Staff notation for Roll the Old Chariot Along +
+
13
+
+ Staff notation for Randy Dandy-O +
+
12
+ Staff notation for Bully Boys +
+
5
+
+ Staff notation for Bully in the Alley +
+
6
+ Staff notation for Mingulay Boat Song +
+
11
+
+ Staff notation for Leave Her Johnny +
+
10
+ Staff notation for Drunken Sailor +
+
7
+
+ Staff notation for Health to the Company +
+
8
+ Staff notation for Joli Rouge +
+
9
+ + diff --git a/musicbook/south-australia.html b/musicbook/south-australia.html new file mode 100644 index 0000000..9ba6177 --- /dev/null +++ b/musicbook/south-australia.html @@ -0,0 +1,3 @@ +
+ Staff notation for South Australia +
diff --git a/musicbook/wellerman.html b/musicbook/wellerman.html new file mode 100644 index 0000000..180a91c --- /dev/null +++ b/musicbook/wellerman.html @@ -0,0 +1,3 @@ +
+ Staff notation for Wellerman +
diff --git a/musicbook/whiskey-johnny.html b/musicbook/whiskey-johnny.html new file mode 100644 index 0000000..f72f7bc --- /dev/null +++ b/musicbook/whiskey-johnny.html @@ -0,0 +1,3 @@ +
+ Staff notation for Whiskey Johnny +
From 96c00ae2f44f223bbdc7167920b2e4b223105dac Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:28:05 -0700 Subject: [PATCH 3/5] Changes to get set working on Windows and in agent --- .gitignore | 1 + .vscode/mcp.json | 9 +++++ .vscode/settings.json | 25 +++++++++++++ package.json | 8 +++-- patches/pug-pack+1.11.0.patch | 67 +++++++++++++++++++++++++++++++++++ songs-to-json | 29 --------------- songs-to-json.js | 27 ++++++++++++++ 7 files changed, 135 insertions(+), 31 deletions(-) create mode 100644 .vscode/mcp.json create mode 100644 .vscode/settings.json create mode 100644 patches/pug-pack+1.11.0.patch delete mode 100755 songs-to-json create mode 100644 songs-to-json.js diff --git a/.gitignore b/.gitignore index f90e636..d3f616a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ node_modules yarn.lock package-lock.json +.playwright-mcp/ diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000..137db1f --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,9 @@ +{ + "servers": { + "playwright": { + "command": "npx", + "args": ["-y", "@playwright/mcp", "--headless", "--browser", "chromium"] + } + }, + "inputs": [] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..f5e51f1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,25 @@ +{ + // Workspace-level auto-approve list. Lives in the repo so it roams across + // all machines via git. Per-machine overrides go in %APPDATA%\Code\User\settings.json. + // + // Design rule: ONLY read-only / stdout-only cmdlets and a CLOSED, enumerated + // list of helper scripts may auto-approve. Nothing that writes to disk, + // executes an arbitrary script block, or names an unknown script belongs here. + // + // See .github/skills/_shared/scripts/README.md for the rationale and full mechanism. + "chat.tools.terminal.autoApprove": { + // --- Read-only inspection (no side effects) --- + "Test-Path": true, + "Get-Item": true, + "Get-ItemProperty": true, + "Get-Date": true, + // --- Read-only data shaping (stdout only; no -FilePath/-Path writes, + // no script-block execution) --- + "Group-Object": true, + "ConvertFrom-Json": true, + "ConvertTo-Json": true, + "ConvertFrom-Csv": true, + "ConvertTo-Csv": true, + "Out-String": true, + } +} \ No newline at end of file diff --git a/package.json b/package.json index b895458..13648f9 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,19 @@ { "scripts": { - "build": "./songs-to-json && pug-pack src && cp Songbook.pdf dist && cp qr-code.svg dist", + "postinstall": "patch-package", + "build": "node songs-to-json.js && pug-pack src && node -e \"const fs=require('fs');for(const f of ['Songbook.pdf','qr-code.svg'])fs.cpSync(f,'dist/'+f)\"", "booklet": "node node_modules/markdown-booklet/src/cli.js build booklet/book.yaml --out booklet/sea-shanties.html", "booklet:proof": "node node_modules/markdown-booklet/src/cli.js build booklet/book.yaml --reading --out booklet/proof.html", + "musicbook": "node node_modules/markdown-booklet/src/cli.js build musicbook/book.yaml --out musicbook/sea-shanties-music.html", + "musicbook:proof": "node node_modules/markdown-booklet/src/cli.js build musicbook/book.yaml --reading --out musicbook/proof.html", "scaleL": "coffee src/transform.coffee scaleL", - "dev": "nodemon -w src -w songs -i src/songs.json -i src/by-title.json -e '*' -x npm run build" + "dev": "nodemon -w src -w songs -i src/songs.json -i src/by-title.json -e \"*\" -x npm run build" }, "devDependencies": { "coffeescript": "^2.7.0", "markdown-booklet": "github:chrisglein/markdown-booklet", "nodemon": "^2.0.22", + "patch-package": "^8.0.1", "pug-pack": "brewingcode/pug-pack" }, "dependencies": { diff --git a/patches/pug-pack+1.11.0.patch b/patches/pug-pack+1.11.0.patch new file mode 100644 index 0000000..f07fe03 --- /dev/null +++ b/patches/pug-pack+1.11.0.patch @@ -0,0 +1,67 @@ +diff --git a/node_modules/pug-pack/lib/build.coffee b/node_modules/pug-pack/lib/build.coffee +index da9318b..359c63a 100644 +--- a/node_modules/pug-pack/lib/build.coffee ++++ b/node_modules/pug-pack/lib/build.coffee +@@ -66,13 +66,18 @@ module.exports = self = + + out + ++ # compile :coffeescript blocks with our bundled compiler, so the build ++ # doesn't depend on pug hoisting jstransformer-coffeescript to top-level ++ coffeescript: (text, options) -> ++ coffeescript.compile text ++ + # replacement for path.parse(), but in the context of this module + parsename: (f) -> + parts = path.parse f + parts.ext = parts.ext.replace /^\./, '' + parts.absfile = path.resolve self.vars.basedir, f + parts.absdir = path.resolve self.vars.basedir +- parts.srcname = parts.absfile.replace(new RegExp(parts.absdir, 'i'), '').replace(/^\//, '') ++ parts.srcname = path.relative(parts.absdir, parts.absfile).split(path.sep).join('/') + self.vars.files[parts.srcname] = parts.absfile + parts + +@@ -176,23 +181,33 @@ module.exports = self = + # 1, for example + crawl: (rootDir, skipPug) -> + self.vars.basedir = path.resolve rootDir ++ gitOpts = { cwd: self.vars.basedir } ++ ++ walkFiles = (dir) -> ++ results = [] ++ for entry in fs.readdirSync dir ++ full = path.join dir, entry ++ if fs.statSync(full).isDirectory() ++ results = results.concat walkFiles full ++ else ++ results.push full ++ results + +- execAsync("cd '#{self.vars.basedir}' && git rev-parse --short HEAD").then (stdout) => ++ execAsync("git rev-parse --short HEAD", gitOpts).then (stdout) => + self.vars.src.GIT_HEAD = stdout.toString().trim() +- .catch -> ++ .catch => + self.vars.src.GIT_HEAD = null +- +- if head = self.vars.src.GIT_HEAD +- execAsync("cd '#{self.vars.basedir}' && git tag --points-at #{head}").then (stdout) => ++ .then => ++ return unless head = self.vars.src.GIT_HEAD ++ execAsync("git tag --points-at #{head}", gitOpts).then (stdout) => + self.vars.src.GIT_TAGS = stdout.toString().split('\n').filter (s) -> s.match(/\S/) +- .catch -> ++ .catch => + self.vars.src.GIT_TAGS = [] +- +- execAsync("find '#{self.vars.basedir}' -type f -print0").then (stdout) => ++ .then => + pug_files = [] + other_files = [] + +- stdout.split('\0').forEach (f) => ++ walkFiles(self.vars.basedir).forEach (f) => + return unless f + { name, ext, srcname } = self.parsename f + if name.match(/^_/) diff --git a/songs-to-json b/songs-to-json deleted file mode 100755 index b5e59f6..0000000 --- a/songs-to-json +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python3 - -import os, json, re -songs = {} -byTitle = {} -for f in os.listdir('songs'): - if not re.search(r'\.txt$', f, re.I): - continue - - try: - with open('songs/' + f) as fh: - song = fh.read() - except: - with open('songs/' + f, encoding='latin-1') as fh: - song = fh.read() - - songs[f] = song - - m = re.search(r'^T:\s*(.*)', song, re.MULTILINE) - if m: - title = m.group(1) - byTitle[title] = song - - else: - print('weird song:', f) -with open('src/songs.json', 'w') as fh: - fh.write(json.dumps(songs)) -with open('src/by-title.json', 'w') as fh: - fh.write(json.dumps(byTitle)) diff --git a/songs-to-json.js b/songs-to-json.js new file mode 100644 index 0000000..b2b0632 --- /dev/null +++ b/songs-to-json.js @@ -0,0 +1,27 @@ +const fs = require('fs'); +const path = require('path'); + +const songsDir = 'songs'; +const songs = {}; +const byTitle = {}; + +for (const f of fs.readdirSync(songsDir)) { + if (!/\.txt$/i.test(f)) continue; + + const buf = fs.readFileSync(path.join(songsDir, f)); + let song = buf.toString('utf8'); + if (song.includes('\uFFFD')) song = buf.toString('latin1'); + song = song.replace(/\r\n/g, '\n'); + + songs[f] = song; + + const m = song.match(/^T:\s*(.*)/m); + if (m) { + byTitle[m[1]] = song; + } else { + console.log('weird song:', f); + } +} + +fs.writeFileSync('src/songs.json', JSON.stringify(songs)); +fs.writeFileSync('src/by-title.json', JSON.stringify(byTitle)); From 296e237d83d3a73864c337484455e314cbc214dd Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Wed, 1 Jul 2026 09:55:09 -0700 Subject: [PATCH 4/5] Add Old Maui --- musicbook/book.yaml | 7 ++++--- musicbook/old-maui.html | 3 +++ musicbook/pages/old-maui.svg | 1 + musicbook/proof.html | 5 ++++- musicbook/sea-shanties-music.html | 5 ++++- 5 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 musicbook/old-maui.html create mode 100644 musicbook/pages/old-maui.svg diff --git a/musicbook/book.yaml b/musicbook/book.yaml index e57cb11..6bb8116 100644 --- a/musicbook/book.yaml +++ b/musicbook/book.yaml @@ -16,11 +16,12 @@ config: # Staff notation captured from the running site at # ?file=.txt&fullscreen=true&verses=false -# Each song is a single page (no spreads). Order mirrors the lyrics songbook. -# (skipper-jan-rebec is omitted — it has no ABC/staff notation on the site.) +# Each song is a single page (no spreads). Order mirrors the lyrics songbook, +# with Old Maui filling what was the blank second page (cover + 15 = 16 pages). +# (skipper-jan-rebec now has ABC on master but is not included here yet.) pages: - { file: cover.html, showPageNumber: false } - - blank + - { file: old-maui.html } - { file: all-for-me-grog.html } - { file: barretts-privateers.html } - { file: bully-boys.html } diff --git a/musicbook/old-maui.html b/musicbook/old-maui.html new file mode 100644 index 0000000..0725e8a --- /dev/null +++ b/musicbook/old-maui.html @@ -0,0 +1,3 @@ +
+ Staff notation for Old Maui +
diff --git a/musicbook/pages/old-maui.svg b/musicbook/pages/old-maui.svg new file mode 100644 index 0000000..35c1962 --- /dev/null +++ b/musicbook/pages/old-maui.svg @@ -0,0 +1 @@ +Sheet Music for "Old Maui"Old MauiVerseIt'sBaBdamnEmEtoughElifeBDfullBofBtoilGGandF EstrifeDFweB Awha-EmGler-FmenEun-BFder-D Ego,EmEandBweBdon'tEmEgiveEaEdamnBDwhenBtheBgaleGGisF EdoneDFhowB AhardEmGtheEwindsBFdidD Eblow,EmEforGwe'reAhome-GBwardBboundBfromAtheGArc-DAticAgroundAwithGaFgoodEmGshipGtautGandEfree,BFandBweBdon'tEmEgiveEaEdamnBDwhenBweBdrinkGGourF ErumDFwithBtheAgirlsEmGofEoldBFMau-DE---> Chorusi,EmEroll-Gin'AdownGBtoBoldBMau-A Gi,DAmeAboys,Arol-Blin'AdownEmGtoGoldGMau-E Fi,BFwe'reBhomeEmEwardEboundBDfromBtheBArc-GGticF Eground,DFrol-Blin'AdownEmGtoEoldBFMau-D EiEmE \ No newline at end of file diff --git a/musicbook/proof.html b/musicbook/proof.html index be7fd2d..71821c5 100644 --- a/musicbook/proof.html +++ b/musicbook/proof.html @@ -131,7 +131,10 @@ -
+
+ Staff notation for Old Maui +
+
2
Staff notation for All For Me Grog
diff --git a/musicbook/sea-shanties-music.html b/musicbook/sea-shanties-music.html index e8243db..b109b4e 100644 --- a/musicbook/sea-shanties-music.html +++ b/musicbook/sea-shanties-music.html @@ -139,7 +139,10 @@
-
+
+ Staff notation for Old Maui +
+
2
Staff notation for Wellerman
15
From dd12ec5591e631bf557f5a656733e73f694fa746 Mon Sep 17 00:00:00 2001 From: Chris <26607885+chrisglein@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:11:48 -0700 Subject: [PATCH 5/5] Agent written instructions and documentation --- .github/copilot-instructions.md | 8 ++++++ AGENTS.md | 44 +++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 AGENTS.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..edc784f --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,8 @@ +# Copilot instructions — shanties + +**The primary artifact is the website** (`src/`): an interactive ABC-notation songbook — pick or type a song and abcjs live-renders staff notation, with transpose and lyrics / verses / guitar-tab / trumpet-fingering toggles. It deploys to https://brewingcode.github.io/shanties. The two printable **booklets** (`booklet/` = lyrics, `musicbook/` = staff) are secondary artifacts derived from the same `songs/`. **Read `AGENTS.md` for site architecture, URL params/filters, and the booklet/music-capture pipelines before any non-trivial change.** + +- Build the site: `npm run build` (Node-only, cross-platform → `dist/`). Serve with live reload: `npx pug-pack src -w` (http://localhost:3000); `npm run dev` rebuilds but does **not** serve. +- `src/songs.json` + `src/by-title.json` are generated & gitignored — run a build if they're missing. +- The Windows build is already fixed via `patches/pug-pack+1.11.0.patch` (applied by `postinstall`/patch-package). Don't re-diagnose or revert it. +- Prefer Node built-ins over new deps; don't leave throwaway scripts; this is a PowerShell box — use single-line commands. diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1a1c5db --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,44 @@ +# AGENTS.md — shanties + +Fuller agent guide for the sea-shanties project. The always-loaded essentials live in `.github/copilot-instructions.md`; read this file for anything beyond a trivial change. + +The repo's **primary purpose is the website** (`src/`) — an interactive ABC-notation songbook. The two printable saddle-stitch booklets are secondary artifacts derived from the same `songs/`. The site deploys to https://brewingcode.github.io/shanties by `.github/workflows/gh-pages.yml` (Ubuntu, Node 20, `npm install` + `npm run build`). + +## Build & run +- `npm run build` — site → `dist/`: runs `songs-to-json.js`, then `pug-pack src`, then copies `Songbook.pdf` + `qr-code.svg`. Cross-platform (Node only — no python/`cp`). +- Serve locally with live reload: `npx pug-pack src -w` → http://localhost:3000 (browserSync). `npm run dev` watches + rebuilds but does not serve. +- `npm run booklet` / `booklet:proof` / `booklet:single` — lyrics booklet (`booklet/`). +- `npm run musicbook` / `musicbook:proof` — staff-notation booklet (`musicbook/`). +- Syntax-check CoffeeScript snippets by piping (dedented) to `npx coffee -s -c -p`. + +## The website (`src/`) — the primary artifact +Interactive ABC songbook: type ABC into `#abc` (or pick a song from the dropdown, or click "add a song" → GitHub `songs/`), and abcjs live-renders staff notation into `#paper`. Settings toggle inline lyrics (`#show-lyrics`), extended verses (`#show-verses`), trumpet fingering (`#show-trumpet`), and guitar tab (`#show-gtab`); `#transpose` shifts the key and shows from/to in `#fromKey`/`#toKey`. Parse warnings render to `#warnings`; on iPad the textarea sits behind an Edit button. +- `src/index.pug` is the whole page (extends pug-pack `_base`). All logic is CoffeeScript in a `:coffeescript` filter; abcjs/jquery/bootstrap are `include`d and inlined into one big `dist/index.html`. +- `songs/*.txt` are ABC songs. `songs-to-json.js` generates `src/songs.json` (keyed by filename) + `src/by-title.json` (keyed by `T:` title) — both are **generated and gitignored**; run a build if they're missing. +- abcjs renders into `#paper`. UI chrome is tagged `.noprint` (hidden in print and when `body.fullscreen`). +- URL params: `title=` / `file=` pick a song; `fullscreen=true` hides chrome; `lyrics=false`, `verses=false` hide inline / extended lyrics (read before first render). +- `setSong` filters ABC lines pre-render: lowercase `w:` = inline lyrics (or trumpet fingering if all digits), uppercase `W:` = extended verses. +- ABC songs use `%%` directives (e.g. `%%notelabels`, `%%notecolors`, `%%vocalfont`) alongside standard fields (`T:`, `M:`, `K:`, `w:`/`W:`). + +## Booklets (markdown-booklet) +- Engine: `node node_modules/markdown-booklet/src/cli.js build /book.yaml [--out … | --reading | --single]`. +- `booklet/` = lyrics (Markdown, two-page spreads). `musicbook/` = staff notation (single `type: html` pages, no spreads), parallel to the lyrics book. +- Song list source of truth is `booklet/book.yaml`. Before assuming a song has staff notation, confirm its `songs/.txt` exists (e.g. `skipper-jan-rebec` was booklet-only for a while). + +## Music-book staff capture (`musicbook/pages/*.svg`) +Each staff SVG is captured from the running site. To (re)generate one: +1. Serve the site (`npx pug-pack src -w`). +2. Headlessly load `?file=.txt&fullscreen=true&verses=false`, grab `#paper svg` outerHTML (strip its inline `style`, set `width=100%`, remove `height`). +3. **Post-process — required, or `` renders broken:** add `xmlns="http://www.w3.org/2000/svg"` to the root `` (abcjs omits it, so the standalone file is invalid XML) and replace ` ` → ` ` (` ` is undefined in standalone XML/SVG). Write UTF-8, no BOM. +The abcjs SVG already renders the `T:` title, so pages need no extra heading; `.staff img` fit-contains within the page (`music.css`). Each `.html` is just `
`. + +## Cross-platform — do not undo +- Windows builds work via **patch-package**: `patches/pug-pack+1.11.0.patch` (applied by the `postinstall` script) fixes pug-pack's Unix-`find` call, its Windows path/regex `srcname` bug, the git `cwd`, and registers a `coffeescript` pug filter (so it no longer depends on hoisting `jstransformer-coffeescript`). Don't revert these or re-diagnose "pug-pack broken on Windows". +- `pug-pack` is an **unpinned git-branch** dependency — if it changes upstream the patch may need refreshing (`npx patch-package pug-pack`). + +## Conventions & gotchas +- Prefer Node built-ins over new dependencies (e.g. `fs.cpSync`, not `shx`). +- Don't write throwaway scripts merely to execute them; validate by reasoning or a one-off inline command. Delete one-shot data-fix scripts after use. +- Don't hard-wrap Markdown to a fixed column width. +- This is a Windows/PowerShell dev box — prefer single-line commands; multi-line array/here-string pastes can mangle in the persistent shell. +- `.playwright-mcp/` is scratch output and is gitignored.