refactor: migrate COA (#1309)
Some checks are pending
Deploy static content to Pages / deploy (push) Waiting to run
Code quality / quality (push) Waiting to run

* refactor: migrate COA

* fix: PR feedback
This commit is contained in:
Marc Emmanuel 2026-02-15 16:11:59 +01:00 committed by GitHub
parent 1100c7c53b
commit 4936a887ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 4691 additions and 4266 deletions

View file

@ -289,7 +289,7 @@ class BurgModule {
? "City"
: burg.type;
burg.coa = COA.generate(stateCOA, kinship, null, type);
burg.coa.shield = COA.getShield(burg.culture, burg.state);
burg.coa.shield = COA.getShield(burg.culture!, burg.state!);
}
private defineFeatures(burg: Burg) {

53
src/modules/emblem/box.ts Normal file
View file

@ -0,0 +1,53 @@
// shield-specific size multiplier
export const shieldBox = {
heater: "0 10 200 200",
spanish: "0 10 200 200",
french: "0 10 200 200",
horsehead: "0 10 200 200",
horsehead2: "0 10 200 200",
polish: "0 0 200 200",
hessen: "0 5 200 200",
swiss: "0 10 200 200",
boeotian: "0 0 200 200",
roman: "0 0 200 200",
kite: "0 0 200 200",
oldFrench: "0 10 200 200",
renaissance: "0 5 200 200",
baroque: "0 10 200 200",
targe: "0 0 200 200",
targe2: "0 0 200 200",
pavise: "0 0 200 200",
wedged: "0 10 200 200",
flag: "0 0 200 200",
pennon: "2.5 0 200 200",
guidon: "2.5 0 200 200",
banner: "0 10 200 200",
dovetail: "0 10 200 200",
gonfalon: "0 10 200 200",
pennant: "0 0 200 200",
round: "0 0 200 200",
oval: "0 0 200 200",
vesicaPiscis: "0 0 200 200",
square: "0 0 200 200",
diamond: "0 0 200 200",
no: "0 0 200 200",
fantasy1: "0 0 200 200",
fantasy2: "0 5 200 200",
fantasy3: "0 5 200 200",
fantasy4: "0 5 200 200",
fantasy5: "0 0 200 200",
noldor: "0 0 200 200",
gondor: "0 5 200 200",
easterling: "0 0 200 200",
erebor: "0 0 200 200",
ironHills: "0 5 200 200",
urukHai: "0 0 200 200",
moriaOrc: "0 0 200 200",
};

View file

@ -0,0 +1,883 @@
export interface ChargeDataEntry {
colors?: number;
sinister?: boolean;
reversed?: boolean;
positions?: Record<string, number>;
natural?: string;
}
export const chargeData: Record<string, ChargeDataEntry> = {
agnusDei: {
colors: 2,
sinister: true,
},
angel: {
colors: 2,
positions: { e: 1 },
},
anvil: {
sinister: true,
},
apple: {
colors: 2,
},
arbalest: {
colors: 3,
reversed: true,
},
archer: {
colors: 3,
sinister: true,
},
armEmbowedHoldingSabre: {
colors: 3,
sinister: true,
},
armEmbowedVambraced: {
sinister: true,
},
armEmbowedVambracedHoldingSword: {
colors: 3,
sinister: true,
},
armillarySphere: {
positions: { e: 1 },
},
arrow: {
colors: 3,
reversed: true,
},
arrowsSheaf: {
colors: 3,
reversed: true,
},
axe: {
colors: 2,
sinister: true,
},
badgerStatant: {
colors: 2,
sinister: true,
},
banner: {
colors: 2,
},
basilisk: {
colors: 3,
sinister: true,
},
bearPassant: {
colors: 3,
sinister: true,
},
bearRampant: {
colors: 3,
sinister: true,
},
bee: {
colors: 3,
reversed: true,
},
bell: {
colors: 2,
},
boarHeadErased: {
colors: 3,
sinister: true,
},
boarRampant: {
colors: 3,
sinister: true,
positions: { e: 12, beh: 1, kn: 1, jln: 2 },
},
boat: {
colors: 2,
},
bookClosed: {
colors: 3,
sinister: true,
},
bookClosed2: {
sinister: true,
},
bookOpen: {
colors: 3,
},
bow: {
sinister: true,
},
bowWithArrow: {
colors: 3,
reversed: true,
},
bowWithThreeArrows: {
colors: 3,
},
bucket: {
colors: 2,
},
bugleHorn: {
colors: 2,
},
bugleHorn2: {
colors: 2,
},
bullHeadCaboshed: {
colors: 2,
},
bullPassant: {
colors: 3,
sinister: true,
},
butterfly: {
colors: 3,
reversed: true,
},
camel: {
colors: 2,
sinister: true,
},
cancer: {
reversed: true,
},
cannon: {
colors: 2,
sinister: true,
},
caravel: {
colors: 3,
sinister: true,
},
castle: {
colors: 2,
},
castle2: {
colors: 3,
},
catPassantGuardant: {
colors: 2,
sinister: true,
},
cavalier: {
colors: 3,
sinister: true,
positions: { e: 1 },
},
centaur: {
colors: 3,
sinister: true,
},
chalice: {
colors: 2,
},
cinquefoil: {
reversed: true,
},
cock: {
colors: 3,
sinister: true,
},
comet: {
reversed: true,
},
cowStatant: {
colors: 3,
sinister: true,
},
cossack: {
colors: 3,
sinister: true,
},
crescent: {
reversed: true,
},
crocodile: {
colors: 2,
sinister: true,
},
crosier: {
sinister: true,
},
crossbow: {
colors: 3,
sinister: true,
},
crossGamma: {
sinister: true,
},
crossLatin: {
reversed: true,
},
crossTau: {
reversed: true,
},
crossTriquetra: {
reversed: true,
},
crown: {
colors: 2,
positions: {
e: 10,
abcdefgzi: 1,
beh: 3,
behdf: 2,
acegi: 1,
kn: 1,
pq: 2,
abc: 1,
jln: 4,
jleh: 1,
def: 2,
abcpqh: 3,
},
},
crown2: {
colors: 3,
positions: {
e: 10,
abcdefgzi: 1,
beh: 3,
behdf: 2,
acegi: 1,
kn: 1,
pq: 2,
abc: 1,
jln: 4,
jleh: 1,
def: 2,
abcpqh: 3,
},
},
deerHeadCaboshed: {
colors: 2,
},
dolphin: {
colors: 2,
sinister: true,
},
donkeyHeadCaboshed: {
colors: 2,
},
dove: {
colors: 2,
natural: "argent",
sinister: true,
},
doveDisplayed: {
colors: 2,
natural: "argent",
sinister: true,
},
dragonfly: {
colors: 2,
reversed: true,
},
dragonPassant: {
colors: 3,
sinister: true,
},
dragonRampant: {
colors: 3,
sinister: true,
},
drakkar: {
colors: 3,
sinister: true,
},
drawingCompass: {
sinister: true,
},
drum: {
colors: 3,
},
duck: {
colors: 3,
sinister: true,
},
eagle: {
colors: 3,
sinister: true,
positions: { e: 15, beh: 1, kn: 1, abc: 1, jlh: 2, def: 2, pq: 1 },
},
eagleTwoHeads: {
colors: 3,
},
elephant: {
colors: 2,
sinister: true,
},
elephantHeadErased: {
colors: 2,
sinister: true,
},
falchion: {
colors: 2,
reversed: true,
},
falcon: {
colors: 3,
sinister: true,
},
fan: {
colors: 2,
reversed: true,
},
fasces: {
colors: 3,
sinister: true,
},
feather: {
sinister: true,
},
flamberge: {
colors: 2,
reversed: true,
},
flangedMace: {
reversed: true,
},
fly: {
colors: 3,
reversed: true,
},
foot: {
sinister: true,
},
fountain: {
natural: "azure",
},
frog: {
reversed: true,
},
garb: {
colors: 2,
natural: "or",
positions: {
e: 1,
def: 3,
abc: 2,
beh: 1,
kn: 1,
jln: 3,
jleh: 1,
abcpqh: 1,
joe: 1,
lme: 1,
},
},
gauntlet: {
sinister: true,
reversed: true,
},
goat: {
colors: 3,
sinister: true,
},
goutte: {
reversed: true,
},
grapeBunch: {
colors: 3,
sinister: true,
},
grapeBunch2: {
colors: 3,
sinister: true,
},
grenade: {
colors: 2,
},
greyhoundCourant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1 },
},
greyhoundRampant: {
colors: 2,
sinister: true,
positions: { e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1 },
},
greyhoundSejant: {
colors: 3,
sinister: true,
},
griffinPassant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 2, abc: 2, bdefh: 1, kn: 1, jlh: 2, abcpqh: 1 },
},
griffinRampant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1 },
},
hand: {
sinister: true,
reversed: true,
positions: { e: 10, jln: 2, kn: 1, jeo: 1, abc: 2, pqe: 1 },
},
harp: {
colors: 2,
sinister: true,
},
hatchet: {
colors: 2,
sinister: true,
},
head: {
colors: 2,
sinister: true,
positions: { e: 1 },
},
headWreathed: {
colors: 3,
sinister: true,
positions: { e: 1 },
},
hedgehog: {
colors: 3,
sinister: true,
},
helmet: {
sinister: true,
},
helmetCorinthian: {
colors: 3,
sinister: true,
},
helmetGreat: {
sinister: true,
},
helmetZischagge: {
sinister: true,
},
heron: {
colors: 2,
sinister: true,
},
hindStatant: {
colors: 2,
sinister: true,
},
hook: {
sinister: true,
},
horseHeadCouped: {
sinister: true,
},
horsePassant: {
colors: 2,
sinister: true,
},
horseRampant: {
colors: 3,
sinister: true,
},
horseSalient: {
colors: 2,
sinister: true,
},
horseshoe: {
reversed: true,
},
hourglass: {
colors: 3,
},
ladybird: {
colors: 3,
reversed: true,
},
lamb: {
colors: 2,
sinister: true,
},
lambPassantReguardant: {
colors: 2,
sinister: true,
},
lanceWithBanner: {
colors: 3,
sinister: true,
},
laurelWreath: {
colors: 2,
},
lighthouse: {
colors: 3,
},
lionHeadCaboshed: {
colors: 2,
},
lionHeadErased: {
colors: 2,
sinister: true,
},
lionPassant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1 },
},
lionPassantGuardant: {
colors: 3,
sinister: true,
},
lionRampant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 2, abc: 2, bdefh: 1, kn: 1, jlh: 2, abcpqh: 1 },
},
lionSejant: {
colors: 3,
sinister: true,
},
lizard: {
reversed: true,
},
lochaberAxe: {
colors: 2,
sinister: true,
},
log: {
sinister: true,
},
lute: {
colors: 2,
sinister: true,
},
lymphad: {
colors: 3,
sinister: true,
positions: { e: 1 },
},
mace: {
colors: 2,
},
maces: {
colors: 2,
},
mallet: {
colors: 2,
},
mantle: {
colors: 3,
},
martenCourant: {
colors: 3,
sinister: true,
},
mascle: {
positions: {
e: 15,
abcdefgzi: 3,
beh: 3,
bdefh: 4,
acegi: 1,
kn: 3,
joe: 2,
abc: 3,
jlh: 8,
jleh: 1,
df: 3,
abcpqh: 4,
pqe: 3,
eknpq: 3,
},
},
mastiffStatant: {
colors: 3,
sinister: true,
},
mitre: {
colors: 3,
},
monk: {
sinister: true,
},
moonInCrescent: {
sinister: true,
},
mullet: {
reversed: true,
},
mullet7: {
reversed: true,
},
oak: {
colors: 3,
},
orb: {
colors: 3,
},
ouroboros: {
sinister: true,
},
owl: {
colors: 2,
sinister: true,
},
owlDisplayed: {
colors: 2,
},
palmTree: {
colors: 3,
},
parrot: {
colors: 2,
sinister: true,
},
peacock: {
colors: 3,
sinister: true,
},
peacockInPride: {
colors: 3,
sinister: true,
},
pear: {
colors: 2,
},
pegasus: {
colors: 3,
sinister: true,
},
pike: {
colors: 2,
sinister: true,
},
pineTree: {
colors: 2,
},
plaice: {
colors: 2,
sinister: true,
},
plough: {
colors: 2,
sinister: true,
},
ploughshare: {
sinister: true,
},
porcupine: {
colors: 2,
sinister: true,
},
portcullis: {
colors: 2,
},
rabbitSejant: {
colors: 2,
sinister: true,
},
rake: {
reversed: true,
},
rapier: {
colors: 2,
sinister: true,
reversed: true,
},
ramHeadErased: {
colors: 3,
sinister: true,
},
ramPassant: {
colors: 3,
sinister: true,
},
ratRampant: {
colors: 2,
sinister: true,
},
raven: {
colors: 2,
natural: "sable",
sinister: true,
positions: { e: 15, beh: 1, kn: 1, jeo: 1, abc: 3, jln: 3, def: 1 },
},
rhinoceros: {
colors: 2,
sinister: true,
},
rose: {
colors: 3,
},
sabre: {
colors: 2,
sinister: true,
},
sabre2: {
colors: 2,
sinister: true,
reversed: true,
},
sabresCrossed: {
colors: 2,
reversed: true,
},
sagittarius: {
colors: 3,
sinister: true,
},
salmon: {
colors: 2,
sinister: true,
},
saw: {
colors: 2,
},
scale: {
colors: 2,
},
scaleImbalanced: {
colors: 2,
sinister: true,
},
scissors: {
reversed: true,
},
scorpion: {
reversed: true,
},
scrollClosed: {
colors: 2,
sinister: true,
},
scythe: {
colors: 2,
sinister: true,
reversed: true,
},
scythe2: {
sinister: true,
},
serpent: {
colors: 2,
sinister: true,
},
shield: {
colors: 2,
sinister: true,
},
sickle: {
colors: 2,
sinister: true,
reversed: true,
},
snail: {
colors: 2,
sinister: true,
},
snake: {
colors: 2,
sinister: true,
},
spear: {
colors: 2,
reversed: true,
},
spiral: {
sinister: true,
reversed: true,
},
squirrel: {
sinister: true,
},
stagLodgedRegardant: {
colors: 3,
sinister: true,
},
stagPassant: {
colors: 2,
sinister: true,
},
stirrup: {
colors: 2,
},
swallow: {
colors: 2,
sinister: true,
},
swan: {
colors: 3,
sinister: true,
},
swanErased: {
colors: 3,
sinister: true,
},
sword: {
colors: 2,
reversed: true,
},
talbotPassant: {
colors: 3,
sinister: true,
},
talbotSejant: {
colors: 3,
sinister: true,
},
tower: {
colors: 2,
},
tree: {
positions: { e: 1 },
},
trefoil: {
reversed: true,
},
trowel: {
colors: 2,
sinister: true,
reversed: true,
},
unicornRampant: {
colors: 3,
sinister: true,
},
wasp: {
colors: 3,
reversed: true,
},
wheatStalk: {
colors: 2,
},
windmill: {
colors: 3,
sinister: true,
},
wing: {
sinister: true,
},
wingSword: {
colors: 3,
sinister: true,
},
wolfHeadErased: {
colors: 2,
sinister: true,
},
wolfPassant: {
colors: 3,
sinister: true,
positions: { e: 10, def: 1, abc: 1, bdefh: 1, jlh: 1, abcpqh: 1 },
},
wolfRampant: {
colors: 3,
sinister: true,
},
wolfStatant: {
colors: 3,
sinister: true,
},
wyvern: {
colors: 3,
sinister: true,
positions: { e: 10, jln: 1 },
},
wyvernWithWingsDisplayed: {
colors: 3,
sinister: true,
},
};

