Skip to content

Commit

Permalink
feat: generate pdf
Browse files Browse the repository at this point in the history
  • Loading branch information
bellstrand committed Sep 27, 2024
1 parent 5262a74 commit 111c14d
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 91 deletions.
34 changes: 34 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Release
on:
release:
types: [published]

permissions:
contents: write

jobs:
release:
timeout-minutes: 5
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2

- name: Install dependencies
run: bun install

- name: Install Playwright Browsers
run: npx playwright install --with-deps chromium

- name: Generate PDF's
run: bun generate

- name: Upload PDF's
run: |
for file in ./storage/*.pdf; do
echo "$file"
gh release upload ${{github.event.release.tag_name}} "$file"
done
env:
GITHUB_TOKEN: ${{ github.TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

node_modules/

storage/
Binary file added bun.lockb
Binary file not shown.
43 changes: 43 additions & 0 deletions generate-pdf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { readdir } from 'node:fs/promises';
import { chromium } from "playwright-core";

const dir = import.meta.dirname;

async function generate() {
const browser = await chromium.launch({ headless: true, args: ["--disable-web-security"] })
const page = await browser.newPage({ bypassCSP: true })
page.addInitScript((dir) => {
window.addEventListener('DOMContentLoaded', () => {
const html = document.querySelector("html") as HTMLHtmlElement
html.innerHTML = html?.innerHTML.replace("/style.css", `file:///${dir}/style.css`).replaceAll("/images/", `file:///${dir}/images/`)
});
}, dir);

const files = (await readdir("./sets")).filter((f) => f !== "template.html")

for(const file of files) {
page.goto(`file:///${dir}/sets/${file}`)
await page.waitForLoadState()
// console.info("waitForLoadState")
await page.waitForSelector("page")
// console.log("waitForSelector")
await page.waitForLoadState("domcontentloaded")
await page.waitForLoadState("networkidle")

const title = (await page.title()).replaceAll(":", " ")

await page.pdf({
path: `./storage/${title}.pdf`,
printBackground: false,
scale: 1,
width: "21cm",
height: "29.7cm"
})
console.info(`Generated "${title}.pdf" PDF`)
}
await page.close()

process.exit(0)
}

void generate()
7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"scripts": {
"generate": "bun ./generate-pdf.ts",
"dev:mkm": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/mkm.html'",
"dev:lotr": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/lotr.html'",
"dev:ltr": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/ltr.html'",
"dev:vow": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/vow.html'",
"dev:otj": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/otj.html'",
"dev:mh3": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/mh3.html'",
Expand All @@ -11,6 +12,10 @@
"dev:dsk": "browser-sync start --server --no-inject-changes --files './' --startPath '/sets/dsk.html'"
},
"devDependencies": {
"@types/bun": "^1.1.10",
"browser-sync": "^3.0.2"
},
"dependencies": {
"playwright": "^1.47.2"
}
}
201 changes: 111 additions & 90 deletions sets/dsk.html
Original file line number Diff line number Diff line change
@@ -1,114 +1,135 @@
<!DOCTYPE html>
<html>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="/style.css" />
<title>Archetypes</title>
</head>
<body>
<page size="A4">
<div class="title">Duskmourn: House of Horrors</div>
<h1>Archetypes</h1>
<div class="archetypes">
<div class="archetype">
<h2>Eerie Midrange</h2>
<img src="/images\dsk\Gremlin_Tamer.jpg" alt="Gremlin Tamer" />
<span>Search the House! Play lots of enchantments and unlock Rooms to power up your creatures and get around all the horrifying blockers your opponent might throw your way.</span>
</div>

<div class="archetype">
<h2>Eerie Control</h2>
<img src="/images\dsk\Fear_of_Infinity.jpg" alt="Fear of Infinity" />
<span>Live out your worst nightmares and share them with your opponent, unlocking Rooms and playing enchantments to kill off their creatures and seize control of the game.</span>
</div>

<div class="archetype">
<h2>Sacrifice</h2>
<img src="/images\dsk\Sawblade_Skinripper.jpg" alt="Sawblade Skinripper" />
<span>Want to slash through opposing creatures and your opponent with ease? Pay the price for strength by sacrificing your own creatures and old Rooms.</span>
</div>

<div class="archetype">
<h2>Delirium Midrange</h2>
<img src="/images\dsk\Wildfire_Wickerfolk.jpg" alt="Wildfire Wickerfolk" />
<span>Fill your deck with artifact and enchantment creatures (along with other card types), and attack early and often. Once you get four different card types into your graveyard, your cards power up. Then go for the jugular!</span>
</div>

<div class="archetype">
<h2>Survival</h2>
<img src="/images\dsk\Shrewd_Storyteller.jpg" alt="Shrewd Storyteller" />
<span>Utilize all of Duskmourn's tricks to power up your creatures and help them smash their way to safety. Find other ways to tap them and hide until the danger's past.</span>
</div>
</div>
<div class="archetypes">
<div class="archetype">
<h2>Reanimator</h2>
<img src="/images\dsk\Shroudstomper.jpg" alt="Shroudstomper" />
<span>All hail Valgavoth! Slow your opponent down while you get enormous monsters into your graveyard and then perform the rituals to return them to life.</span>
</div>

<div class="archetype">
<h2>Rooms</h2>
<img src="/images\dsk\Intruding_Soulrager.jpg" alt="Intruding Soulrager" />
<span>The House never ends! Trap your opponent going in circles as you unlock Rooms to build up control of more and more territory, then unleash the ghosts held within for a frightening finish.</span>
</div>

<div class="archetype">
<h2>Graveyard</h2>
<img src="/images\dsk\Broodspinner.jpg" alt="Broodspinner" />
<span>Prioritize getting a wide variety of card types, then gum up the board as you fill your graveyard with them. Once you've got at least four, grind your opponent to dust by recycling what you've thrown away.</span>
</div>

<div class="archetype">
<h2>Power Aggro</h2>
<img src="/images\dsk\Arabella__Abandoned_Doll.jpg" alt="Arabella, Abandoned Doll" />
<span>Fill your deck with Toys, Clowns, and other creatures that have 2 or less power and start attacking! Smash your opponents swiftly by clearing out their blockers and buffing your little creatures.</span>
</div>

<div class="archetype">
<h2>Manifest Dread</h2>
<img src="/images\dsk\Oblivious_Bookworm.jpg" alt="Oblivious Bookworm" />
<span>Something's lurking in the shadows. Manifest face-down creatures and get them into combat, then surprise your opponent with their true forms to outsize the competition.</span>
</div>
</div>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" type="text/css" href="/style.css" />
<title>Duskmourn: House of Horrors [Draft]</title>
</head>

<h1>Mechanics</h1>
<body>
<page size="A4">
<div class="title">Duskmourn: House of Horrors</div>

<h1>Archetypes</h1>
<div class="archetypes">
<div class="archetype">
<h2>Eerie Midrange</h2>
<img src="/images/dsk/Gremlin_Tamer.jpg" alt="Gremlin Tamer" />
<span>Search the House! Play lots of enchantments and unlock Rooms to power up your creatures and get
around all the horrifying blockers your opponent might throw your way.</span>
</div>

<div class="archetype">
<h2>Eerie Control</h2>
<img src="/images/dsk/Fear_of_Infinity.jpg" alt="Fear of Infinity" />
<span>Live out your worst nightmares and share them with your opponent, unlocking Rooms and playing
enchantments to kill off their creatures and seize control of the game.</span>
</div>

<div class="archetype">
<h2>Sacrifice</h2>
<img src="/images/dsk/Sawblade_Skinripper.jpg" alt="Sawblade Skinripper" />
<span>Want to slash through opposing creatures and your opponent with ease? Pay the price for strength
by sacrificing your own creatures and old Rooms.</span>
</div>

<div class="archetype">
<h2>Delirium Midrange</h2>
<img src="/images/dsk/Wildfire_Wickerfolk.jpg" alt="Wildfire Wickerfolk" />
<span>Fill your deck with artifact and enchantment creatures (along with other card types), and attack
early and often. Once you get four different card types into your graveyard, your cards power up.
Then go for the jugular!</span>
</div>

<div class="archetype">
<h2>Survival</h2>
<img src="/images/dsk/Shrewd_Storyteller.jpg" alt="Shrewd Storyteller" />
<span>Utilize all of Duskmourn's tricks to power up your creatures and help them smash their way to
safety. Find other ways to tap them and hide until the danger's past.</span>
</div>
</div>
<div class="archetypes">
<div class="archetype">
<h2>Reanimator</h2>
<img src="/images/dsk/Shroudstomper.jpg" alt="Shroudstomper" />
<span>All hail Valgavoth! Slow your opponent down while you get enormous monsters into your graveyard
and then perform the rituals to return them to life.</span>
</div>

<div class="archetype">
<h2>Rooms</h2>
<img src="/images/dsk/Intruding_Soulrager.jpg" alt="Intruding Soulrager" />
<span>The House never ends! Trap your opponent going in circles as you unlock Rooms to build up control
of more and more territory, then unleash the ghosts held within for a frightening finish.</span>
</div>

<div class="archetype">
<h2>Graveyard</h2>
<img src="/images/dsk/Broodspinner.jpg" alt="Broodspinner" />
<span>Prioritize getting a wide variety of card types, then gum up the board as you fill your graveyard
with them. Once you've got at least four, grind your opponent to dust by recycling what you've
thrown away.</span>
</div>

<div class="archetype">
<h2>Power Aggro</h2>
<img src="/images/dsk/Arabella__Abandoned_Doll.jpg" alt="Arabella, Abandoned Doll" />
<span>Fill your deck with Toys, Clowns, and other creatures that have 2 or less power and start
attacking! Smash your opponents swiftly by clearing out their blockers and buffing your little
creatures.</span>
</div>

<div class="archetype">
<h2>Manifest Dread</h2>
<img src="/images/dsk/Oblivious_Bookworm.jpg" alt="Oblivious Bookworm" />
<span>Something's lurking in the shadows. Manifest face-down creatures and get them into combat, then
surprise your opponent with their true forms to outsize the competition.</span>
</div>
</div>

<h1>Mechanics</h1>
<div class="mechanics">
<div class="mechanic">
<h2>Rooms</h2>
<span>Enchantment - Room (You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)</span>
<span>Enchantment - Room (You may cast either half. That door unlocks on the battlefield. As a sorcery,
you may pay the mana cost of a locked door to unlock it.)</span>
</div>
<div class="mechanic">
<h2>Umbra Armor</h2>
<span>Former: "Totem Armor". Umbra armor appears on Aura cards. If a
creature enchanted by an Aura with umbra armor would be destroyed,
instead that Aura is destroyed and all damage dealt to the creature
<span>Former: "Totem Armor". Umbra armor appears on Aura cards. If a creature enchanted by an Aura with
umbra armor would be destroyed, instead that Aura is destroyed and all damage dealt to the creature
is removed.
</span>
</div>
<div class="mechanic">
<h2>Impending</h2>
<span>Impending [X] — (If you cast this spell for its impending cost, it enters with [X] time counters and isn't a creature until the last is removed. At the beginning of your end step, remove a time counter from it.)
<span>Impending [X] — (If you cast this spell for its impending cost, it enters with [X] time counters
and isn't a creature until the last is removed. At the beginning of your end step, remove a time
counter from it.)
</span>
</div>
<div class="mechanic">
<h2>Manifest Dread</h2>
<span>(Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2 creature and the other into your graveyard. Turn it face up any time for its mana cost if it's a creature card.)</span>
<span>(Look at the top two cards of your library. Put one onto the battlefield face down as a 2/2
creature and the other into your graveyard. Turn it face up any time for its mana cost if it's a
creature card.)</span>
</div>
<div class="mechanic">
<h2>Survival</h2>
<span>Survival — At the beginning of your second main phase, if [CARNDAME] is tapped, you gain 2 life.</span>
<span>Survival — At the beginning of your second main phase, if [CARNDAME] is tapped, you gain 2
life.</span>
</div>
<div class="mechanic">
<div class="mechanic">
<h2>Eerie</h2>
<span>Eerie — Whenever an enchantment you control enters and whenever you fully unlock a Room, put a +1/+1 counter on target creature.</span>
<span>Eerie — Whenever an enchantment you control enters and whenever you fully unlock a Room, put a
+1/+1 counter on target creature.</span>
</div>
</div>
</page>
</body>
</html>
</page>
</body>

</html>
27 changes: 27 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"compilerOptions": {
// Enable latest features
"lib": ["ESNext", "DOM"],
"target": "ESNext",
"module": "ESNext",
"moduleDetection": "force",
"jsx": "react-jsx",
"allowJs": true,

// Bundler mode
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"verbatimModuleSyntax": true,
"noEmit": true,

// Best practices
"strict": true,
"skipLibCheck": true,
"noFallthroughCasesInSwitch": true,

// Some stricter flags
"noUnusedLocals": true,
"noUnusedParameters": true,
"noPropertyAccessFromIndexSignature": true,
},
}

0 comments on commit 111c14d

Please sign in to comment.