139 lines
6.0 KiB
Markdown
139 lines
6.0 KiB
Markdown
# BrevyScribe
|
|
|
|
BrevyScribe is a fork of [FancyScribe](https://github.com/NilsUeter/fancyscribe).
|
|
It prints **generic datasheets** instead of a record of one army list.
|
|
|
|
FancyScribe shows a BattleScribe or New Recruit roster as 10th-edition
|
|
datacards. The cards show only the wargear that you selected. That is correct
|
|
for a list that you play today. It is not correct for a reference card that you
|
|
keep, because the official cards show *every* option of a unit. BrevyScribe
|
|
rewrites the roster before it renders the cards. As a result, the printed cards
|
|
read like the official ones.
|
|
|
|
Three transforms do this work. You can switch each one on or off in the user
|
|
interface.
|
|
|
|
| Transform | What it does |
|
|
| --- | --- |
|
|
| **Merge duplicates** | Mutually exclusive wargear makes you take one datasheet two times. One Skatros has a radium jezzail, another has a transuranic arquebus. This transform folds the copies of a unit into one card that carries all options. |
|
|
| **Drop Leader/Support** | This transform removes the attachment rules. After the army is built, these rules tell you nothing that you need during a game. They are also long, and they push the necessary rules off the card. |
|
|
| **Split choice abilities** | An ability such as *Canticles of the Omnissiah* arrives as one block of text. This transform divides it into the intro rule and one titled row for each option. The official datasheets print it in this form. |
|
|
|
|
The app does all of its work in the browser. There is no server component, no
|
|
upload, no account and no analytics. Rosters stay in `localStorage` and never
|
|
leave your machine.
|
|
|
|
## Lore text
|
|
|
|
Official datasheets print a paragraph of flavor text to the right of the model
|
|
image. The **Show Lore Text** toggle prints this text. The card then gives the
|
|
right third of its image to the text, behind a gradient that fades the image
|
|
into the dark. Cards without an entry keep the full-width image.
|
|
|
|
[`public/Lore.csv`](public/Lore.csv) supplies the text. The file is a
|
|
pipe-delimited export in this form:
|
|
|
|
```
|
|
name|legend
|
|
Custodian Guard|These warriors form the backbone of the shield companies, ...
|
|
```
|
|
|
|
The app fetches this file only when a roster is on screen. A missing or bad
|
|
file means that the cards print without lore text.
|
|
|
|
The names in a roster do not match the export exactly, so the app searches for
|
|
the closest entry. This search is a heuristic, and you can correct it:
|
|
|
|
- To change the text of a card, edit it in place. The app keeps your edit in
|
|
`localStorage` under `lore_<unit name>`. If you clear the edit, the text of
|
|
the export comes back.
|
|
- If the export does not cover a unit, the card shows an **Add lore** button.
|
|
|
|
About 40 names carry lore for more than one faction. Chaos Daemons and Death
|
|
Guard both field Plaguebearers, and three armies field a Ministorum Priest. The
|
|
export has no column that separates them, so the longest entry wins.
|
|
|
|
Only the 10th-edition and 11th-edition cards show lore text. The 9th-edition
|
|
renderer lays out its header differently.
|
|
|
|
## Run it on your machine
|
|
|
|
```sh
|
|
npm install
|
|
npm run dev # http://localhost:5173
|
|
npm test
|
|
npm run build # static files in dist/
|
|
```
|
|
|
|
## Deploy to scribe.luxick.de
|
|
|
|
The build output is **static files**. There is no application server and no
|
|
socket, so nginx serves the files directly. The app does all of its work in the
|
|
browser. For the same reason, upstream FancyScribe can live on GitHub Pages.
|
|
|
|
The server needs no Node. Do the setup one time, in two stages. The two stages
|
|
are necessary because the real configuration names a certificate, and nginx
|
|
refuses to load a configuration whose certificate does not exist. Therefore
|
|
nginx first comes up on port 80 only. That is far enough for certbot to answer
|
|
the challenge.
|
|
|
|
```sh
|
|
sudo mkdir -p /var/www/brevyscribe /var/www/certbot
|
|
sudo chown "$USER" /var/www/brevyscribe
|
|
|
|
# Stage 1: HTTP only, so that nginx starts without a certificate.
|
|
sudo tee /etc/nginx/sites-available/scribe.luxick.de >/dev/null <<'EOF'
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name scribe.luxick.de;
|
|
location /.well-known/acme-challenge/ { root /var/www/certbot; }
|
|
}
|
|
EOF
|
|
sudo ln -s /etc/nginx/sites-available/scribe.luxick.de /etc/nginx/sites-enabled/
|
|
sudo nginx -t && sudo systemctl reload nginx
|
|
|
|
sudo certbot certonly --webroot -w /var/www/certbot -d scribe.luxick.de
|
|
|
|
# Stage 2: the real configuration, now that the certificate is on disk.
|
|
sudo cp deploy/nginx-scribe.luxick.de.conf /etc/nginx/sites-available/scribe.luxick.de
|
|
sudo nginx -t && sudo systemctl reload nginx
|
|
```
|
|
|
|
Use `certonly --webroot`, not `--nginx`. The configuration in the repository
|
|
carries its own redirect and TLS block. The nginx plugin rewrites the installed
|
|
file, and the installed file then drifts away from the one in the repository.
|
|
The port 80 block keeps its `acme-challenge` location for this reason, so
|
|
renewals continue to work without your attention.
|
|
|
|
CAUTION: The timer of certbot does not reload nginx. Put a one-line hook that
|
|
runs `systemctl reload nginx` in `/etc/letsencrypt/renewal-hooks/deploy/`.
|
|
Without this hook, the server serves a renewed certificate only after the next
|
|
restart.
|
|
|
|
Each deploy is then one command from a checkout on your own machine. The
|
|
command runs the tests, builds the app and copies `dist/` to the server with
|
|
rsync.
|
|
|
|
```sh
|
|
./deploy/deploy.sh
|
|
```
|
|
|
|
The script uses `--delete` on purpose. The asset filenames contain a hash of
|
|
the content, so old bundles collect on the server without this flag. There is
|
|
no state on the server and nothing to back up. Every roster stays in the
|
|
`localStorage` of the browser.
|
|
|
|
`index.html` loads Noto Sans from Google Fonts, so a page load contacts
|
|
`fonts.googleapis.com`. If you do not want this request, delete the `<link>`
|
|
tags. Then host the font next to the fonts in `public/fonts/`.
|
|
|
|
## Credit
|
|
|
|
The difficult parts are the work of
|
|
[Nils Ueter](https://github.com/NilsUeter/fancyscribe): the parser, the card
|
|
layout and the print CSS. The parsing logic comes in turn from
|
|
[PrettyScribe](https://github.com/rweyrauch/PrettyScribe). Upstream ships no
|
|
license file. Treat this fork as a private, personal deployment, not as
|
|
something that you redistribute.
|