View file

@ -0,0 +1,477 @@
import { chargeData } from "./chargeData";
export const charges = {
types: {
conventional: 33, // 40 charges
crosses: 13, // 30 charges
beasts: 7, // 41 charges
beastHeads: 3, // 10 charges
birds: 3, // 16 charges
reptiles: 2, // 5 charges
bugs: 2, // 8 charges
fishes: 1, // 3 charges
molluscs: 1, // 2 charges
plants: 3, // 18 charges
fantastic: 5, // 14 charges
agriculture: 2, // 8 charges
arms: 5, // 32 charges
bodyparts: 2, // 12 charges
people: 2, // 4 charges
architecture: 3, // 11 charges
seafaring: 3, // 9 charges
tools: 3, // 15 charges
miscellaneous: 5, // 30 charges
inescutcheon: 3, // 43 charges
ornaments: 0, // 9 charges
uploaded: 0,
},
single: {
conventional: 10,
crosses: 8,
beasts: 7,
beastHeads: 3,
birds: 3,
reptiles: 2,
bugs: 2,
fishes: 1,
molluscs: 1,
plants: 3,
fantastic: 5,
agriculture: 2,
arms: 5,
bodyparts: 2,
people: 2,
architecture: 3,
seafaring: 3,
tools: 3,
miscellaneous: 5,
inescutcheon: 1,
},
semy: {
conventional: 4,
crosses: 1,
},
conventional: {
annulet: 4,
billet: 5,
carreau: 1,
comet: 1,
compassRose: 1,
crescent: 5,
delf: 0,
estoile: 1,
fleurDeLis: 6,
fountain: 1,
fusil: 4,
gear: 1,
goutte: 4,
heart: 4,
lozenge: 2,
lozengeFaceted: 3,
lozengePloye: 1,
mascle: 4,
moonInCrescent: 1,
mullet: 5,
mullet10: 1,
mullet4: 3,
mullet6: 4,
mullet6Faceted: 1,
mullet6Pierced: 1,
mullet7: 1,
mullet8: 1,
mulletFaceted: 1,
mulletPierced: 1,
pique: 2,
roundel: 4,
roundel2: 3,
rustre: 2,
spiral: 1,
sun: 3,
sunInSplendour: 1,
sunInSplendour2: 1,
trefle: 2,
triangle: 3,
trianglePierced: 1,
},
crosses: {
crossHummetty: 15,
crossVoided: 1,
crossPattee: 2,
crossPatteeAlisee: 1,
crossFormee: 1,
crossFormee2: 2,
crossPotent: 2,
crossJerusalem: 1,
crosslet: 1,
crossClechy: 3,
crossBottony: 1,
crossFleury: 3,
crossPatonce: 1,
crossPommy: 1,
crossGamma: 1,
crossArrowed: 1,
crossFitchy: 1,
crossCercelee: 1,
crossMoline: 2,
crossFourchy: 1,
crossAvellane: 1,
crossErminee: 1,
crossBiparted: 1,
crossMaltese: 3,
crossTemplar: 2,
crossCeltic: 1,
crossCeltic2: 1,
crossTriquetra: 1,
crossCarolingian: 1,
crossOccitan: 1,
crossSaltire: 3,
crossBurgundy: 1,
crossLatin: 3,
crossPatriarchal: 1,
crossOrthodox: 1,
crossCalvary: 1,
crossDouble: 1,
crossTau: 1,
crossSantiago: 1,
crossAnkh: 1,
},
beasts: {
agnusDei: 1,
badgerStatant: 1,
bearPassant: 1,
bearRampant: 3,
boarRampant: 1,
bullPassant: 1,
camel: 1,
catPassantGuardant: 1,
cowStatant: 1,
dolphin: 1,
elephant: 1,
goat: 1,
greyhoundCourant: 1,
greyhoundRampant: 1,
greyhoundSejant: 1,
hedgehog: 1,
hindStatant: 1,
horsePassant: 1,
horseRampant: 2,
horseSalient: 1,
lamb: 1,
lambPassantReguardant: 1,
lionPassant: 3,
lionPassantGuardant: 2,
lionRampant: 7,
lionSejant: 2,
martenCourant: 1,
mastiffStatant: 1,
porcupine: 1,
rabbitSejant: 1,
ramPassant: 1,
ratRampant: 1,
rhinoceros: 1,
squirrel: 1,
stagLodgedRegardant: 1,
stagPassant: 1,
talbotPassant: 1,
talbotSejant: 1,
wolfPassant: 1,
wolfRampant: 1,
wolfStatant: 1,
},
beastHeads: {
boarHeadErased: 1,
bullHeadCaboshed: 1,
deerHeadCaboshed: 1,
donkeyHeadCaboshed: 1,
elephantHeadErased: 1,
horseHeadCouped: 1,
lionHeadCaboshed: 2,
lionHeadErased: 2,
ramHeadErased: 1,
wolfHeadErased: 2,
},
birds: {
cock: 3,
dove: 2,
doveDisplayed: 1,
duck: 1,
eagle: 9,
falcon: 2,
heron: 1,
owl: 1,
owlDisplayed: 1,
parrot: 1,
peacock: 1,
peacockInPride: 1,
raven: 2,
swallow: 1,
swan: 2,
swanErased: 1,
},
reptiles: {
crocodile: 1,
frog: 1,
lizard: 1,
ouroboros: 1,
snake: 1,
},
bugs: {
bee: 1,
butterfly: 1,
cancer: 1,
dragonfly: 1,
fly: 1,
ladybird: 1,
scorpion: 1,
wasp: 1,
},
fishes: {
pike: 1,
plaice: 1,
salmon: 1,
},
molluscs: {
escallop: 4,
snail: 1,
},
plants: {
apple: 1,
cinquefoil: 1,
earOfWheat: 1,
grapeBunch: 1,
grapeBunch2: 1,
mapleLeaf: 1,
oak: 1,
palmTree: 1,
pear: 1,
pineCone: 1,
pineTree: 1,
quatrefoil: 1,
rose: 1,
sextifoil: 1,
thistle: 1,
tree: 1,
trefoil: 1,
wheatStalk: 1,
},
fantastic: {
angel: 3,
basilisk: 1,
centaur: 1,
dragonPassant: 3,
dragonRampant: 2,
eagleTwoHeads: 2,
griffinPassant: 1,
griffinRampant: 2,
pegasus: 1,
sagittarius: 1,
serpent: 1,
unicornRampant: 1,
wyvern: 1,
wyvernWithWingsDisplayed: 1,
},
agriculture: {
garb: 2,
millstone: 1,
plough: 1,
ploughshare: 1,
rake: 1,
scythe: 1,
scythe2: 1,
sickle: 1,
},
arms: {
arbalest: 1,
arbalest2: 1,
arrow: 1,
arrowsSheaf: 1,
axe: 3,
bow: 1,
bowWithArrow: 2,
bowWithThreeArrows: 1,
cannon: 1,
falchion: 1,
flamberge: 1,
flangedMace: 1,
gauntlet: 1,
grenade: 1,
hatchet: 3,
helmet: 2,
helmetCorinthian: 1,
helmetGreat: 2,
helmetZischagge: 1,
lanceHead: 1,
lanceWithBanner: 1,
lochaberAxe: 1,
mace: 1,
maces: 1,
mallet: 1,
rapier: 1,
sabre: 1,
sabre2: 1,
sabresCrossed: 1,
shield: 1,
spear: 1,
sword: 4,
},
bodyparts: {
armEmbowedHoldingSabre: 1,
armEmbowedVambraced: 1,
armEmbowedVambracedHoldingSword: 1,
bone: 1,
crossedBones: 2,
foot: 1,
hand: 4,
head: 1,
headWreathed: 1,
skeleton: 2,
skull: 2,
skull2: 1,
},
people: {
archer: 1,
cavalier: 3,
cossack: 1,
monk: 1,
},
architecture: {
bridge: 1,
bridge2: 1,
castle: 2,
castle2: 1,
column: 1,
lighthouse: 1,
palace: 1,
pillar: 1,
portcullis: 1,
tower: 2,
windmill: 1,
},
seafaring: {
anchor: 6,
armillarySphere: 1,
boat: 2,
boat2: 1,
caravel: 1,
drakkar: 1,
lymphad: 2,
raft: 1,
shipWheel: 1,
},
tools: {
anvil: 2,
drawingCompass: 2,
fan: 1,
hook: 1,
ladder: 1,
ladder2: 1,
pincers: 1,
saw: 1,
scale: 1,
scaleImbalanced: 1,
scalesHanging: 1,
scissors: 1,
scissors2: 1,
shears: 1,
trowel: 1,
},
miscellaneous: {
attire: 2,
banner: 2,
bell: 3,
bookClosed: 1,
bookClosed2: 1,
bookOpen: 1,
bucket: 1,
buckle: 1,
bugleHorn: 2,
bugleHorn2: 1,
chain: 2,
chalice: 2,
cowHorns: 3,
crosier: 1,
crown: 3,
crown2: 2,
drum: 1,
fasces: 1,
feather: 3,
harp: 2,
horseshoe: 3,
hourglass: 2,
key: 3,
laurelWreath: 2,
laurelWreath2: 1,
log: 1,
lute: 2,
lyre: 1,
mitre: 1,
orb: 1,
pot: 2,
ramsHorn: 1,
sceptre: 1,
scrollClosed: 1,
snowflake: 1,
stagsAttires: 1,
stirrup: 2,
wheel: 3,
wing: 2,
wingSword: 1,
},
inescutcheon: {
inescutcheonHeater: 1,
inescutcheonSpanish: 1,
inescutcheonFrench: 1,
inescutcheonHorsehead: 1,
inescutcheonHorsehead2: 1,
inescutcheonPolish: 1,
inescutcheonHessen: 1,
inescutcheonSwiss: 1,
inescutcheonBoeotian: 1,
inescutcheonRoman: 1,
inescutcheonKite: 1,
inescutcheonOldFrench: 1,
inescutcheonRenaissance: 1,
inescutcheonBaroque: 1,
inescutcheonTarge: 1,
inescutcheonTarge2: 1,
inescutcheonPavise: 1,
inescutcheonWedged: 1,
inescutcheonFlag: 1,
inescutcheonPennon: 1,
inescutcheonGuidon: 1,
inescutcheonBanner: 1,
inescutcheonDovetail: 1,
inescutcheonGonfalon: 1,
inescutcheonPennant: 1,
inescutcheonRound: 1,
inescutcheonOval: 1,
inescutcheonVesicaPiscis: 1,
inescutcheonSquare: 1,
inescutcheonDiamond: 1,
inescutcheonNo: 1,
inescutcheonFantasy1: 1,
inescutcheonFantasy2: 1,
inescutcheonFantasy3: 1,
inescutcheonFantasy4: 1,
inescutcheonFantasy5: 1,
inescutcheonNoldor: 1,
inescutcheonGondor: 1,
inescutcheonEasterling: 1,
inescutcheonErebor: 1,
inescutcheonIronHills: 1,
inescutcheonUrukHai: 1,
inescutcheonMoriaOrc: 1,
},
ornaments: {
mantle: 0,
ribbon1: 3,
ribbon2: 2,
ribbon3: 1,
ribbon4: 1,
ribbon5: 1,
ribbon6: 1,
ribbon7: 1,
ribbon8: 1,
},
data: chargeData,
};

View file

@ -0,0 +1,12 @@
export const colors = {
argent: "#fafafa",
or: "#ffe066",
gules: "#d7374a",
sable: "#333333",
azure: "#377cd7",
vert: "#26c061",
purpure: "#522d5b",
murrey: "#85185b",
sanguine: "#b63a3a",
tenné: "#cc7f19",
};

View file

@ -0,0 +1,46 @@
import { lineWeights } from "./lineWeights";
export const divisions = {
variants: {
perPale: 5,
perFess: 5,
perBend: 2,
perBendSinister: 1,
perChevron: 1,
perChevronReversed: 1,
perCross: 5,
perPile: 1,
perSaltire: 1,
gyronny: 1,
chevronny: 1,
},
perPale: lineWeights,
perFess: lineWeights,
perBend: lineWeights,
perBendSinister: lineWeights,
perChevron: lineWeights,
perChevronReversed: lineWeights,
perCross: {
straight: 20,
wavy: 5,
engrailed: 4,
invecked: 3,
rayonne: 1,
embattled: 1,
raguly: 1,
urdy: 1,
indented: 2,
dentilly: 1,
bevilled: 1,
angled: 1,
embattledGhibellin: 1,
embattledGrady: 1,
dovetailedIndented: 1,
dovetailed: 1,
potenty: 1,
potentyDexter: 1,
potentySinister: 1,
nebuly: 1,
},
perPile: lineWeights,
};

View file

@ -0,0 +1,591 @@
import { P, rw } from "../../utils";
import { charges } from "./charges";
import { divisions } from "./divisions";
import { lineWeights } from "./lineWeights";
import { ordinaries } from "./ordinaries";
import { positions } from "./positions";
import { shields } from "./shields";
import { createTinctures } from "./tinctures";
import { typeMapping } from "./typeMapping";
declare global {
var COA: EmblemGeneratorModule;
}
export interface EmblemCharge {
charge: string;
t: string;
p: string;
t2?: string;
t3?: string;
size?: number;
sinister?: number;
reversed?: number;
divided?: string;
}
export interface EmblemOrdinary {
ordinary: string;
t: string;
line?: string;
divided?: string;
above?: boolean;
}
export interface EmblemDivision {
division: string;
t: string;
line?: string;
}
export interface Emblem {
t1: string;
shield?: string;
division?: EmblemDivision;
ordinaries?: EmblemOrdinary[];
charges?: EmblemCharge[];
custom?: boolean;
}
class EmblemGeneratorModule {
generate(
parent: Emblem | null,
kinship: number | null,
dominion: number | null,
type?: string,
): Emblem {
if (!parent || parent.custom) {
parent = null;
kinship = 0;
dominion = 0;
}
let usedPattern: string | null = null;
const usedTinctures: string[] = [];
const t1 = P(kinship as number)
? parent!.t1
: this.getTincture("field", usedTinctures, null);
if (t1.includes("-")) usedPattern = t1;
const coa: Emblem = { t1 };
const addCharge = P(usedPattern ? 0.5 : 0.93); // 80% for charge
const linedOrdinary =
(addCharge && P(0.3)) || P(0.5)
? parent?.ordinaries && P(kinship as number)
? parent.ordinaries[0].ordinary
: rw(ordinaries.lined)
: null;
const ordinary =
(!addCharge && P(0.65)) || P(0.3)
? linedOrdinary
? linedOrdinary
: rw(ordinaries.straight)
: null; // 36% for ordinary
const rareDivided = [
"chief",
"terrace",
"chevron",
"quarter",
"flaunches",
].includes(ordinary!);
const divisioned = (() => {
if (rareDivided) return P(0.03);
if (addCharge && ordinary) return P(0.03);
if (addCharge) return P(0.3);
if (ordinary) return P(0.7);
return P(0.995);
})();
const division = (() => {
if (divisioned) {
if (parent?.division && P((kinship as number) - 0.1))
return parent.division.division;
return rw(divisions.variants);
}
return null;
})();
if (division) {
const t = this.getTincture(
"division",
usedTinctures,
P(0.98) ? coa.t1 : null,
);
coa.division = { division, t };
if (divisions[division as keyof typeof divisions])
coa.division.line =
usedPattern || (ordinary && P(0.7))
? "straight"
: rw(divisions[division as keyof typeof divisions]);
}
if (ordinary) {
coa.ordinaries = [
{ ordinary, t: this.getTincture("charge", usedTinctures, coa.t1) },
];
if (linedOrdinary)
coa.ordinaries[0].line =
usedPattern || (division && P(0.7)) ? "straight" : rw(lineWeights);
if (
division &&
!addCharge &&
!usedPattern &&
P(0.5) &&
ordinary !== "bordure" &&
ordinary !== "orle"
) {
if (P(0.8)) coa.ordinaries[0].divided = "counter";
// 40%
else if (P(0.6)) coa.ordinaries[0].divided = "field";
// 6%
else coa.ordinaries[0].divided = "division"; // 4%
}
}
if (addCharge) {
const charge = (() => {
if (parent?.charges && P((kinship as number) - 0.1))
return parent.charges[0].charge;
if (type && type !== "Generic" && P(0.3)) return rw(typeMapping[type]);
return this.selectCharge(
ordinary || divisioned ? charges.types : charges.single,
);
})();
const chargeDataEntry = charges.data[charge] || {};
let p: string;
let t: string;
const ordinaryData = ordinaries.data[ordinary!];
const tOrdinary = coa.ordinaries ? coa.ordinaries[0].t : null;
if (ordinaryData?.positionsOn && P(0.8)) {
// place charge over ordinary (use tincture of field type)
p = rw(ordinaryData.positionsOn);
t =
!usedPattern && P(0.3)
? coa.t1
: this.getTincture("charge", [], tOrdinary);
} else if (ordinaryData?.positionsOff && P(0.95)) {
// place charge out of ordinary (use tincture of ordinary type)
p = rw(ordinaryData.positionsOff);
t =
!usedPattern && P(0.3)
? tOrdinary!
: this.getTincture("charge", usedTinctures, coa.t1);
} else if (
positions.divisions[division as keyof typeof positions.divisions]
) {
// place charge in fields made by division
p = rw(
positions.divisions[division as keyof typeof positions.divisions],
);
t = this.getTincture(
"charge",
tOrdinary ? usedTinctures.concat(tOrdinary) : usedTinctures,
coa.t1,
);
} else if (chargeDataEntry.positions) {
// place charge-suitable position
p = rw(chargeDataEntry.positions);
t = this.getTincture("charge", usedTinctures, coa.t1);
} else {
// place in standard position (use new tincture)
p = usedPattern
? "e"
: charges.conventional[charge as keyof typeof charges.conventional]
? rw(positions.conventional)
: rw(positions.complex);
t = this.getTincture(
"charge",
usedTinctures.concat(tOrdinary!),
coa.t1,
);
}
if (
chargeDataEntry.natural &&
chargeDataEntry.natural !== t &&
chargeDataEntry.natural !== tOrdinary
)
t = chargeDataEntry.natural;
const item: EmblemCharge = { charge: charge, t, p };
const colors = chargeDataEntry.colors || 1;
if (colors > 1)
item.t2 = P(0.25)
? this.getTincture("charge", usedTinctures, coa.t1)
: t;
if (colors > 2 && item.t2)
item.t3 = P(0.5)
? this.getTincture("charge", usedTinctures, coa.t1)
: t;
coa.charges = [item];
if (p === "ABCDEFGHIJKL" && P(0.95)) {
// add central charge if charge is in bordure
coa.charges[0].charge = rw(charges.conventional);
const chargeNew = this.selectCharge(charges.single);
const tNew = this.getTincture("charge", usedTinctures, coa.t1);
coa.charges.push({ charge: chargeNew, t: tNew, p: "e" });
} else if (P(0.8) && charge === "inescutcheon") {
// add charge to inescutcheon
const chargeNew = this.selectCharge(charges.types);
const t2 = this.getTincture("charge", [], t);
coa.charges.push({ charge: chargeNew, t: t2, p, size: 0.5 });
} else if (division && !ordinary) {
const allowCounter =
!usedPattern &&
(!coa.division?.line || coa.division.line === "straight");
// dimidiation: second charge at division basic positions
if (
P(0.3) &&
["perPale", "perFess"].includes(division) &&
coa.division?.line === "straight"
) {
coa.charges[0].divided = "field";
if (P(0.95)) {
const p2 =
p === "e" || P(0.5)
? "e"
: rw(
positions.divisions[
division as keyof typeof positions.divisions
],
);
const chargeNew = this.selectCharge(charges.single);
const tNew = this.getTincture(
"charge",
usedTinctures,
coa.division!.t,
);
coa.charges.push({
charge: chargeNew,
t: tNew,
p: p2,
divided: "division",
});
}
} else if (allowCounter && P(0.4)) coa.charges[0].divided = "counter";
// counterchanged, 40%
else if (
["perPale", "perFess", "perBend", "perBendSinister"].includes(
division,
) &&
P(0.8)
) {
// place 2 charges in division standard positions
const [p1, p2] =
division === "perPale"
? ["p", "q"]
: division === "perFess"
? ["k", "n"]
: division === "perBend"
? ["l", "m"]
: ["j", "o"]; // perBendSinister
coa.charges[0].p = p1;
const chargeNew = this.selectCharge(charges.single);
const tNew = this.getTincture(
"charge",
usedTinctures,
coa.division!.t,
);
coa.charges.push({ charge: chargeNew, t: tNew, p: p2 });
} else if (["perCross", "perSaltire"].includes(division) && P(0.5)) {
// place 4 charges in division standard positions
const [p1, p2, p3, p4] =
division === "perCross"
? ["j", "l", "m", "o"]
: ["b", "d", "f", "h"];
coa.charges[0].p = p1;
const c2 = this.selectCharge(charges.single);
const t2 = this.getTincture("charge", [], coa.division!.t);
const c3 = this.selectCharge(charges.single);
const t3 = this.getTincture("charge", [], coa.division!.t);
const c4 = this.selectCharge(charges.single);
const t4 = this.getTincture("charge", [], coa.t1);
coa.charges.push(
{ charge: c2, t: t2, p: p2 },
{ charge: c3, t: t3, p: p3 },
{ charge: c4, t: t4, p: p4 },
);
} else if (allowCounter && p.length > 1)
coa.charges[0].divided = "counter"; // counterchanged, 40%
}
for (const c of coa.charges) {
this.defineChargeAttributes(ordinary, division, c);
}
}
// dominions have canton with parent coa
if (P(dominion as number) && parent?.charges) {
const invert = this.isSameType(parent.t1, coa.t1);
const t = invert
? this.getTincture("division", usedTinctures, coa.t1)
: parent.t1;
const canton: EmblemOrdinary = { ordinary: "canton", t };
if (coa.charges) {
for (let i = coa.charges.length - 1; i >= 0; i--) {
const charge = coa.charges[i];
if (charge.size === 1.5) charge.size = 1.4;
charge.p = charge.p.replaceAll(/[ajy]/g, "");
if (!charge.p) coa.charges.splice(i, 1);
}
}
let charge = parent.charges[0].charge;
if (charge === "inescutcheon" && parent.charges[1])
charge = parent.charges[1].charge;
let t2 = invert ? parent.t1 : parent.charges[0].t;
if (this.isSameType(t, t2))
t2 = this.getTincture("charge", usedTinctures, t);
if (!coa.charges) coa.charges = [];
coa.charges.push({ charge, t: t2, p: "y", size: 0.5 });
if (coa.ordinaries) {
coa.ordinaries.push(canton);
} else {
coa.ordinaries = [canton];
}
}
return coa;
}
private selectCharge(set?: Record<string, number>): string {
const type = set ? rw(set) : rw(charges.types);
return type === "inescutcheon"
? "inescutcheon"
: rw(charges[type as keyof typeof charges] as Record<string, number>);
}
// Select tincture: element type (field, division, charge), used field tinctures, field type to follow RoT
private getTincture(
element: "field" | "division" | "charge",
fields: string[] = [],
RoT: string | null,
): string {
const base = RoT ? (RoT.includes("-") ? RoT.split("-")[1] : RoT) : null;
const tinctures = createTinctures();
let type = rw(tinctures[element]); // metals, colours, stains, patterns
if (RoT && type !== "patterns")
type = this.getType(base!) === "metals" ? "colours" : "metals"; // follow RoT
if (type === "metals" && fields.includes("or") && fields.includes("argent"))
type = "colours"; // exclude metals overuse
let tincture = rw(
tinctures[type as keyof typeof tinctures] as Record<string, number>,
);
while (tincture === base || fields.includes(tincture)) {
tincture = rw(
tinctures[type as keyof typeof tinctures] as Record<string, number>,
);
} // follow RoT
if (type !== "patterns" && element !== "charge") fields.push(tincture); // add field tincture
if (type === "patterns") {
tincture = this.definePattern(tincture, element, fields);
}
return tincture;
}
private defineChargeAttributes(
ordinary: string | null,
division: string | null,
c: EmblemCharge,
): void {
// define size
c.size = (c.size || 1) * this.getSize(c.p, ordinary, division);
// clean-up position
c.p = [...new Set(c.p)].join("");
// define orientation
if (P(0.02) && charges.data[c.charge]?.sinister) c.sinister = 1;
if (P(0.02) && charges.data[c.charge]?.reversed) c.reversed = 1;
}
private getType(t: string): string | undefined {
const tinc = t.includes("-") ? t.split("-")[1] : t;
const tinctures = createTinctures();
if (Object.keys(tinctures.metals).includes(tinc)) return "metals";
if (Object.keys(tinctures.colours).includes(tinc)) return "colours";
if (Object.keys(tinctures.stains).includes(tinc)) return "stains";
return undefined;
}
private isSameType(t1: string, t2: string): boolean {
return this.typeOf(t1) === this.typeOf(t2);
}
private typeOf(tinc: string): string {
const tinctures = createTinctures();
if (Object.keys(tinctures.metals).includes(tinc)) return "metals";
if (Object.keys(tinctures.colours).includes(tinc)) return "colours";
if (Object.keys(tinctures.stains).includes(tinc)) return "stains";
return "pattern";
}
private definePattern(
pattern: string,
element: "field" | "division" | "charge",
usedTinctures: string[],
): string {
let t1: string | null = null;
let t2: string | null = null;
let size = "";
// Size selection - must use sequential P() calls to match original behavior
if (P(0.1)) size = "-small";
// biome-ignore lint/suspicious/noDuplicateElseIf: <explanation>
else if (P(0.1)) size = "-smaller";
else if (P(0.01)) size = "-big";
else if (P(0.005)) size = "-smallest";
// apply standard tinctures
if (P(0.5) && ["vair", "vairInPale", "vairEnPointe"].includes(pattern)) {
t1 = "azure";
t2 = "argent";
} else if (P(0.8) && pattern === "ermine") {
t1 = "argent";
t2 = "sable";
} else if (pattern === "pappellony") {
if (P(0.2)) {
t1 = "gules";
t2 = "or";
// biome-ignore lint/suspicious/noDuplicateElseIf: <explanation>
} else if (P(0.2)) {
t1 = "argent";
t2 = "sable";
// biome-ignore lint/suspicious/noDuplicateElseIf: <explanation>
} else if (P(0.2)) {
t1 = "azure";
t2 = "argent";
}
} else if (pattern === "masoned") {
if (P(0.3)) {
t1 = "gules";
t2 = "argent";
// biome-ignore lint/suspicious/noDuplicateElseIf: <explanation>
} else if (P(0.3)) {
t1 = "argent";
t2 = "sable";
} else if (P(0.1)) {
t1 = "or";
t2 = "sable";
}
} else if (pattern === "fretty") {
if (t2 === "sable" || P(0.35)) {
t1 = "argent";
t2 = "gules";
} else if (P(0.25)) {
t1 = "sable";
t2 = "or";
} else if (P(0.15)) {
t1 = "gules";
t2 = "argent";
}
} else if (pattern === "semy")
pattern = `${pattern}_of_${this.selectCharge(charges.semy)}`;
if (!t1 || !t2) {
const tinctures = createTinctures();
const startWithMetal = P(0.7);
t1 = startWithMetal ? rw(tinctures.metals) : rw(tinctures.colours);
t2 = startWithMetal ? rw(tinctures.colours) : rw(tinctures.metals);
}
// division should not be the same tincture as base field
if (element === "division") {
if (usedTinctures.includes(t1)) t1 = this.replaceTincture(t1);
if (usedTinctures.includes(t2)) t2 = this.replaceTincture(t2);
}
usedTinctures.push(t1, t2);
return `${pattern}-${t1}-${t2}${size}`;
}
private replaceTincture(t: string): string {
const type = this.getType(t);
let n: string | null = null;
const tinctures = createTinctures();
while (!n || n === t) {
n = rw(
tinctures[type as keyof typeof tinctures] as Record<string, number>,
);
}
return n;
}
private getSize(
p: string,
o: string | null = null,
d: string | null = null,
): number {
if (p === "e" && (o === "bordure" || o === "orle")) return 1.1;
if (p === "e") return 1.5;
if (p === "jln" || p === "jlh") return 0.7;
if (p === "abcpqh" || p === "ez" || p === "be") return 0.5;
if (["a", "b", "c", "d", "f", "g", "h", "i", "bh", "df"].includes(p))
return 0.5;
if (["j", "l", "m", "o", "jlmo"].includes(p) && d === "perCross")
return 0.6;
if (p.length > 10) return 0.18; // >10 (bordure)
if (p.length > 7) return 0.3; // 8, 9, 10
if (p.length > 4) return 0.4; // 5, 6, 7
if (p.length > 2) return 0.5; // 3, 4
return 0.7; // 1, 2
}
getShield(culture: number, state?: number): string {
const emblemShape = document.getElementById(
"emblemShape",
) as HTMLSelectElement | null;
const shapeGroup =
emblemShape?.selectedOptions[0]?.parentElement?.getAttribute("label") ||
"Diversiform";
if (shapeGroup !== "Diversiform") return emblemShape!.value;
if (emblemShape?.value === "state" && state && pack.states[state].coa)
return pack.states[state].coa!.shield!;
if (pack.cultures[culture].shield) return pack.cultures[culture].shield!;
ERROR &&
console.error(
"Shield shape is not defined on culture level",
pack.cultures[culture],
);
return "heater";
}
toString(coa: Emblem): string {
return JSON.stringify(coa).replaceAll("#", "%23");
}
copy(coa: Emblem): Emblem {
return JSON.parse(JSON.stringify(coa));
}
get shields() {
return shields;
}
}
export default EmblemGeneratorModule;
window.COA = new EmblemGeneratorModule();

View file

@ -0,0 +1,2 @@
import "./generator";
import "./renderer";

View file

@ -0,0 +1,37 @@
// Line weights for random selection
// Different from lines.ts which contains SVG path data for rendering
export const lineWeights = {
straight: 50,
wavy: 8,
engrailed: 4,
invecked: 3,
rayonne: 3,
embattled: 1,
raguly: 1,
urdy: 1,
dancetty: 1,
indented: 2,
dentilly: 1,
bevilled: 1,
angled: 1,
flechy: 1,
barby: 1,
enclavy: 1,
escartely: 1,
arched: 2,
archedReversed: 1,
nowy: 1,
nowyReversed: 1,
embattledGhibellin: 1,
embattledNotched: 1,
embattledGrady: 1,
dovetailedIndented: 1,
dovetailed: 1,
potenty: 1,
potentyDexter: 1,
potentySinister: 1,
nebuly: 2,
seaWaves: 1,
dragonTeeth: 1,
firTrees: 1,
};

View file

@ -0,0 +1,57 @@
export const lines = {
straight: "m 0,100 v15 h 200 v -15 z",
engrailed:
"m 0,95 a 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 6.25,6.25 0 0 0 12.5,0 v 20 H 0 Z",
invecked:
"M0,102.5 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 a6.25,6.25,0,0,1,12.5,0 v12.5 H0 z",
embattled:
"M 0,105 H 2.5 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 15 V 95 h 15 v 10 h 2.5 v 10 H 0 Z",
wavy: "m 200,115 v -15 c -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 -8.9,3.5 -16,3.1 -25,0 -8.9,-3.5 -16,-3.1 -25,0 -8.9,3.5 -16,3.2 -25,0 -8.9,-3.5 -16,-3.2 -25,0 v 15 z",
raguly:
"m 200,95 h -3 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 h -10 l -5,10 h -10 l 5,-10 H 97 l -5,10 H 82 L 87,95 H 77 l -5,10 H 62 L 67,95 H 57 l -5,10 H 42 L 47,95 H 37 l -5,10 H 22 L 27,95 H 17 l -5,10 H 2 L 7,95 H 0 v 20 h 200 z",
dancetty:
"m 0,105 10,-15 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 15,20 15,-20 10,15 v 10 H 0 Z",
dentilly:
"M 180,105 170,95 v 10 L 160,95 v 10 L 150,95 v 10 L 140,95 v 10 L 130,95 v 10 L 120,95 v 10 L 110,95 v 10 L 100,95 v 10 L 90,95 v 10 L 80,95 v 10 L 70,95 v 10 L 60,95 v 10 L 50,95 v 10 L 40,95 v 10 L 30,95 v 10 L 20,95 v 10 L 10,95 v 10 L 0,95 v 20 H 200 V 105 L 190,95 v 10 L 180,95 Z",
angled: "m 0,95 h 100 v 10 h 100 v 10 H 0 Z",
urdy: "m 200,90 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,6 -5,-6 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 l -5,-5 -5,5 v 10 l -5,5 -5,-5 V 95 L 0,90 v 25 h 200",
indented:
"m 100,95 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 v 20 H 0 V 95 l 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 5,-10 5,10 z",
bevilled: "m 0,92.5 h 110 l -20,15 H 200 V 115 H 0 Z",
nowy: "m 0,95 h 80 c 0,0 0.1,20.1 20,20 19.9,-0.1 20,-20 20,-20 h 80 v 20 H 0 Z",
nowyReversed:
"m 200,105 h -80 c 0,0 -0.1,-20.1 -20,-20 -19.9,0.1 -20,20 -20,20 H 0 v 10 h 200 z",
potenty:
"m 3,95 v 5 h 5 v 5 H 0 v 10 h 200 l 0.5,-10 H 193 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 h -15 v -5 h 5 v -5 h -15 v 5 h 5 v 5 H 100.5 93 v -5 h 5 V 95 H 83 v 5 h 5 v 5 H 73 v -5 h 5 V 95 H 63 v 5 h 5 v 5 H 53 v -5 h 5 V 95 H 43 v 5 h 5 v 5 H 33 v -5 h 5 V 95 H 23 v 5 h 5 v 5 H 13 v -5 h 5 v -5 z",
potentyDexter:
"m 200,105 h -2 v -10 0 0 h -10 v 5 h 5 v 5 H 183 V 95 h -10 v 5 h 5 v 5 H 168 V 95 h -10 v 5 h 5 v 5 H 153 V 95 h -10 v 5 h 5 v 5 H 138 V 95 h -10 v 5 h 5 v 5 H 123 V 95 h -10 v 5 h 5 v 5 h -10 v 0 0 -10 H 98 v 5 h 5 v 5 H 93 V 95 H 83 v 5 h 5 v 5 H 78 V 95 H 68 v 5 h 5 v 5 H 63 V 95 H 53 v 5 h 5 v 5 H 48 V 95 H 38 v 5 h 5 v 5 H 33 V 95 H 23 v 5 h 5 v 5 H 18 V 95 H 8 v 5 h 5 v 5 H 3 V 95 H 0 v 20 h 200 z",
potentySinister:
"m 2.5,95 v 10 H 0 v 10 h 202.5 v -15 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 h -10 v 10 h -10 v -5 h 5 v -5 z",
embattledGhibellin:
"M 200,200 V 100 l -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 -5,-5 v 10 l -5,-5 -5,5 V 95 l -5,5 v 15 h 200",
embattledNotched:
"m 200,105 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 h -5 V 95 l -5,5 -5,-5 v 10 H 90 V 95 l -5,5 -5,-5 v 10 H 75 V 95 l -5,5 -5,-5 v 10 H 60 V 95 l -5,5 -5,-5 v 10 H 45 V 95 l -5,5 -5,-5 v 10 H 30 V 95 l -5,5 -5,-5 v 10 H 15 V 95 l -5,5 -5,-5 v 10 H 0 v 10 h 200",
embattledGrady:
"m 0,95 v 20 H 200 V 95 h -2.5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 h -5 v 5 h -5 v 5 h -5 v -5 h -5 v -5 z",
dovetailed:
"m 200,95 h -7 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 h -14 l 4,10 h -14 l 4,-10 H 93 l 4,10 H 83 L 87,95 H 73 l 4,10 H 63 L 67,95 H 53 l 4,10 H 43 L 47,95 H 33 l 4,10 H 23 L 27,95 H 13 l 4,10 H 3 L 7,95 H 0 v 20 h 200",
dovetailedIndented:
"m 200,100 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 -7,-5 4,10 -7,-5 -7,5 4,-10 -7,5 v 15 h 200",
nebuly:
"m 13.1,89.8 c -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.2,4.5 -7.3,4.5 -0.5,0 -2.2,-0.2 -2.2,-0.2 V 115 h 200 v -10.1 c -3.7,-0.2 -6.7,-2.2 -6.7,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.8,-1.9 1.8,-3.1 0,-2.5 -3.2,-4.5 -7.2,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 -1.5,4.1 -4.2,4.4 -8.8,4.5 -4.7,-0.1 -8.7,-1.5 -8.9,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 -4.1,0 -7.3,2 -7.3,4.5 0,1.2 0.7,2.3 1.8,3.1 1.2,0.7 1.9,1.8 1.9,3 0,2.5 -3.3,4.5 -7.3,4.5 -4,0 -7.3,-2 -7.3,-4.5 0,-1.2 0.7,-2.3 1.9,-3 1.2,-0.8 1.9,-1.9 1.9,-3.1 0,-2.5 -3.3,-4.5 -7.3,-4.5 z",
rayonne:
"M0 115l-.1-6 .2.8c1.3-1 2.3-2.5 2.9-4.4.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4A9 9 0 015.5 90c-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 2.1 3.1 3.1 4.6 1 1.6 2.4 3.1 2.7 4.8.3 1.7.3 3.3 0 5.2 1.3-1 2.6-2.7 3.2-4.6.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.5 2 1.7 3.6 3.1 4.6a9 9 0 013.1 4.6c.5 2 .4 3.9-.3 5.4a9 9 0 003.1-4.6c.5-2 .4-3.9-.3-5.4-.7-1.5-.8-3.4-.3-5.4.5-2 1.7-3.6 3.1-4.6-.7 1.5-.8 3.4-.3 5.4.75 2.79 2.72 4.08 4.45 5.82L200 115z",
seaWaves:
"m 28.83,94.9 c -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.33,-2.03 -2.19,-3.56 -4.45,-3.56 -4.24,0 -6.91,3.13 -8.5,5.13 V 115 h 200 v -14.89 c -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.44,-3.6 3.6,-3.6 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -6.6,3.09 -8.19,5.09 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.2,-3.55 -4.46,-3.55 -4.25,0 -7.16,3.17 -8.75,5.18 -1.59,2.01 -4.5,5.18 -8.75,5.18 -2.16,0 -3.91,-1.63 -3.91,-3.64 0,-2.01 1.75,-3.64 3.91,-3.64 0.7,0 1.36,0.17 1.93,0.48 -0.34,-2.01 -2.21,-3.55 -4.46,-3.55 z",
dragonTeeth:
"M 9.4,85 C 6.5,88.1 4.1,92.9 3,98.8 1.9,104.6 2.3,110.4 3.8,115 2.4,113.5 0,106.6 0,109.3 v 5.7 h 200 v -5.7 c -1.1,-2.4 -2,-5.1 -2.6,-8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.9 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.9 -0.7,11.6 0.8,16.2 -1.4,-1.5 -2.8,-3.9 -3.8,-6.1 -1.1,-2.4 -2.3,-6.1 -2.6,-7.7 -0.2,-5.9 0.2,-11.7 1.7,-16.3 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.9,-16.2 -3,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -2.9,-3.1 -5.3,-7.9 -6.4,-13.8 C 63,95.4 63.4,89.6 64.9,85 c -2.9,3.1 -5.3,7.9 -6.3,13.8 -1.1,5.8 -0.7,11.6 0.8,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.6,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 -1.1,-5.8 -0.7,-11.6 0.8,-16.2 -2.9,3.1 -5.3,7.9 -6.4,13.8 -1.1,5.8 -0.7,11.6 0.9,16.2 -3,-3.1 -5.3,-7.9 -6.4,-13.8 C 18.6,95.4 19,89.6 20.5,85 17.6,88.1 15.2,92.9 14.1,98.8 13,104.6 13.4,110.4 14.9,115 12,111.9 9.6,107.1 8.6,101.2 7.5,95.4 7.9,89.6 9.4,85 Z",
firTrees:
"m 3.9,90 -4,7 2,-0.5 L 0,100 v 15 h 200 v -15 l -1.9,-3.5 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4.1,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 -4,-7 -4,7 2,-0.5 -4,7 2,-0.5 -4,7 -4,-7 2,0.5 -4,-7 2,0.5 z",
flechy: "m 0,100 h 85 l 15,-15 15,15 h 85 v 15 H 0 Z",
barby: "m 0,100 h 85 l 15,15 15,-15 h 85 v 15 H 0 Z",
enclavy: "M 0,100 H 85 V 85 h 30 v 15 h 85 v 15 H 0 Z",
escartely: "m 0,100 h 85 v 15 h 30 v -15 h 85 v 15 H 0 Z",
arched: "m 100,95 c 40,-0.2 100,20 100,20 H 0 c 0,0 60,-19.8 100,-20 z",
archedReversed:
"m 0,85 c 0,0 60,20.2 100,20 40,-0.2 100,-20 100,-20 v 30 H 0 Z",
};

View file

@ -0,0 +1,162 @@
export const ordinaries = {
lined: {
pale: 7,
fess: 5,
bend: 3,
bendSinister: 2,
chief: 5,
bar: 2,
gemelle: 1,
fessCotissed: 1,
fessDoubleCotissed: 1,
bendlet: 2,
bendletSinister: 1,
terrace: 3,
cross: 6,
crossParted: 1,
saltire: 2,
saltireParted: 1,
},
straight: {
bordure: 8,
orle: 4,
mount: 1,
point: 2,
flaunches: 1,
gore: 1,
gyron: 1,
quarter: 1,
canton: 2,
pall: 3,
pallReversed: 2,
chevron: 4,
chevronReversed: 3,
pile: 2,
pileInBend: 2,
pileInBendSinister: 1,
piles: 1,
pilesInPoint: 2,
label: 1,
},
data: {
bar: {
positionsOn: { defdefdef: 1 },
positionsOff: { abc: 2, abcgzi: 1, jlh: 5, bgi: 2, ach: 1 },
},
bend: {
positionsOn: { ee: 2, jo: 1, joe: 1 },
positionsOff: { ccg: 2, ccc: 1 },
},
bendSinister: {
positionsOn: { ee: 1, lm: 1, lem: 4 },
positionsOff: { aai: 2, aaa: 1 },
},
bendlet: {
positionsOn: { joejoejoe: 1 },
positionsOff: { ccg: 2, ccc: 1 },
},
bendletSinister: {
positionsOn: { lemlemlem: 1 },
positionsOff: { aai: 2, aaa: 1 },
},
bordure: {
positionsOn: { ABCDEFGHIJKL: 1 },
positionsOff: { e: 4, jleh: 2, kenken: 1, peqpeq: 1 },
},
canton: {
positionsOn: { yyyy: 1 },
positionsOff: { e: 5, beh: 1, def: 1, bdefh: 1, kn: 1 },
},
chevron: {
positionsOn: { ach: 3, hhh: 1 },
},
chevronReversed: {
positionsOff: { bbb: 1 },
},
chief: {
positionsOn: { abc: 5, bbb: 1 },
positionsOff: { emo: 2, emoz: 1, ez: 2 },
},
cross: {
positionsOn: { eeee: 1, behdfbehdf: 3, behbehbeh: 2 },
positionsOff: { acgi: 1 },
},
crossParted: {
positionsOn: { e: 5, ee: 1 },
},
fess: {
positionsOn: { ee: 1, def: 3 },
positionsOff: { abc: 3, abcz: 1 },
},
fessCotissed: {
positionsOn: { ee: 1, def: 3 },
},
fessDoubleCotissed: {
positionsOn: { ee: 1, defdef: 3 },
},
flaunches: {
positionsOff: { e: 3, kn: 1, beh: 3 },
},
gemelle: {
positionsOff: { abc: 1 },
},
gyron: {
positionsOff: { bh: 1 },
},
label: {
positionsOff: { defgzi: 2, eh: 3, defdefhmo: 1, egiegi: 1, pqn: 5 },
},
mount: {
positionsOff: { e: 5, def: 1, bdf: 3 },
},
orle: {
positionsOff: { e: 4, jleh: 1, kenken: 1, peqpeq: 1 },
},
pale: {
positionsOn: { ee: 12, beh: 10, kn: 3, bb: 1 },
positionsOff: { yyy: 1 },
},
pall: {
positionsOn: { ee: 1, jleh: 5, jlhh: 3 },
positionsOff: { BCKFEILGJbdmfo: 1 },
},
pallReversed: {
positionsOn: { ee: 1, bemo: 5 },
positionsOff: { aczac: 1 },
},
pile: {
positionsOn: { bbb: 1 },
positionsOff: { acdfgi: 1, acac: 1 },
},
pileInBend: {
positionsOn: { eeee: 1, eeoo: 1 },
positionsOff: { cg: 1 },
},
pileInBendSinister: {
positionsOn: { eeee: 1, eemm: 1 },
positionsOff: { ai: 1 },
},
point: {
positionsOff: { e: 2, def: 1, bdf: 3, acbdef: 1 },
},
quarter: {
positionsOn: { jjj: 1 },
positionsOff: { e: 1 },
},
saltire: {
positionsOn: { ee: 5, jlemo: 1 },
},
saltireParted: {
positionsOn: { e: 5, ee: 1 },
},
terrace: {
positionsOff: { e: 5, def: 1, bdf: 3 },
},
} as Record<
string,
{
positionsOn?: Record<string, number>;
positionsOff?: Record<string, number>;
}
>,
};

View file

@ -0,0 +1,70 @@
export const shieldPaths = {
heater: "m25,25 h150 v50 a150,150,0,0,1,-75,125 a150,150,0,0,1,-75,-125 z",
spanish: "m25,25 h150 v100 a75,75,0,0,1,-150,0 z",
french:
"m 25,25 h 150 v 139.15 c 0,41.745 -66,18.15 -75,36.3 -9,-18.15 -75,5.445 -75,-36.3 v 0 z",
horsehead:
"m 20,40 c 0,60 40,80 40,100 0,10 -4,15 -0.35,30 C 65,185.7 81,200 100,200 c 19.1,0 35.3,-14.6 40.5,-30.4 C 144.2,155 140,150 140,140 140,120 180,100 180,40 142.72,40 150,15 100,15 55,15 55,40 20,40 Z",
horsehead2:
"M60 20c-5 20-10 35-35 55 25 35 35 65 30 100 20 0 35 10 45 26 10-16 30-26 45-26-5-35 5-65 30-100a87 87 0 01-35-55c-25 3-55 3-80 0z",
polish:
"m 90.3,6.3 c -12.7,0 -20.7,10.9 -40.5,14 0,11.8 -4.9,23.5 -11.4,31.1 0,0 12.7,6 12.7,19.3 C 51.1,90.8 30,90.8 30,90.8 c 0,0 -3.6,7.4 -3.6,22.4 0,34.3 23.1,60.2 40.7,68.2 17.6,8 27.7,11.4 32.9,18.6 5.2,-7.3 15.3,-10.7 32.8,-18.6 17.6,-8 40.7,-33.9 40.7,-68.2 0,-15 -3.6,-22.4 -3.6,-22.4 0,0 -21.1,0 -21.1,-20.1 0,-13.3 12.7,-19.3 12.7,-19.3 C 155.1,43.7 150.2,32.1 150.2,20.3 130.4,17.2 122.5,6.3 109.7,6.3 102.5,6.3 100,10 100,10 c 0,0 -2.5,-3.7 -9.7,-3.7 z",
hessen:
"M170 20c4 5 8 13 15 20 0 0-10 0-10 15 0 100-15 140-75 145-65-5-75-45-75-145 0-15-10-15-10-15l15-20c0 15 10-5 70-5s70 20 70 5z",
swiss:
"m 25,20 c -0.1,0 25.2,8.5 37.6,8.5 C 75.1,28.5 99.1,20 100,20 c 0.6,0 24.9,8.5 37.3,8.5 C 149.8,28.5 174.4,20 175,20 l -0.3,22.6 C 173.2,160.3 100,200 100,200 100,200 26.5,160.9 25.2,42.6 Z",
boeotian:
"M150 115c-5 0-10-5-10-15s5-15 10-15c10 0 7 10 15 10 10 0 0-30 0-30-10-25-30-55-65-55S45 40 35 65c0 0-10 30 0 30 8 0 5-10 15-10 5 0 10 5 10 15s-5 15-10 15c-10 0-7-10-15-10-10 0 0 30 0 30 10 25 30 55 65 55s55-30 65-55c0 0 10-30 0-30-8 0-5 10-15 10z",
roman: "m 160,170 c -40,20 -80,20 -120,0 V 30 C 80,10 120,10 160,30 Z",
kite: "m 53.3,46.4 c 0,4.1 1,12.3 1,12.3 7.1,55.7 45.7,141.3 45.7,141.3 0,0 38.6,-85.6 45.7,-141.2 0,0 1,-8.1 1,-12.3 C 146.7,20.9 125.8,0.1 100,0.1 74.2,0.1 53.3,20.9 53.3,46.4 Z",
oldFrench: "m25,25 h150 v75 a100,100,0,0,1,-75,100 a100,100,0,0,1,-75,-100 z",
renaissance:
"M 25,33.9 C 33.4,50.3 36.2,72.9 36.2,81.7 36.2,109.9 25,122.6 25,141 c 0,29.4 24.9,44.1 40.2,47.7 15.3,3.7 29.3,0 34.8,11.3 5.5,-11.3 19.6,-7.6 34.8,-11.3 C 150.1,185 175,170.3 175,141 c 0,-18.4 -11.2,-31.1 -11.2,-59.3 0,-8.8 2.8,-31.3 11.2,-47.7 L 155.7,14.4 C 138.2,21.8 119.3,25.7 100,25.7 c -19.3,0 -38.2,-3.9 -55.7,-11.3 z",
baroque:
"m 100,25 c 18,0 50,2 75,14 v 37 l -2.7,3.2 c -4.9,5.4 -6.6,9.6 -6.7,16.2 0,6.5 2,11.6 6.9,17.2 l 2.8,3.1 v 10.2 c 0,17.7 -2.2,27.7 -7.8,35.9 -5,7.3 -11.7,11.3 -32.3,19.4 -12.6,5 -20.2,8.8 -28.6,14.5 C 103.3,198 100,200 100,200 c 0,0 -2.8,-2.3 -6.4,-4.7 C 85.6,189.8 78,186 65,180.9 32.4,168.1 26.9,160.9 25.8,129.3 L 25,116 l 3.3,-3.3 c 4.8,-5.2 7,-10.7 7,-17.3 0,-6.8 -1.8,-11.1 -6.5,-16.1 L 25,76 V 39 C 50,27 82,25 100,25 Z",
targe:
"m 20,35 c 15,0 115,-60 155,-10 -5,10 -15,15 -10,50 5,45 10,70 -10,90 C 125,195 75,195 50,175 25,150 30,130 35,85 50,95 65,85 65,70 65,50 50,45 40,50 30,55 27,65 30,70 23,73 20,70 14,70 11,60 20,45 20,35 Z",
targe2:
"m 84,32.2 c 6.2,-1 19.5,-31.4 94.1,-20.2 -30.57,33.64 -21.66,67.37 -11.2,95 20.2,69.5 -41.17549,84.7 -66.88,84.7 C 74.32,191.7071 8.38,168.95 32,105.9 36.88,92.88 31,89 31,82.6 35.15,82.262199 56.79,86.17 56.5,69.8 56.20,52.74 42.2,47.9 25.9,55.2 25.9,51.4 39.8,6.7 84,32.2 Z",
pavise:
"M95 7L39.9 37.3a10 10 0 00-5.1 9.5L46 180c.4 5.2 3.7 10 9 10h90c5.3 0 9.6-4.8 10-10l10.6-133.2a10 10 0 00-5-9.5L105 7c-4.2-2.3-6.2-2.3-10 0z",
wedged:
"m 51.2,19 h 96.4 c 3.1,12.7 10.7,20.9 26.5,20.8 C 175.7,94.5 165.3,144.3 100,200 43.5,154.2 22.8,102.8 25.1,39.7 37,38.9 47.1,34.7 51.2,19 Z",
round:
"m 185,100 a 85,85 0 0 1 -85,85 85,85 0 0 1 -85,-85 85,85 0 0 1 85,-85 85,85 0 0 1 85,85",
oval: "m 32.3,99.5 a 67.7,93.7 0 1 1 0,1.3 z",
vesicaPiscis:
"M 100,0 C 63.9,20.4 41,58.5 41,100 c 0,41.5 22.9,79.6 59,100 36.1,-20.4 59,-58.5 59,-100 C 159,58.5 136.1,20.4 100,0 Z",
square: "M 25,25 H 175 V 175 H 25 Z",
diamond: "M 25,100 100,200 175,100 100,0 Z",
no: "m0,0 h200 v200 h-200 z",
flag: "M 10,40 h180 v120 h-180 Z",
pennon: "M 10,40 l190,60 -190,60 Z",
guidon: "M 10,40 h190 l-65,60 65,60 h-190 Z",
banner: "m 25,25 v 170 l 25,-40 25,40 25,-40 25,40 25,-40 25,40 V 25 Z",
dovetail: "m 25,25 v 175 l 75,-40 75,40 V 25 Z",
gonfalon: "m 25,25 v 125 l 75,50 75,-50 V 25 Z",
pennant: "M 25,15 100,200 175,15 Z",
fantasy1:
"M 100,5 C 85,30 40,35 15,40 c 40,35 20,90 40,115 15,25 40,30 45,45 5,-15 30,-20 45,-45 20,-25 0,-80 40,-115 C 160,35 115,30 100,5 Z",
fantasy2:
"m 152,21 c 0,0 -27,14 -52,-4 C 75,35 48,21 48,21 50,45 30,55 30,75 60,75 60,115 32,120 c 3,40 53,50 68,80 15,-30 65,-40 68,-80 -28,-5 -28,-45 2,-45 C 170,55 150,45 152,21 Z",
fantasy3:
"M 167,67 C 165,0 35,0 33,67 c 32,-7 27,53 -3,43 -5,45 60,65 70,90 10,-25 75,-47.51058 70,-90 -30,10 -35,-50 -3,-43 z",
fantasy4:
"M100 9C55 48 27 27 13 39c23 50 3 119 49 150 14 9 28 11 38 11s27-4 38-11c55-39 24-108 49-150-14-12-45 7-87-30z",
fantasy5:
"M 100,0 C 75,25 30,25 30,25 c 0,69 20,145 70,175 50,-30 71,-106 70,-175 0,0 -45,0 -70,-25 z",
noldor:
"m 55,75 h 2 c 3,-25 38,-10 3,20 15,50 30,75 40,105 10,-30 25,-55 40,-105 -35,-30 0,-45 3,-20 h 2 C 150,30 110,20 100,0 90,20 50,30 55,75 Z",
gondor:
"m 100,200 c 15,-15 38,-35 45,-60 h 5 V 30 h -5 C 133,10 67,10 55,30 h -5 v 110 h 5 c 7,25 30,45 45,60 z",
easterling: "M 160,185 C 120,170 80,170 40,185 V 15 c 40,15 80,15 120,0 z",
erebor:
"M25 135 V60 l22-13 16-37 h75 l15 37 22 13 v75l-22 18-16 37 H63l-16-37z",
ironHills: "m 30,25 60,-10 10,10 10,-10 60,10 -5,125 -65,50 -65,-50 z",
urukHai:
"M 30,60 C 40,60 60,50 60,20 l -5,-3 45,-17 75,40 -5,5 -35,155 -5,-35 H 70 v 35 z",
moriaOrc:
"M45 35c5 3 7 10 13 9h19c4-2 7-4 9-9 6 1 9 9 16 11 7-2 14 0 21 0 6-3 6-10 10-15 2-5 1-10-2-15-2-4-5-14-4-16 3 6 7 11 12 14 7 3 3 12 7 16 3 6 4 12 9 18 2 4 6 8 5 14 0 6-1 12 3 18-3 6-2 13-1 20 1 6-2 12-1 18 0 6-3 13 0 18 8 4 0 8-5 7-4 3-9 3-13 9-5 5-5 13-8 19 0 6 0 15-7 16-1 6-7 6-10 12-1-6 0-6-2-9l2-19c2-4 5-12-3-12-4-5-11-5-15 1l-13-18c-3-4-2 9-3 12 2 2-4-6-7-5-8-2-8 7-11 11-2 4-5 10-8 9 3-10 3-16 1-23-1-4 2-9-4-11 0-6 1-13-2-19-4-2-9-6-13-7V91c4-7-5-13 0-19-3-7 2-11 2-18-1-6 1-12 3-17v-1z",
};

View file

@ -0,0 +1,126 @@
export const patterns = {
semy: (p: string, c1: string, c2: string, size: number, chargeId: string) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="200" fill="${c1}" stroke="none"/><g fill="${c2}"><use transform="translate(-100 -50)" href="#${chargeId}"/><use transform="translate(100 -50)" href="#${chargeId}"/><use transform="translate(0 50)" href="#${chargeId}"/></g></pattern>`,
vair: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="25" fill="${c1}" stroke="none"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c2}" stroke="none"/><path d="m25,25 l-6.25,6.25 v12.5 l-6.25,6.25 l-6.25,-6.25 v-12.5 l-6.25,-6.25 z" fill="${c1}"/><path d="M0 50 h25" fill="none"/></pattern>`,
counterVair: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50" stroke="#000" stroke-width=".2"><rect width="25" height="50" fill="${c2}" stroke="none"/><path d="m 12.5,0 6.25,6.25 v 12.5 L 25,25 18.75,31.25 v 12.5 L 12.5,50 6.25,43.75 V 31.25 L 0,25 6.25,18.75 V 6.25 Z" fill="${c1}"/></pattern>`,
vairInPale: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 25 25"><rect width="25" height="25" fill="${c1}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}" stroke="#000" stroke-width=".2"/></pattern>`,
vairEnPointe: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 25 50"><rect width="25" height="25" fill="${c2}"/><path d="m12.5,0 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c1}"/><rect x="0" y="25" width="25" height="25" fill="${c1}" stroke-width="1" stroke="${c1}"/><path d="m12.5,25 l6.25,6.25 v12.5 l6.25,6.25 h-25 l6.25,-6.25 v-12.5 z" fill="${c2}"/></pattern>`,
vairAncien: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><path fill="${c2}" stroke="none" d="m 0,90 c 10,0 25,-5 25,-40 0,-25 10,-40 25,-40 15,0 25,15 25,40 0,35 15,40 25,40 v 10 H 0 Z"/><path fill="none" stroke="#000" d="M 0,90 c 10,0 25,-5 25,-40 0,-35 15,-40 25,-40 10,0 25,5 25,40 0,35 15,40 25,40 M0,100 h100"/></pattern>`,
potent: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="#000"><rect width="200" height="100" fill="${c1}" stroke="none"/><rect y="100" width="200" height="100" fill="${c2}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}"/><path d="m25 100v50h50v50h50v-50h50v-50z" fill="${c1}"/><path d="m0 0h200 M0 100h200" fill="none"/></pattern>`,
counterPotent: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m25 50h50v-50h50v50h50v100h-50v50h-50v-50h-50v-50z" fill="${c2}"/><path d="m0 0h200 M0 100h200 M0 200h200"/></pattern>`,
potentInPale: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.0625
}" viewBox="0 0 200 100" stroke-width="1"><rect width="200" height="100" fill="${c1}" stroke="none"/><path d="m25 50h50v-50h50v50h50v50h-150z" fill="${c2}" stroke="#000"/><path d="m0 0h200 M0 100h200" fill="none" stroke="#000"/></pattern>`,
potentEnPointe: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" stroke="none"><rect width="200" height="200" fill="${c1}"/><path d="m0 0h25v50h50v50h50v-50h50v-50h25v100h-25v50h-50v50h-50v-50h-50v-50h-25v-100" fill="${c2}"/></pattern>`,
ermine: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 200 200" fill="${c2}"><rect width="200" height="200" fill="${c1}"/><g stroke="none" fill="${c2}"><g transform="translate(-100 -50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g><g transform="translate(100 -50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g><g transform="translate(0 50)"><path d="m100 81.1c-4.25 17.6-12.7 29.8-21.2 38.9 3.65-0.607 7.9-3.04 11.5-5.47-2.42 4.86-4.86 8.51-7.3 12.7 1.82-0.607 6.07-4.86 12.7-10.9 1.21 8.51 2.42 17.6 4.25 23.6 1.82-5.47 3.04-15.2 4.25-23.6 3.65 3.65 7.3 7.9 12.7 10.9l-7.9-13.3c3.65 1.82 7.9 4.86 11.5 6.07-9.11-9.11-17-21.2-20.6-38.9z"/><path d="m82.4 81.7c-0.607-0.607-6.07 2.42-9.72-4.25 7.9 6.68 15.2-7.3 21.8 1.82 1.82 4.25-6.68 10.9-12.1 2.42z"/><path d="m117 81.7c0.607-1.21 6.07 2.42 9.11-4.86-7.3 7.3-15.2-7.3-21.2 2.42-1.82 4.25 6.68 10.9 12.1 2.42z"/><path d="m101 66.5c-1.02-0.607 3.58-4.25-3.07-8.51 5.63 7.9-10.2 10.9-1.54 17.6 3.58 2.42 12.2-2.42 4.6-9.11z"/></g></g></pattern>`,
chequy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.25}" height="${
size * 0.25
}" viewBox="0 0 50 50" fill="${c2}"><rect width="50" height="50"/><rect width="25" height="25" fill="${c1}"/><rect x="25" y="25" width="25" height="25" fill="${c1}"/></pattern>`,
lozengy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><polygon points="25,0 50,25 25,50 0,25" fill="${c2}"/></pattern>`,
fusily: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 50 100"><rect width="50" height="100" fill="${c2}"/><polygon points="25,0 50,50 25,100 0,50" fill="${c1}"/></pattern>`,
pally: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.125
}" viewBox="0 0 100 25"><rect width="100" height="25" fill="${c2}"/><rect x="25" y="0" width="25" height="25" fill="${c1}"/><rect x="75" y="0" width="25" height="25" fill="${c1}"/></pattern>`,
barry: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.5
}" viewBox="0 0 25 100"><rect width="25" height="100" fill="${c2}"/><rect x="0" y="25" width="25" height="25" fill="${c1}"/><rect x="0" y="75" width="25" height="25" fill="${c1}"/></pattern>`,
gemelles: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 50 50"><rect width="50" height="50" fill="${c1}"/><rect y="5" width="50" height="10" fill="${c2}"/><rect y="40" width="50" height="10" fill="${c2}"/></pattern>`,
bendy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.5
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><polygon points="0,25 75,100 25,100 0,75" fill="${c2}"/><polygon points="25,0 75,0 100,25 100,75" fill="${c2}"/></pattern>`,
bendySinister: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.5}" height="${
size * 0.5
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c2}"/><polygon points="0,25 25,0 75,0 0,75" fill="${c1}"/><polygon points="25,100 100,25 100,75 75,100" fill="${c1}"/></pattern>`,
palyBendy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.6258}" height="${
size * 0.3576
}" viewBox="0 0 175 100"><rect y="0" x="0" width="175" height="100" fill="${c2}"/><g fill="${c1}"><path d="m0 20 35 30v50l-35-30z"/><path d="m35 0 35 30v50l-35-30z"/><path d="m70 0h23l12 10v50l-35-30z"/><path d="m70 80 23 20h-23z"/><path d="m105 60 35 30v10h-35z"/><path d="m105 0h35v40l-35-30z"/><path d="m 140,40 35,30 v 30 h -23 l -12,-10z"/><path d="M 175,0 V 20 L 152,0 Z"/></g></pattern>`,
barryBendy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.3572}" height="${
size * 0.6251
}" viewBox="0 0 100 175"><rect width="100" height="175" fill="${c2}"/><g fill="${c1}"><path d="m20 0 30 35h50l-30-35z"/><path d="m0 35 30 35h50l-30-35z"/><path d="m0 70v23l10 12h50l-30-35z"/><path d="m80 70 20 23v-23z"/><path d="m60 105 30 35h10v-35z"/><path d="m0 105v35h40l-30-35z"/><path d="m 40,140 30,35 h 30 v -23 l -10,-12 z"/><path d="m0 175h20l-20-23z"/></g></pattern>`,
pappellony: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100"><rect width="100" height="100" fill="${c1}"/><circle cx="0" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="100" cy="51" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/><circle cx="50" cy="1" r="45" stroke="${c2}" fill="${c1}" stroke-width="10"/></pattern>`,
pappellony2: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" stroke="#000" stroke-width="2"><rect width="100" height="100" fill="${c1}" stroke="none"/><circle cy="50" r="49" fill="${c2}"/><circle cx="100" cy="50" r="49" fill="${c2}"/><circle cx="50" cy="0" r="49" fill="${c1}"/></pattern>`,
scaly: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" stroke="#000"><rect width="100" height="100" fill="${c1}" stroke="none"/><path d="M 0,84 C -40,84 -50,49 -50,49 -50,79 -27,99 0,99 27,99 50,79 50,49 50,49 40,84 0,84 Z" fill="${c2}"/><path d="M 100,84 C 60,84 50,49 50,49 c 0,30 23,50 50,50 27,0 50,-20 50,-50 0,0 -10,35 -50,35 z" fill="${c2}"/><path d="M 50,35 C 10,35 0,0 0,0 0,30 23,50 50,50 77,50 100,30 100,0 100,0 90,35 50,35 Z" fill="${c2}"/></pattern>`,
plumetty: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.25
}" viewBox="0 0 50 100" stroke-width=".8"><rect width="50" height="100" fill="${c2}" stroke="none"/><path fill="${c1}" stroke="none" d="M 25,100 C 44,88 49.5,74 50,50 33.5,40 25,25 25,4e-7 25,25 16.5,40 0,50 0.5,74 6,88 25,100 Z"/><path fill="none" stroke="${c2}" d="m17 40c5.363 2.692 10.7 2.641 16 0m-19 7c7.448 4.105 14.78 3.894 22 0m-27 7c6-2 10.75 3.003 16 3 5.412-0.0031 10-5 16-3m-35 9c4-7 12 3 19 2 7 1 15-9 19-2m-35 6c6-2 11 3 16 3s10-5 16-3m-30 7c8 0 8 3 14 3s7-3 14-3m-25 8c7.385 4.048 14.72 3.951 22 0m-19 8c5.455 2.766 10.78 2.566 16 0m-8 6v-78"/><g fill="none" stroke="${c1}"><path d="m42 90c2.678 1.344 5.337 2.004 8 2m-11 5c3.686 2.032 7.344 3.006 10.97 3m0.0261-1.2e-4v-30"/><path d="m0 92c2.689 0.0045 5.328-0.6687 8-2m-8 10c3.709-0.0033 7.348-1.031 11-3m-11 3v-30"/><path d="m0 7c5.412-0.0031 10-5 16-3m-16 11c7 1 15-9 19-2m-19 9c5 0 10-5 16-3m-16 10c6 0 7-3 14-3m-14.02 11c3.685-0.002185 7.357-1.014 11.02-3m-11 10c2.694-0.01117 5.358-0.7036 7.996-2m-8 6v-48"/><path d="m34 4c6-2 10.75 3.003 16 3m-19 6c4-7 12 3 19 2m-16 4c6-2 11 3 16 3m-14 4c8 0 8 3 14 3m-11 5c3.641 1.996 7.383 2.985 11 3m-8 5c2.762 1.401 5.303 2.154 8.002 2.112m-0.00154 3.888v-48"/></g></pattern>`,
masoned: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.125}" height="${
size * 0.125
}" viewBox="0 0 100 100" fill="none"><rect width="100" height="100" fill="${c1}"/><rect width="100" height="50" stroke="${c2}" stroke-width="4"/><line x1="50" y1="50" x2="50" y2="100" stroke="${c2}" stroke-width="5"/></pattern>`,
fretty: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.2}" height="${
size * 0.2
}" viewBox="0 0 140 140" stroke="#000" stroke-width="2"><rect width="140" height="140" fill="${c1}" stroke="none"/><path d="m-15 5 150 150 20-20-150-150z" fill="${c2}"/><path d="m10 150 140-140-20-20-140 140z" fill="${c2}" stroke="none"/><path d="m0 120 20 20 120-120-20-20z" fill="none"/></pattern>`,
grillage: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.25}" height="${
size * 0.25
}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect width="200" height="200" fill="${c1}" stroke="none"/><path d="m205 65v-30h-210v30z" fill="${c2}"/><path d="m65-5h-30v210h30z" fill="${c2}"/><path d="m205 165v-30h-210v30z" fill="${c2}"/><path d="m165,65h-30v140h30z" fill="${c2}"/><path d="m 165,-5h-30v40h30z" fill="${c2}"/></pattern>`,
chainy: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.167}" height="${
size * 0.167
}" viewBox="0 0 200 200" stroke="#000" stroke-width="2"><rect x="-6.691e-6" width="200" height="200" fill="${c1}" stroke="none"/><path d="m155-5-20-20-160 160 20 20z" fill="${c2}"/><path d="m45 205 160-160 20 20-160 160z" fill="${c2}"/><path d="m45-5 20-20 160 160-20 20-160-160" fill="${c2}"/><path d="m-5 45-20 20 160 160 20-20-160-160" fill="${c2}"/></pattern>`,
maily: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.167}" height="${
size * 0.167
}" viewBox="0 0 200 200" stroke="#000" stroke-width="1.2"><path fill="${c1}" stroke="none" d="M0 0h200v200H0z"/><g fill="${c2}"><path d="m80-2c-5.27e-4 2.403-0.1094 6.806-0.3262 9.199 5.014-1.109 10.1-1.768 15.19-2.059 0.09325-1.712 0.1401-5.426 0.1406-7.141z"/><path d="m100 5a95 95 0 0 0-95 95 95 95 0 0 0 95 95 95 95 0 0 0 95-95 95 95 0 0 0-95-95zm0 15a80 80 0 0 1 80 80 80 80 0 0 1-80 80 80 80 0 0 1-80-80 80 80 0 0 1 80-80z"/><path d="m92.8 20.33c-5.562 0.4859-11.04 1.603-16.34 3.217-7.793 25.31-27.61 45.12-52.91 52.91-5.321 1.638-10.8 2.716-16.34 3.217-2.394 0.2168-6.796 0.3256-9.199 0.3262v15c1.714-4.79e-4 5.429-0.04737 7.141-0.1406 5.109-0.2761 10.19-0.9646 15.19-2.059 36.24-7.937 64.54-36.24 72.47-72.47z"/><path d="m202 80c-2.403-5.31e-4 -6.806-0.1094-9.199-0.3262 1.109 5.014 1.768 10.1 2.059 15.19 1.712 0.09326 5.426 0.1401 7.141 0.1406z"/><path d="m179.7 92.8c-0.4859-5.562-1.603-11.04-3.217-16.34-25.31-7.793-45.12-27.61-52.91-52.91-1.638-5.321-2.716-10.8-3.217-16.34-0.2168-2.394-0.3256-6.796-0.3262-9.199h-15c4.8e-4 1.714 0.0474 5.429 0.1406 7.141 0.2761 5.109 0.9646 10.19 2.059 15.19 7.937 36.24 36.24 64.54 72.47 72.47z"/><path d="m120 202c5.3e-4 -2.403 0.1094-6.806 0.3262-9.199-5.014 1.109-10.1 1.768-15.19 2.059-0.0933 1.712-0.1402 5.426-0.1406 7.141z"/><path d="m107.2 179.7c5.562-0.4859 11.04-1.603 16.34-3.217 7.793-25.31 27.61-45.12 52.91-52.91 5.321-1.638 10.8-2.716 16.34-3.217 2.394-0.2168 6.796-0.3256 9.199-0.3262v-15c-1.714 4.7e-4 -5.429 0.0474-7.141 0.1406-5.109 0.2761-10.19 0.9646-15.19 2.059-36.24 7.937-64.54 36.24-72.47 72.47z"/><path d="m -2,120 c 2.403,5.4e-4 6.806,0.1094 9.199,0.3262 -1.109,-5.014 -1.768,-10.1 -2.059,-15.19 -1.712,-0.0933 -5.426,-0.1402 -7.141,-0.1406 z"/><path d="m 20.33,107.2 c 0.4859,5.562 1.603,11.04 3.217,16.34 25.31,7.793 45.12,27.61 52.91,52.91 1.638,5.321 2.716,10.8 3.217,16.34 0.2168,2.394 0.3256,6.796 0.3262,9.199 L 95,202 c -4.8e-4,-1.714 -0.0472,-5.44 -0.1404,-7.152 -0.2761,-5.109 -0.9646,-10.19 -2.059,-15.19 -7.937,-36.24 -36.24,-64.54 -72.47,-72.47 z"/></g></pattern>`,
honeycombed: (p: string, c1: string, c2: string, size: number) =>
`<pattern id="${p}" width="${size * 0.143}" height="${
size * 0.24514
}" viewBox="0 0 70 120"><rect width="70" height="120" fill="${c1}"/><path d="M 70,0 V 20 L 35,40 m 35,80 V 100 L 35,80 M 0,120 V 100 L 35,80 V 40 L 0,20 V 0" stroke="${c2}" fill="none" stroke-width="3"/></pattern>`,
};

View file

@ -0,0 +1,51 @@
export const positions = {
conventional: {
e: 20,
abcdefgzi: 3,
beh: 3,
behdf: 2,
acegi: 1,
kn: 3,
bhdf: 1,
jeo: 1,
abc: 3,
jln: 6,
jlh: 3,
kmo: 2,
jleh: 1,
def: 3,
abcpqh: 4,
ABCDEFGHIJKL: 1,
},
complex: {
e: 40,
beh: 1,
kn: 1,
jeo: 1,
abc: 2,
jln: 7,
jlh: 2,
def: 1,
abcpqh: 1,
},
divisions: {
perPale: { e: 15, pq: 5, jo: 2, jl: 2, ABCDEFGHIJKL: 1 },
perFess: {
e: 12,
kn: 4,
jkl: 2,
gizgiz: 1,
jlh: 3,
kmo: 1,
ABCDEFGHIJKL: 1,
},
perBend: { e: 5, lm: 5, bcfdgh: 1 },
perBendSinister: { e: 1, jo: 1 },
perCross: { e: 4, jlmo: 1, j: 1, jo: 2, jl: 1 },
perChevron: { e: 1, jlh: 1, dfk: 1, dfbh: 2, bdefh: 1 },
perChevronReversed: { e: 1, mok: 2, dfh: 2, dfbh: 1, bdefh: 1 },
perSaltire: { bhdf: 8, e: 3, abcdefgzi: 1, bh: 1, df: 1, ABCDEFGHIJKL: 1 },
perPile: { ee: 3, be: 2, abceh: 1, abcabc: 1, jleh: 1 },
},
inescutcheon: { e: 4, jln: 1 },
};

View file

@ -0,0 +1,363 @@
import { shieldBox } from "./box";
import { colors } from "./colors";
import { lines } from "./lines";
import { shieldPaths } from "./paths";
import { patterns } from "./patterns";
import { shieldPositions } from "./shieldPositions";
import { shieldSize } from "./size";
import { templates } from "./templates";
declare global {
var COArenderer: EmblemRenderModule;
}
interface Division {
division: string;
line?: string;
t: string;
}
interface Ordinary {
ordinary: string;
line?: string;
t: string;
divided?: "field" | "division" | "counter";
above?: boolean;
}
interface Charge {
stroke: string;
charge: string;
t: string;
size?: number;
sinister?: boolean;
reversed?: boolean;
line?: string;
divided?: "field" | "division" | "counter";
p: number[]; // position on shield from 1 to 9
}
interface Emblem {
shield: string;
t1: string;
division?: Division;
ordinaries?: Ordinary[];
charges?: Charge[];
custom?: boolean; // if true, coa will not be rendered
}
class EmblemRenderModule {
get shieldPaths() {
return shieldPaths;
}
private getTemplate(id: string, line?: string) {
const linedId = `${id}Lined` as keyof typeof templates;
if (!line || line === "straight" || !templates[linedId])
return templates[id as keyof typeof templates]; // return regular template if no line or line is straight or lined template does not exist
const linePath = lines[line as keyof typeof lines];
return (templates[linedId] as (line: string) => string)(linePath);
}
// get charge is string starts with "semy"
private semy(input: string | undefined) {
if (!input) return false;
const isSemy = /^semy/.test(input);
if (!isSemy) return false;
const match = input.match(/semy_of_(.*?)-/);
return match ? match[1] : false;
}
private async fetchCharge(charge: string, id: string) {
const fetched = fetch(`./charges/${charge}.svg`)
.then((res) => {
if (res.ok) return res.text();
else throw new Error("Cannot fetch charge");
})
.then((text) => {
const html = document.createElement("html");
html.innerHTML = text;
const g: SVGAElement = html.querySelector("g") as SVGAElement;
g.setAttribute("id", `${charge}_${id}`);
return g.outerHTML;
})
.catch((err) => {
ERROR && console.error(err);
});
return fetched;
}
private async getCharges(coa: Emblem, id: string, shieldPath: string) {
const charges = coa.charges
? coa.charges.map((charge) => charge.charge)
: []; // add charges
if (this.semy(coa.t1)) charges.push(this.semy(coa.t1) as string); // add field semy charge
if (this.semy(coa.division?.t))
charges.push(this.semy(coa.division?.t) as string); // add division semy charge
const uniqueCharges = [...new Set(charges)];
const fetchedCharges = await Promise.all(
uniqueCharges.map(async (charge) => {
if (charge === "inescutcheon")
return `<g id="inescutcheon_${id}"><path transform="translate(66 66) scale(.34)" d="${shieldPath}"/></g>`;
const fetched = await this.fetchCharge(charge, id);
return fetched;
}),
);
return fetchedCharges.join("");
}
// get color or link to pattern
private clr(tincture: string) {
return tincture in colors
? colors[tincture as keyof typeof colors]
: `url(#${tincture})`;
}
private getSizeMod(size: string) {
if (size === "small") return 0.8;
if (size === "smaller") return 0.5;
if (size === "smallest") return 0.25;
if (size === "big") return 1.6;
return 1;
}
private getPatterns(coa: Emblem, id: string) {
const isPattern = (string: string) => string.includes("-");
const patternsToAdd = [];
if (coa.t1.includes("-")) patternsToAdd.push(coa.t1); // add field pattern
if (coa.division && isPattern(coa.division.t))
patternsToAdd.push(coa.division.t); // add division pattern
if (coa.ordinaries)
coa.ordinaries
.filter((ordinary) => isPattern(ordinary.t))
.forEach((ordinary) => {
patternsToAdd.push(ordinary.t); // add ordinaries pattern
});
if (coa.charges)
coa.charges
.filter((charge) => isPattern(charge.t))
.forEach((charge) => {
patternsToAdd.push(charge.t); // add charges pattern
});
if (!patternsToAdd.length) return "";
return [...new Set(patternsToAdd)]
.map((patternString) => {
const [pattern, t1, t2, size] = patternString.split("-");
const charge = this.semy(patternString);
if (charge)
return patterns.semy(
patternString,
this.clr(t1),
this.clr(t2),
this.getSizeMod(size),
`${charge}_${id}`,
);
return patterns[pattern as keyof typeof patterns](
patternString,
this.clr(t1),
this.clr(t2),
this.getSizeMod(size),
charge as string,
);
})
.join("");
}
private async draw(id: string, coa: Emblem) {
const { shield = "heater", division, ordinaries = [], charges = [] } = coa;
const ordinariesRegular = ordinaries.filter((o) => !o.above);
const ordinariesAboveCharges = ordinaries.filter((o) => o.above);
const shieldPath =
shield in shieldPaths
? shieldPaths[shield as keyof typeof shieldPaths]
: shieldPaths.heater;
const tDiv = division
? division.t.includes("-")
? division.t.split("-")[1]
: division.t
: null;
const positions =
shield in shieldPositions
? shieldPositions[shield as keyof typeof shieldPositions]
: shieldPositions.heater;
const sizeModifier =
shield in shieldSize ? shieldSize[shield as keyof typeof shieldSize] : 1;
const viewBox =
shield in shieldBox
? shieldBox[shield as keyof typeof shieldBox]
: "0 0 200 200";
const shieldClip = `<clipPath id="${shield}_${id}"><path d="${shieldPath}"/></clipPath>`;
const divisionClip = division
? `<clipPath id="divisionClip_${id}">${this.getTemplate(division.division, division.line)}</clipPath>`
: "";
const loadedCharges = await this.getCharges(coa, id, shieldPath);
const loadedPatterns = this.getPatterns(coa, id);
const blacklight = `<radialGradient id="backlight_${id}" cx="100%" cy="100%" r="150%"><stop stop-color="#fff" stop-opacity=".3" offset="0"/><stop stop-color="#fff" stop-opacity=".15" offset=".25"/><stop stop-color="#000" stop-opacity="0" offset="1"/></radialGradient>`;
const field = `<rect x="0" y="0" width="200" height="200" fill="${this.clr(coa.t1)}"/>`;
const style = `<style>
g.secondary,path.secondary {fill: var(--secondary);}
g.tertiary,path.tertiary {fill: var(--tertiary);}
</style>`;
const templateCharge = (
charge: Charge,
tincture: string,
secondaryTincture?: string,
tertiaryTincture?: string,
) => {
const primary = this.clr(tincture);
const secondary = this.clr(secondaryTincture || tincture);
const tertiary = this.clr(tertiaryTincture || tincture);
const stroke = charge.stroke || "#000";
const chargePositions = [...new Set(charge.p)].filter(
(position) => positions[position as unknown as keyof typeof positions],
); // filter out invalid positions
let svg = `<g fill="${primary}" style="--secondary: ${secondary}; --tertiary: ${tertiary}" stroke="${stroke}">`;
for (const p of chargePositions) {
const transform = getElTransform(charge, p);
svg += `<use href="#${charge.charge}_${id}" transform="${transform}"></use>`;
}
return `${svg}</g>`;
function getElTransform(c: Charge, p: string | number) {
const s = (c.size || 1) * sizeModifier;
const sx = c.sinister ? -s : s;
const sy = c.reversed ? -s : s;
let [x, y] = positions[p as keyof typeof positions];
x = x - 100 * (sx - 1);
y = y - 100 * (sy - 1);
const scale = c.sinister || c.reversed ? `${sx} ${sy}` : s;
return `translate(${x} ${y}) scale(${scale})`;
}
};
const templateOrdinary = (ordinary: Ordinary, tincture: string) => {
const fill = this.clr(tincture);
let svg = `<g fill="${fill}" stroke="none">`;
if (ordinary.ordinary === "bordure")
svg += `<path d="${shieldPath}" fill="none" stroke="${fill}" stroke-width="16.7%"/>`;
else if (ordinary.ordinary === "orle")
svg += `<path d="${shieldPath}" fill="none" stroke="${fill}" stroke-width="5%" transform="scale(.85)" transform-origin="center"/>`;
else svg += this.getTemplate(ordinary.ordinary, ordinary.line);
return `${svg}</g>`;
};
const templateDivision = () => {
let svg = "";
// In field part
for (const ordinary of ordinariesRegular) {
if (ordinary.divided === "field")
svg += templateOrdinary(ordinary, ordinary.t);
else if (ordinary.divided === "counter")
svg += templateOrdinary(ordinary, tDiv!);
}
for (const charge of charges) {
if (charge.divided === "field") svg += templateCharge(charge, charge.t);
else if (charge.divided === "counter")
svg += templateCharge(charge, tDiv!);
}
for (const ordinary of ordinariesAboveCharges) {
if (ordinary.divided === "field")
svg += templateOrdinary(ordinary, ordinary.t);
else if (ordinary.divided === "counter")
svg += templateOrdinary(ordinary, tDiv!);
}
// In division part
svg += `<g clip-path="url(#divisionClip_${id})"><rect x="0" y="0" width="200" height="200" fill="${this.clr(
division!.t,
)}"/>`;
for (const ordinary of ordinariesRegular) {
if (ordinary.divided === "division")
svg += templateOrdinary(ordinary, ordinary.t);
else if (ordinary.divided === "counter")
svg += templateOrdinary(ordinary, coa.t1);
}
for (const charge of charges) {
if (charge.divided === "division")
svg += templateCharge(charge, charge.t);
else if (charge.divided === "counter")
svg += templateCharge(charge, coa.t1);
}
for (const ordinary of ordinariesAboveCharges) {
if (ordinary.divided === "division")
svg += templateOrdinary(ordinary, ordinary.t);
else if (ordinary.divided === "counter")
svg += templateOrdinary(ordinary, coa.t1);
}
svg += `</g>`;
return svg;
};
const templateAboveAll = () => {
let svg = "";
ordinariesRegular
.filter((o) => !o.divided)
.forEach((ordinary) => {
svg += templateOrdinary(ordinary, ordinary.t);
});
charges
.filter((o) => !o.divided || !division)
.forEach((charge) => {
svg += templateCharge(charge, charge.t);
});
ordinariesAboveCharges
.filter((o) => !o.divided)
.forEach((ordinary) => {
svg += templateOrdinary(ordinary, ordinary.t);
});
return svg;
};
const divisionGroup = division ? templateDivision() : "";
const overlay = `<path d="${shieldPath}" fill="url(#backlight_${id})" stroke="#333"/>`;
const svg = `<svg id="${id}" width="200" height="200" viewBox="${viewBox}">
<defs>${shieldClip}${divisionClip}${loadedCharges}${loadedPatterns}${blacklight}${style}</defs>
<g clip-path="url(#${shield}_${id})">${field}${divisionGroup}${templateAboveAll()}</g>
${overlay}</svg>`;
// insert coa svg to defs
document.getElementById("coas")!.insertAdjacentHTML("beforeend", svg);
return true;
}
// render coa if does not exist
async trigger(id: string, coa: Emblem) {
if (!coa) return console.warn(`Emblem ${id} is undefined`);
if (coa.custom) return console.warn("Cannot render custom emblem", coa);
if (!document.getElementById(id)) return this.draw(id, coa);
}
async add(type: string, i: number, coa: Emblem, x: number, y: number) {
const id = `${type}COA${i}`;
const g: HTMLElement = document.getElementById(
`${type}Emblems`,
) as HTMLElement;
if (emblems.selectAll("use").size()) {
const size = parseFloat(g.getAttribute("font-size") || "50");
const use = `<use data-i="${i}" x="${x - size / 2}" y="${y - size / 2}" width="1em" height="1em" href="#${id}"/>`;
g.insertAdjacentHTML("beforeend", use);
}
if (layerIsOn("toggleEmblems")) this.trigger(id, coa);
}
}
window.COArenderer = new EmblemRenderModule();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,46 @@
export const shields: {
types: Record<string, number>;
[key: string]: Record<string, number>;
} = {
types: {
basic: 10,
regional: 2,
historical: 1,
specific: 1,
banner: 1,
simple: 2,
fantasy: 1,
middleEarth: 0,
},
basic: { heater: 12, spanish: 6, french: 1 },
regional: { horsehead: 1, horsehead2: 1, polish: 1, hessen: 1, swiss: 1 },
historical: {
boeotian: 1,
roman: 2,
kite: 1,
oldFrench: 5,
renaissance: 2,
baroque: 2,
},
specific: { targe: 1, targe2: 0, pavise: 5, wedged: 10 },
banner: {
flag: 1,
pennon: 0,
guidon: 0,
banner: 0,
dovetail: 1,
gonfalon: 5,
pennant: 0,
},
simple: { round: 12, oval: 6, vesicaPiscis: 1, square: 1, diamond: 2, no: 0 },
fantasy: { fantasy1: 2, fantasy2: 2, fantasy3: 1, fantasy4: 1, fantasy5: 3 },
middleEarth: {
noldor: 1,
gondor: 1,
easterling: 1,
erebor: 1,
ironHills: 1,
urukHai: 1,
moriaOrc: 1,
},
};

View file

@ -0,0 +1,32 @@
export const shieldSize = {
horsehead: 0.9,
horsehead2: 0.9,
polish: 0.85,
swiss: 0.95,
boeotian: 0.75,
roman: 0.95,
kite: 0.65,
targe2: 0.9,
pavise: 0.9,
wedged: 0.95,
flag: 0.7,
pennon: 0.5,
guidon: 0.65,
banner: 0.8,
dovetail: 0.8,
pennant: 0.6,
oval: 0.95,
vesicaPiscis: 0.8,
diamond: 0.8,
no: 1.2,
fantasy1: 0.8,
fantasy2: 0.7,
fantasy3: 0.7,
fantasy5: 0.9,
noldor: 0.5,
gondor: 0.75,
easterling: 0.8,
erebor: 0.9,
urukHai: 0.8,
moriaOrc: 0.7,
};

View file

@ -0,0 +1,98 @@
export const templates: Record<string, string | ((line: string) => string)> = {
// straight divisions
perFess: `<rect x="0" y="100" width="200" height="100"/>`,
perPale: `<rect x="100" y="0" width="100" height="200"/>`,
perBend: `<polygon points="0,0 200,200 0,200"/>`,
perBendSinister: `<polygon points="200,0 0,200 200,200"/>`,
perChevron: `<polygon points="0,200 100,100 200,200"/>`,
perChevronReversed: `<polygon points="0,0 100,100 200,0"/>`,
perCross: `<rect x="100" y="0" width="100" height="100"/><rect x="0" y="100" width="100" height="100"/>`,
perPile: `<polygon points="0,0 15,0 100,200 185,0 200,0 200,200 0,200"/>`,
perSaltire: `<polygon points="0,0 0,200 200,0 200,200"/>`,
gyronny: `<polygon points="0,0 200,200 200,100 0,100"/><polygon points="200,0 0,200 100,200 100,0"/>`,
chevronny: `<path d="M0,80 100,-15 200,80 200,120 100,25 0,120z M0,160 100,65 200,160 200,200 100,105 0,200z M0,240 100,145 200,240 0,240z"/>`,
// lined divisions
perFessLined: (line: string) =>
`<path d="${line}"/><rect x="0" y="115" width="200" height="85" shape-rendering="crispedges"/>`,
perPaleLined: (line: string) =>
`<path d="${line}" transform="rotate(-90 100 100)"/><rect x="115" y="0" width="85" height="200" shape-rendering="crispedges"/>`,
perBendLined: (line: string) =>
`<path d="${line}" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perBendSinisterLined: (line: string) =>
`<path d="${line}" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)"/><rect x="0" y="115" width="200" height="85" transform="translate(-10 -10) rotate(-45 110 110) scale(1.1)" shape-rendering="crispedges"/>`,
perChevronLined: (line: string) =>
`<rect x="15" y="115" width="200" height="200" transform="translate(70 70) rotate(45 100 100)"/><path d="${line}" transform="translate(129 71) rotate(-45 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(71 71) rotate(45 100 100)"/>`,
perChevronReversedLined: (line: string) =>
`<rect x="15" y="115" width="200" height="200" transform="translate(-70 -70) rotate(225.001 100 100)"/><path d="${line}" transform="translate(-70.7 -70.7) rotate(225 100 100) scale(1 1)"/><path d="${line}" transform="translate(270.7 -70.7) rotate(-225 -100 100) scale(-1 1)"/>`,
perCrossLined: (line: string) =>
`<rect x="100" y="0" width="100" height="92.5"/><rect x="0" y="107.5" width="100" height="92.5"/><path d="${line}" transform="translate(0 50) scale(.5001)"/><path d="${line}" transform="translate(200 150) scale(-.5)"/>`,
perPileLined: (line: string) =>
`<path d="${line}" transform="translate(161.66 10) rotate(66.66 -100 100) scale(-1 1)"/><path d="${line}" transform="translate(38.33 10) rotate(-66.66 100 100)"/><polygon points="-2.15,0 84.15,200 115.85,200 202.15,0 200,200 0,200"/>`,
// straight ordinaries
fess: `<rect x="0" y="75" width="200" height="50"/>`,
pale: `<rect x="75" y="0" width="50" height="200"/>`,
bend: `<polygon points="35,0 200,165 200,200 165,200 0,35 0,0"/>`,
bendSinister: `<polygon points="0,165 165,0 200,0 200,35 35,200 0,200"/>`,
chief: `<rect width="200" height="75"/>`,
bar: `<rect x="0" y="87.5" width="200" height="25"/>`,
gemelle: `<rect x="0" y="76" width="200" height="16"/><rect x="0" y="108" width="200" height="16"/>`,
fessCotissed: `<rect x="0" y="67" width="200" height="8"/><rect x="0" y="83" width="200" height="34"/><rect x="0" y="125" width="200" height="8"/>`,
fessDoubleCotissed: `<rect x="0" y="60" width="200" height="7.5"/><rect x="0" y="72.5" width="200" height="7.5"/><rect x="0" y="85" width="200" height="30"/><rect x="0" y="120" width="200" height="7.5"/><rect x="0" y="132.5" width="200" height="7.5"/>`,
bendlet: `<polygon points="22,0 200,178 200,200 178,200 0,22 0,0"/>`,
bendletSinister: `<polygon points="0,178 178,0 200,0 200,22 22,200 0,200"/>`,
terrace: `<rect x="0" y="145" width="200" height="55"/>`,
cross: `<polygon points="85,0 85,85 0,85 0,115 85,115 85,200 115,200 115,115 200,115 200,85 115,85 115,0"/>`,
crossParted: `<path d="M 80 0 L 80 80 L 0 80 L 0 95 L 80 95 L 80 105 L 0 105 L 0 120 L 80 120 L 80 200 L 95 200 L 95 120 L 105 120 L 105 200 L 120 200 L 120 120 L 200 120 L 200 105 L 120 105 L 120 95 L 200 95 L 200 80 L 120 80 L 120 0 L 105 0 L 105 80 L 95 80 L 95 0 L 80 0 z M 95 95 L 105 95 L 105 105 L 95 105 L 95 95 z"/>`,
saltire: `<path d="M 0,21 79,100 0,179 0,200 21,200 100,121 179,200 200,200 200,179 121,100 200,21 200,0 179,0 100,79 21,0 0,0 Z"/>`,
saltireParted: `<path d="M 7 0 L 89 82 L 82 89 L 0 7 L 0 28 L 72 100 L 0 172 L 0 193 L 82 111 L 89 118 L 7 200 L 28 200 L 100 128 L 172 200 L 193 200 L 111 118 L 118 111 L 200 193 L 200 172 L 128 100 L 200 28 L 200 7 L 118 89 L 111 82 L 193 0 L 172 0 L 100 72 L 28 0 L 7 0 z M 100 93 L 107 100 L 100 107 L 93 100 L 100 93 z"/>`,
mount: `<path d="m0,250 a100,100,0,0,1,200,0"/>`,
point: `<path d="M0,200 Q80,180 100,135 Q120,180 200,200"/>`,
flaunches: `<path d="M0,0 q120,100 0,200 M200,0 q-120,100 0,200"/>`,
gore: `<path d="M20,0 Q30,75 100,100 Q80,150 100,200 L0,200 L0,0 Z"/>`,
pall: `<polygon points="0,0 30,0 100,70 170,0 200,0 200,30 122,109 122,200 78,200 78,109 0,30"/>`,
pallReversed: `<polygon points="0,200 0,170 78,91 78,0 122,0 122,91 200,170 200,200 170,200 100,130 30,200"/>`,
chevron: `<polygon points="0,125 100,60 200,125 200,165 100,100 0,165"/>`,
chevronReversed: `<polygon points="0,75 100,140 200,75 200,35 100,100 0,35"/>`,
gyron: `<polygon points="0,0 100,100 0,100"/>`,
quarter: `<rect width="50%" height="50%"/>`,
canton: `<rect width="37.5%" height="37.5%"/>`,
pile: `<polygon points="70,0 100,175 130,0"/>`,
pileInBend: `<polygon points="200,200 200,144 25,25 145,200"/>`,
pileInBendSinister: `<polygon points="0,200 0,144 175,25 55,200"/>`,
piles: `<polygon points="46,0 75,175 103,0"/><polygon points="95,0 125,175 154,0"/>`,
pilesInPoint: `<path d="M15,0 100,200 60,0Z M80,0 100,200 120,0Z M140,0 100,200 185,0Z"/>`,
label: `<path d="m 46,54.8 6.6,-15.6 95.1,0 5.9,15.5 -16.8,0.1 4.5,-11.8 L 104,43 l 4.3,11.9 -16.8,0 4.3,-11.8 -37.2,0 4.5,11.8 -16.9,0 z"/>`,
// lined ordinaries
fessLined: (line: string) =>
`<path d="${line}" transform="translate(0 -25)"/><path d="${line}" transform="translate(0 25) rotate(180 100 100)"/><rect x="0" y="88" width="200" height="24" stroke="none"/>`,
paleLined: (line: string) =>
`<path d="${line}" transform="rotate(-90 100 100) translate(0 -25)"/><path d="${line}" transform="rotate(90 100 100) translate(0 -25)"/><rect x="88" y="0" width="24" height="200" stroke="none"/>`,
bendLined: (line: string) =>
`<path d="${line}" transform="translate(8 -18) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-28 18) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendSinisterLined: (line: string) =>
`<path d="${line}" transform="translate(-28 -18) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(8 18) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="88" width="200" height="24" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
chiefLined: (line: string) =>
`<path d="${line}" transform="translate(0,-25) rotate(180.00001 100 100)"/><rect width="200" height="62" stroke="none"/>`,
barLined: (line: string) =>
`<path d="${line}" transform="translate(0,-12.5)"/><path d="${line}" transform="translate(0,12.5) rotate(180.00001 100 100)"/><rect x="0" y="94" width="200" height="12" stroke="none"/>`,
gemelleLined: (line: string) =>
`<path d="${line}" transform="translate(0,-22.5)"/><path d="${line}" transform="translate(0,22.5) rotate(180.00001 100 100)"/>`,
fessCotissedLined: (line: string) =>
`<path d="${line}" transform="translate(0 15) scale(1 .5)"/><path d="${line}" transform="translate(0 85) rotate(180 100 50) scale(1 .5)"/><rect x="0" y="80" width="200" height="40"/>`,
fessDoubleCotissedLined: (line: string) =>
`<rect x="0" y="85" width="200" height="30"/><rect x="0" y="72.5" width="200" height="7.5"/><rect x="0" y="120" width="200" height="7.5"/><path d="${line}" transform="translate(0 10) scale(1 .5)"/><path d="${line}" transform="translate(0 90) rotate(180 100 50) scale(1 .5)"/>`,
bendletLined: (line: string) =>
`<path d="${line}" transform="translate(2 -12) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-22 12) rotate(225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(45 110 100) scale(1.1 1)" stroke="none"/>`,
bendletSinisterLined: (line: string) =>
`<path d="${line}" transform="translate(-22 -12) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(2 12) rotate(-225 110 100) scale(1.1 1)"/><rect x="0" y="94" width="200" height="12" transform="translate(-10 0) rotate(-45 110 100) scale(1.1 1)" stroke="none"/>`,
terraceLined: (line: string) =>
`<path d="${line}" transform="translate(0,50)"/><rect x="0" y="164" width="200" height="36" stroke="none"/>`,
crossLined: (line: string) =>
`<path d="${line}" transform="translate(0,-14.5)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-14.5)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-14.5)"/>`,
crossPartedLined: (line: string) =>
`<path d="${line}" transform="translate(0,-20)"/><path d="${line}" transform="rotate(180 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-90 100 100) translate(0,-20)"/><path d="${line}" transform="rotate(-270 100 100) translate(0,-20)"/>`,
saltireLined: (line: string) =>
`<path d="${line}" transform="translate(0 -10) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 10) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-20 -10) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(0 10) rotate(-225 110 100) scale(1.1 1)"/>`,
saltirePartedLined: (line: string) =>
`<path d="${line}" transform="translate(3 -13) rotate(45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 13) rotate(225 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(-23 -13) rotate(-45 110 100) scale(1.1 1)"/><path d="${line}" transform="translate(3 13) rotate(-225 110 100) scale(1.1 1)"/>`,
};

View file

@ -0,0 +1,43 @@
import { P } from "../../utils";
export const createTinctures = () => ({
field: { metals: 3, colours: 4, stains: +P(0.03), patterns: 1 },
division: { metals: 5, colours: 8, stains: +P(0.03), patterns: 1 },
charge: { metals: 2, colours: 3, stains: +P(0.05), patterns: 0 },
metals: { argent: 3, or: 2 },
colours: { gules: 5, azure: 4, sable: 3, purpure: 3, vert: 2 },
stains: { murrey: 1, sanguine: 1, tenné: 1 },
patterns: {
semy: 8,
ermine: 6,
vair: 4,
counterVair: 1,
vairInPale: 1,
vairEnPointe: 2,
vairAncien: 2,
potent: 2,
counterPotent: 1,
potentInPale: 1,
potentEnPointe: 1,
chequy: 8,
lozengy: 5,
fusily: 2,
pally: 8,
barry: 10,
gemelles: 1,
bendy: 8,
bendySinister: 4,
palyBendy: 2,
barryBendy: 1,
pappellony: 2,
pappellony2: 3,
scaly: 1,
plumetty: 1,
masoned: 6,
fretty: 3,
grillage: 1,
chainy: 1,
maily: 2,
honeycombed: 1,
},
});

View file

@ -0,0 +1,187 @@
// Charges specific to culture or burg type (FMG-only config, not coming from Armoria)
export const typeMapping: Record<string, Record<string, number>> = {
Naval: {
anchor: 3,
drakkar: 1,
lymphad: 2,
caravel: 1,
shipWheel: 1,
armillarySphere: 1,
escallop: 1,
dolphin: 1,
plaice: 1,
},
Highland: {
tower: 1,
raven: 1,
wolfHeadErased: 1,
wolfPassant: 1,
goat: 1,
axe: 1,
},
River: {
garb: 1,
rake: 1,
raft: 1,
boat: 2,
drakkar: 2,
hook: 2,
pike: 2,
bullHeadCaboshed: 1,
apple: 1,
pear: 1,
plough: 1,
earOfWheat: 1,
salmon: 1,
cancer: 1,
bridge: 1,
bridge2: 2,
sickle: 1,
scythe: 1,
grapeBunch: 1,
wheatStalk: 1,
windmill: 1,
crocodile: 1,
},
Lake: {
hook: 3,
cancer: 2,
escallop: 1,
pike: 2,
heron: 1,
boat: 1,
boat2: 2,
salmon: 1,
sickle: 1,
windmill: 1,
swanErased: 1,
swan: 1,
frog: 1,
wasp: 1,
},
Nomadic: {
pot: 1,
buckle: 1,
wheel: 2,
sabre: 2,
sabresCrossed: 1,
bow: 2,
arrow: 1,
horseRampant: 1,
horseSalient: 1,
crescent: 1,
camel: 3,
scorpion: 1,
falcon: 1,
},
Hunting: {
bugleHorn: 2,
bugleHorn2: 1,
stagsAttires: 2,
attire: 2,
hatchet: 1,
bowWithArrow: 2,
arrowsSheaf: 1,
lanceHead: 1,
saw: 1,
deerHeadCaboshed: 1,
wolfStatant: 1,
oak: 1,
pineCone: 1,
pineTree: 1,
owl: 1,
falcon: 1,
peacock: 1,
boarHeadErased: 2,
horseHeadCouped: 1,
rabbitSejant: 1,
wolfRampant: 1,
wolfPassant: 1,
greyhoundCourant: 1,
greyhoundRampant: 1,
greyhoundSejant: 1,
mastiffStatant: 1,
talbotPassant: 1,
talbotSejant: 1,
stagPassant: 21,
},
// Selection based on type
City: {
key: 4,
bell: 3,
lute: 1,
tower: 1,
pillar: 1,
castle: 1,
castle2: 1,
portcullis: 1,
mallet: 1,
cannon: 1,
anvil: 1,
buckle: 1,
horseshoe: 1,
stirrup: 1,
lanceWithBanner: 1,
bookClosed: 1,
scissors: 1,
scissors2: 1,
shears: 1,
pincers: 1,
bridge: 2,
archer: 1,
shield: 1,
arbalest: 1,
arbalest2: 1,
bowWithThreeArrows: 1,
spear: 1,
lochaberAxe: 1,
armEmbowedHoldingSabre: 1,
grenade: 1,
maces: 1,
grapeBunch: 1,
cock: 1,
ramHeadErased: 1,
ratRampant: 1,
hourglass: 1,
scale: 1,
scrollClosed: 1,
},
Capital: {
crown: 2,
crown2: 2,
laurelWreath: 1,
orb: 1,
lute: 1,
lyre: 1,
banner: 1,
castle: 1,
castle2: 1,
palace: 1,
column: 1,
lionRampant: 1,
stagLodgedRegardant: 1,
drawingCompass: 1,
rapier: 1,
scaleImbalanced: 1,
scalesHanging: 1,
},
Сathedra: {
crossHummetty: 3,
mitre: 3,
chalice: 1,
orb: 1,
crosier: 2,
lamb: 1,
monk: 2,
angel: 3,
crossLatin: 2,
crossPatriarchal: 1,
crossOrthodox: 1,
crossCalvary: 1,
agnusDei: 3,
bookOpen: 1,
sceptre: 1,
bone: 1,
skull: 1,
},
};

View file

@ -13,4 +13,5 @@ import "./states-generator";
import "./zones-generator";
import "./religions-generator";
import "./provinces-generator";
import "./emblem";
import "./ice";

View file

@ -330,7 +330,7 @@ class ProvinceModule {
: P(0.3);
const kinship = dominion ? 0 : 0.4;
const type = Burgs.getType(center, burgs[burg]?.port);
const coa = COA.generate(s.coa, kinship, dominion, type);
const coa = COA.generate(s.coa, kinship, dominion ? 1 : 0, type);
coa.shield = COA.getShield(c, s.i);
provinces.push({

View file

@ -71,7 +71,7 @@ class StatesModule {
const name = Names.getState(basename, burg.culture!);
const type = pack.cultures[burg.culture!].type;
const coa = COA.generate(null, null, null, type);
coa.shield = COA.getShield(burg.culture, null);
coa.shield = COA.getShield(burg.culture!);
states.push({
i: burg.i,
name,