mirror of
https://github.com/Azgaar/Fantasy-Map-Generator.git
synced 2026-03-23 15:47:24 +01:00
Merge branch 'master' into feature/split-label-view-data
This commit is contained in:
commit
ba0ce8e40b
47 changed files with 8023 additions and 5800 deletions
|
|
@ -6152,6 +6152,7 @@
|
|||
<button onclick="saveGeoJsonRoutes()" data-tip="Download routes data in GeoJSON format">routes</button>
|
||||
<button onclick="saveGeoJsonRivers()" data-tip="Download rivers data in GeoJSON format">rivers</button>
|
||||
<button onclick="saveGeoJsonMarkers()" data-tip="Download markers data in GeoJSON format">markers</button>
|
||||
<button onclick="saveGeoJsonZones()" data-tip="Download zones data in GeoJSON format">zones</button>
|
||||
</div>
|
||||
<p>
|
||||
GeoJSON format is used in GIS tools such as QGIS. Check out
|
||||
|
|
@ -8494,16 +8495,12 @@
|
|||
|
||||
<script defer src="config/heightmap-templates.js"></script>
|
||||
<script defer src="config/precreated-heightmaps.js"></script>
|
||||
<script defer src="modules/ice.js?v=1.111.0"></script>
|
||||
<script defer src="modules/military-generator.js?v=1.107.0"></script>
|
||||
<script defer src="modules/markers-generator.js?v=1.107.0"></script>
|
||||
<script defer src="modules/coa-generator.js?v=1.99.00"></script>
|
||||
<script defer src="modules/military-generator.js?v=1.112.3"></script>
|
||||
<script defer src="modules/resample.js?v=1.112.1"></script>
|
||||
<script defer src="libs/alea.min.js?v1.105.0"></script>
|
||||
<script defer src="libs/polylabel.min.js?v1.105.0"></script>
|
||||
<script defer src="libs/lineclip.min.js?v1.105.0"></script>
|
||||
<script defer src="libs/simplify.js?v1.105.6"></script>
|
||||
<script defer src="modules/fonts.js?v=1.99.03"></script>
|
||||
<script defer src="modules/ui/layers.js?v=1.111.0"></script>
|
||||
<script defer src="modules/ui/measurers.js?v=1.99.00"></script>
|
||||
<script defer src="modules/ui/style-presets.js?v=1.100.00"></script>
|
||||
|
|
@ -8515,7 +8512,7 @@
|
|||
<script defer src="modules/ui/editors.js?v=1.112.1"></script>
|
||||
<script defer src="modules/ui/tools.js?v=1.111.0"></script>
|
||||
<script defer src="modules/ui/world-configurator.js?v=1.105.4"></script>
|
||||
<script defer src="modules/ui/heightmap-editor.js?v=1.105.2"></script>
|
||||
<script defer src="modules/ui/heightmap-editor.js?v=1.112.2"></script>
|
||||
<script defer src="modules/ui/provinces-editor.js?v=1.108.1"></script>
|
||||
<script defer src="modules/ui/biomes-editor.js?v=1.112.0"></script>
|
||||
<script defer src="modules/ui/namesbase-editor.js?v=1.105.11"></script>
|
||||
|
|
@ -8552,12 +8549,11 @@
|
|||
<script defer src="modules/ui/submap-tool.js?v=1.106.2"></script>
|
||||
<script defer src="modules/ui/transform-tool.js?v=1.106.2"></script>
|
||||
<script defer src="modules/ui/hotkeys.js?v=1.104.0"></script>
|
||||
<script defer src="modules/coa-renderer.js?v=1.99.00"></script>
|
||||
<script defer src="libs/rgbquant.min.js"></script>
|
||||
<script defer src="libs/jquery.ui.touch-punch.min.js"></script>
|
||||
<script defer src="modules/io/save.js?v=1.113.0"></script>
|
||||
<script defer src="modules/io/load.js?v=1.113.0"></script>
|
||||
<script defer src="modules/io/cloud.js?v=1.106.0"></script>
|
||||
<script defer src="modules/io/export.js?v=1.108.13"></script>
|
||||
<script defer src="modules/io/export.js?v=1.112.2"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -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
53
src/modules/emblem/box.ts
Normal 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",
|
||||
};
|
||||
883
src/modules/emblem/chargeData.ts
Normal file
883
src/modules/emblem/chargeData.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
477
src/modules/emblem/charges.ts
Normal file
477
src/modules/emblem/charges.ts
Normal 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,
|
||||
};
|
||||
12
src/modules/emblem/colors.ts
Normal file
12
src/modules/emblem/colors.ts
Normal 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",
|
||||
};
|
||||
46
src/modules/emblem/divisions.ts
Normal file
46
src/modules/emblem/divisions.ts
Normal 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,
|
||||
};
|
||||
591
src/modules/emblem/generator.ts
Normal file
591
src/modules/emblem/generator.ts
Normal 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();
|
||||
2
src/modules/emblem/index.ts
Normal file
2
src/modules/emblem/index.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import "./generator";
|
||||
import "./renderer";
|
||||
37
src/modules/emblem/lineWeights.ts
Normal file
37
src/modules/emblem/lineWeights.ts
Normal 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,
|
||||
};
|
||||
57
src/modules/emblem/lines.ts
Normal file
57
src/modules/emblem/lines.ts
Normal 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",
|
||||
};
|
||||
162
src/modules/emblem/ordinaries.ts
Normal file
162
src/modules/emblem/ordinaries.ts
Normal 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>;
|
||||
}
|
||||
>,
|
||||
};
|
||||
70
src/modules/emblem/paths.ts
Normal file
70
src/modules/emblem/paths.ts
Normal 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",
|
||||
};
|
||||
126
src/modules/emblem/patterns.ts
Normal file
126
src/modules/emblem/patterns.ts
Normal 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>`,
|
||||
};
|
||||
51
src/modules/emblem/positions.ts
Normal file
51
src/modules/emblem/positions.ts
Normal 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 },
|
||||
};
|
||||
363
src/modules/emblem/renderer.ts
Normal file
363
src/modules/emblem/renderer.ts
Normal 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();
|
||||
1347
src/modules/emblem/shieldPositions.ts
Normal file
1347
src/modules/emblem/shieldPositions.ts
Normal file
File diff suppressed because it is too large
Load diff
46
src/modules/emblem/shields.ts
Normal file
46
src/modules/emblem/shields.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
32
src/modules/emblem/size.ts
Normal file
32
src/modules/emblem/size.ts
Normal 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,
|
||||
};
|
||||
98
src/modules/emblem/templates.ts
Normal file
98
src/modules/emblem/templates.ts
Normal 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)"/>`,
|
||||
};
|
||||
43
src/modules/emblem/tinctures.ts
Normal file
43
src/modules/emblem/tinctures.ts
Normal 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,
|
||||
},
|
||||
});
|
||||
187
src/modules/emblem/typeMapping.ts
Normal file
187
src/modules/emblem/typeMapping.ts
Normal 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,
|
||||
},
|
||||
};
|
||||
426
src/modules/fonts.ts
Normal file
426
src/modules/fonts.ts
Normal file
|
|
@ -0,0 +1,426 @@
|
|||
import { byId } from "../utils";
|
||||
|
||||
declare global {
|
||||
var declareFont: (font: FontDefinition) => void;
|
||||
var getUsedFonts: (svg: SVGSVGElement) => FontDefinition[];
|
||||
var loadFontsAsDataURI: (
|
||||
fonts: FontDefinition[],
|
||||
) => Promise<FontDefinition[]>;
|
||||
var addGoogleFont: (family: string) => Promise<void>;
|
||||
var addLocalFont: (family: string) => void;
|
||||
var addWebFont: (family: string, src: string) => void;
|
||||
var fonts: FontDefinition[];
|
||||
}
|
||||
|
||||
type FontDefinition = {
|
||||
family: string;
|
||||
src?: string;
|
||||
unicodeRange?: string;
|
||||
variant?: string;
|
||||
};
|
||||
|
||||
window.fonts = [
|
||||
{ family: "Arial" },
|
||||
{ family: "Brush Script MT" },
|
||||
{ family: "Century Gothic" },
|
||||
{ family: "Comic Sans MS" },
|
||||
{ family: "Copperplate" },
|
||||
{ family: "Courier New" },
|
||||
{ family: "Garamond" },
|
||||
{ family: "Georgia" },
|
||||
{ family: "Herculanum" },
|
||||
{ family: "Impact" },
|
||||
{ family: "Papyrus" },
|
||||
{ family: "Party LET" },
|
||||
{ family: "Times New Roman" },
|
||||
{ family: "Verdana" },
|
||||
{
|
||||
family: "Almendra SC",
|
||||
src: "url(https://fonts.gstatic.com/s/almendrasc/v13/Iure6Yx284eebowr7hbyTaZOrLQ.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Amarante",
|
||||
src: "url(https://fonts.gstatic.com/s/amarante/v22/xMQXuF1KTa6EvGx9bp-wAXs.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Amatic SC",
|
||||
src: "url(https://fonts.gstatic.com/s/amaticsc/v11/TUZ3zwprpvBS1izr_vOMscGKfrUC.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Arima Madurai",
|
||||
src: "url(https://fonts.gstatic.com/s/arimamadurai/v14/t5tmIRoeKYORG0WNMgnC3seB3T7Prw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Architects Daughter",
|
||||
src: "url(https://fonts.gstatic.com/s/architectsdaughter/v8/RXTgOOQ9AAtaVOHxx0IUBM3t7GjCYufj5TXV5VnA2p8.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Bitter",
|
||||
src: "url(https://fonts.gstatic.com/s/bitter/v12/zfs6I-5mjWQ3nxqccMoL2A.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Caesar Dressing",
|
||||
src: "url(https://fonts.gstatic.com/s/caesardressing/v6/yYLx0hLa3vawqtwdswbotmK4vrRHdrz7.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Cinzel",
|
||||
src: "url(https://fonts.gstatic.com/s/cinzel/v7/zOdksD_UUTk1LJF9z4tURA.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Dancing Script",
|
||||
src: "url(https://fonts.gstatic.com/s/dancingscript/v9/KGBfwabt0ZRLA5W1ywjowUHdOuSHeh0r6jGTOGdAKHA.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Eagle Lake",
|
||||
src: "url(https://fonts.gstatic.com/s/eaglelake/v24/ptRMTiqbbuNJDOiKj9wG1On4KCFtpe4.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Faster One",
|
||||
src: "url(https://fonts.gstatic.com/s/fasterone/v17/H4ciBXCHmdfClFb-vWhf-LyYhw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Forum",
|
||||
src: "url(https://fonts.gstatic.com/s/forum/v16/6aey4Ky-Vb8Ew8IROpI.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Fredericka the Great",
|
||||
src: "url(https://fonts.gstatic.com/s/frederickathegreat/v6/9Bt33CxNwt7aOctW2xjbCstzwVKsIBVV--Sjxbc.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Gloria Hallelujah",
|
||||
src: "url(https://fonts.gstatic.com/s/gloriahallelujah/v9/CA1k7SlXcY5kvI81M_R28cNDay8z-hHR7F16xrcXsJw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Great Vibes",
|
||||
src: "url(https://fonts.gstatic.com/s/greatvibes/v5/6q1c0ofG6NKsEhAc2eh-3Y4P5ICox8Kq3LLUNMylGO4.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Henny Penny",
|
||||
src: "url(https://fonts.gstatic.com/s/hennypenny/v17/wXKvE3UZookzsxz_kjGSfPQtvXI.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "IM Fell English",
|
||||
src: "url(https://fonts.gstatic.com/s/imfellenglish/v7/xwIisCqGFi8pff-oa9uSVAkYLEKE0CJQa8tfZYc_plY.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Kelly Slab",
|
||||
src: "url(https://fonts.gstatic.com/s/kellyslab/v15/-W_7XJX0Rz3cxUnJC5t6fkQLfg.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Kranky",
|
||||
src: "url(https://fonts.gstatic.com/s/kranky/v24/hESw6XVgJzlPsFn8oR2F.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Lobster Two",
|
||||
src: "url(https://fonts.gstatic.com/s/lobstertwo/v18/BngMUXZGTXPUvIoyV6yN5-fN5qU.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Lugrasimo",
|
||||
src: "url(https://fonts.gstatic.com/s/lugrasimo/v4/qkBXXvoF_s_eT9c7Y7au455KsgbLMA.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Kaushan Script",
|
||||
src: "url(https://fonts.gstatic.com/s/kaushanscript/v6/qx1LSqts-NtiKcLw4N03IEd0sm1ffa_JvZxsF_BEwQk.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Macondo",
|
||||
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "MedievalSharp",
|
||||
src: "url(https://fonts.gstatic.com/s/medievalsharp/v9/EvOJzAlL3oU5AQl2mP5KdgptMqhwMg.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Metal Mania",
|
||||
src: "url(https://fonts.gstatic.com/s/metalmania/v22/RWmMoKWb4e8kqMfBUdPFJdXFiaQ.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Metamorphous",
|
||||
src: "url(https://fonts.gstatic.com/s/metamorphous/v7/Wnz8HA03aAXcC39ZEX5y133EOyqs.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Montez",
|
||||
src: "url(https://fonts.gstatic.com/s/montez/v8/aq8el3-0osHIcFK6bXAPkw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Nova Script",
|
||||
src: "url(https://fonts.gstatic.com/s/novascript/v10/7Au7p_IpkSWSTWaFWkumvlQKGFw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Orbitron",
|
||||
src: "url(https://fonts.gstatic.com/s/orbitron/v9/HmnHiRzvcnQr8CjBje6GQvesZW2xOQ-xsNqO47m55DA.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Oregano",
|
||||
src: "url(https://fonts.gstatic.com/s/oregano/v13/If2IXTPxciS3H4S2oZDVPg.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Pirata One",
|
||||
src: "url(https://fonts.gstatic.com/s/pirataone/v22/I_urMpiDvgLdLh0fAtofhi-Org.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Sail",
|
||||
src: "url(https://fonts.gstatic.com/s/sail/v16/DPEjYwiBxwYJJBPJAQ.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Satisfy",
|
||||
src: "url(https://fonts.gstatic.com/s/satisfy/v8/2OzALGYfHwQjkPYWELy-cw.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Shadows Into Light",
|
||||
src: "url(https://fonts.gstatic.com/s/shadowsintolight/v7/clhLqOv7MXn459PTh0gXYFK2TSYBz0eNcHnp4YqE4Ts.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
{
|
||||
family: "Tapestry",
|
||||
src: "url(https://fonts.gstatic.com/s/macondo/v21/RrQQboN9-iB1IXmOe2LE0Q.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Uncial Antiqua",
|
||||
src: "url(https://fonts.gstatic.com/s/uncialantiqua/v5/N0bM2S5WOex4OUbESzoESK-i-MfWQZQ.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Underdog",
|
||||
src: "url(https://fonts.gstatic.com/s/underdog/v6/CHygV-jCElj7diMroWSlWV8.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "UnifrakturMaguntia",
|
||||
src: "url(https://fonts.gstatic.com/s/unifrakturmaguntia/v16/WWXPlieVYwiGNomYU-ciRLRvEmK7oaVemGZM.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD",
|
||||
},
|
||||
{
|
||||
family: "Yellowtail",
|
||||
src: "url(https://fonts.gstatic.com/s/yellowtail/v8/GcIHC9QEwVkrA19LJU1qlPk_vArhqVIZ0nv9q090hN8.woff2)",
|
||||
unicodeRange:
|
||||
"U+0000-00FF, U+0131, U+0152-0153, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2212, U+2215",
|
||||
},
|
||||
];
|
||||
|
||||
window.declareFont = (font: FontDefinition) => {
|
||||
const { family, src, ...rest } = font;
|
||||
addFontOption(family);
|
||||
|
||||
if (!src) return;
|
||||
const fontFace = new FontFace(family, src, { ...rest, display: "block" });
|
||||
document.fonts.add(fontFace);
|
||||
};
|
||||
|
||||
declareDefaultFonts(); // execute once on load
|
||||
|
||||
function declareDefaultFonts() {
|
||||
fonts.forEach((font) => {
|
||||
declareFont(font);
|
||||
});
|
||||
}
|
||||
|
||||
function addFontOption(family: string) {
|
||||
const options = document.getElementById("styleSelectFont")!;
|
||||
const option = document.createElement("option");
|
||||
option.value = family;
|
||||
option.innerText = family;
|
||||
option.style.fontFamily = family;
|
||||
options.append(option);
|
||||
}
|
||||
|
||||
async function fetchGoogleFont(family: string) {
|
||||
const url = `https://fonts.googleapis.com/css2?family=${family.replace(/ /g, "+")}`;
|
||||
try {
|
||||
const resp = await fetch(url);
|
||||
const text = await resp.text();
|
||||
|
||||
const fontFaceRules = text.match(/font-face\s*{[^}]+}/g);
|
||||
const fonts = fontFaceRules!.map((fontFace) => {
|
||||
const srcURL = fontFace.match(/url\(['"]?(.+?)['"]?\)/)?.[1];
|
||||
const src = `url(${srcURL})`;
|
||||
const unicodeRange = fontFace.match(/unicode-range: (.*?);/)?.[1];
|
||||
const variant = fontFace.match(/font-style: (.*?);/)?.[1];
|
||||
|
||||
const font: FontDefinition = { family, src };
|
||||
if (unicodeRange) font.unicodeRange = unicodeRange;
|
||||
if (variant && variant !== "normal") font.variant = variant;
|
||||
return font;
|
||||
});
|
||||
|
||||
return fonts;
|
||||
} catch (err) {
|
||||
ERROR && console.error(err);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function readBlobAsDataURL(blob: Blob) {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => resolve(reader.result as string);
|
||||
reader.onerror = reject;
|
||||
reader.readAsDataURL(blob);
|
||||
});
|
||||
}
|
||||
|
||||
window.loadFontsAsDataURI = async (fonts: FontDefinition[]) => {
|
||||
const promises = fonts.map(async (font) => {
|
||||
const url = font.src?.match(/url\(['"]?(.+?)['"]?\)/)?.[1];
|
||||
if (!url) return font;
|
||||
const resp = await fetch(url);
|
||||
const blob = await resp.blob();
|
||||
const dataURL = await readBlobAsDataURL(blob);
|
||||
|
||||
return { ...font, src: `url('${dataURL}')` };
|
||||
});
|
||||
|
||||
return await Promise.all(promises);
|
||||
};
|
||||
|
||||
window.getUsedFonts = (svg: SVGSVGElement) => {
|
||||
const usedFontFamilies = new Set();
|
||||
|
||||
const labelGroups = svg.querySelectorAll("#labels g");
|
||||
for (const labelGroup of labelGroups) {
|
||||
const font = labelGroup.getAttribute("font-family");
|
||||
if (font) usedFontFamilies.add(font);
|
||||
}
|
||||
|
||||
const provinceFont = provs.attr("font-family");
|
||||
if (provinceFont) usedFontFamilies.add(provinceFont);
|
||||
|
||||
const legend = svg.querySelector("#legend");
|
||||
const legendFont = legend?.getAttribute("font-family");
|
||||
if (legendFont) usedFontFamilies.add(legendFont);
|
||||
|
||||
const usedFonts = fonts.filter((font) => usedFontFamilies.has(font.family));
|
||||
return usedFonts;
|
||||
};
|
||||
|
||||
window.addGoogleFont = async (family: string) => {
|
||||
const fontRanges = await fetchGoogleFont(family);
|
||||
if (!fontRanges)
|
||||
return tip("Cannot fetch Google font for this value", true, "error", 4000);
|
||||
tip(`Google font ${family} is loading...`, true, "warn", 4000);
|
||||
|
||||
const promises = fontRanges.map((range) => {
|
||||
const { src, unicodeRange } = range;
|
||||
const fontFace = new FontFace(family, src!, {
|
||||
unicodeRange,
|
||||
display: "block",
|
||||
});
|
||||
return fontFace.load();
|
||||
});
|
||||
|
||||
Promise.all(promises)
|
||||
.then((fontFaces) => {
|
||||
fontFaces.forEach((fontFace) => {
|
||||
document.fonts.add(fontFace);
|
||||
});
|
||||
fonts.push(...fontRanges);
|
||||
tip(`Google font ${family} is added to the list`, true, "success", 4000);
|
||||
addFontOption(family);
|
||||
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||
if (select) select.value = family;
|
||||
changeFont();
|
||||
})
|
||||
.catch((err) => {
|
||||
tip(`Failed to load Google font ${family}`, true, "error", 4000);
|
||||
ERROR && console.error(err);
|
||||
});
|
||||
};
|
||||
|
||||
window.addLocalFont = (family: string) => {
|
||||
fonts.push({ family });
|
||||
|
||||
const fontFace = new FontFace(family, `local(${family})`, {
|
||||
display: "block",
|
||||
});
|
||||
document.fonts.add(fontFace);
|
||||
tip(`Local font ${family} is added to the fonts list`, true, "success", 4000);
|
||||
addFontOption(family);
|
||||
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||
if (select) select.value = family;
|
||||
changeFont();
|
||||
};
|
||||
|
||||
window.addWebFont = (family: string, url: string) => {
|
||||
const src = `url('${url}')`;
|
||||
fonts.push({ family, src });
|
||||
|
||||
const fontFace = new FontFace(family, src, { display: "block" });
|
||||
document.fonts.add(fontFace);
|
||||
tip(`Font ${family} is added to the list`, true, "success", 4000);
|
||||
addFontOption(family);
|
||||
const select = byId<HTMLSelectElement>("styleSelectFont");
|
||||
if (select) select.value = family;
|
||||
changeFont();
|
||||
};
|
||||
175
src/modules/ice.ts
Normal file
175
src/modules/ice.ts
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
import Alea from "alea";
|
||||
import { min } from "d3";
|
||||
import {
|
||||
clipPoly,
|
||||
getGridPolygon,
|
||||
getIsolines,
|
||||
lerp,
|
||||
minmax,
|
||||
normalize,
|
||||
P,
|
||||
ra,
|
||||
rand,
|
||||
rn,
|
||||
} from "../utils";
|
||||
import type { Point } from "./voronoi";
|
||||
|
||||
declare global {
|
||||
var Ice: IceModule;
|
||||
}
|
||||
|
||||
class IceModule {
|
||||
// Find next available id for new ice element idealy filling gaps
|
||||
private getNextId() {
|
||||
if (pack.ice.length === 0) return 0;
|
||||
// find gaps in existing ids
|
||||
const existingIds = pack.ice.map((e) => e.i).sort((a, b) => a - b);
|
||||
for (let id = 0; id < existingIds[existingIds.length - 1]; id++) {
|
||||
if (!existingIds.includes(id)) return id;
|
||||
}
|
||||
return existingIds[existingIds.length - 1] + 1;
|
||||
}
|
||||
|
||||
// Clear all ice
|
||||
private clear() {
|
||||
pack.ice = [];
|
||||
}
|
||||
|
||||
// Generate glaciers and icebergs based on temperature and height
|
||||
public generate() {
|
||||
this.clear();
|
||||
const { cells, features } = grid;
|
||||
const { temp, h } = cells;
|
||||
Math.random = Alea(seed);
|
||||
|
||||
const ICEBERG_MAX_TEMP = 0;
|
||||
const GLACIER_MAX_TEMP = -8;
|
||||
const minMaxTemp = min<number>(temp)!;
|
||||
|
||||
// Generate glaciers on cold land
|
||||
{
|
||||
const type = "iceShield";
|
||||
const getType = (cellId: number) =>
|
||||
h[cellId] >= 20 && temp[cellId] <= GLACIER_MAX_TEMP ? type : null;
|
||||
const isolines = getIsolines(grid, getType, { polygons: true });
|
||||
|
||||
if (isolines[type]?.polygons) {
|
||||
isolines[type].polygons.forEach((points: Point[]) => {
|
||||
const clipped = clipPoly(points, graphWidth, graphHeight);
|
||||
pack.ice.push({
|
||||
i: this.getNextId(),
|
||||
points: clipped,
|
||||
type: "glacier",
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Generate icebergs on cold water
|
||||
for (const cellId of grid.cells.i) {
|
||||
const t = temp[cellId];
|
||||
if (h[cellId] >= 20) continue; // no icebergs on land
|
||||
if (t > ICEBERG_MAX_TEMP) continue; // too warm: no icebergs
|
||||
if (features[cells.f[cellId]].type === "lake") continue; // no icebergs on lakes
|
||||
if (P(0.8)) continue; // skip most of eligible cells
|
||||
|
||||
const randomFactor = 0.8 + rand() * 0.4; // random size factor
|
||||
let baseSize = (1 - normalize(t, minMaxTemp, 1)) * 0.8; // size: 0 = zero, 1 = full
|
||||
if (cells.t[cellId] === -1) baseSize /= 1.3; // coastline: smaller icebergs
|
||||
const size = minmax(rn(baseSize * randomFactor, 2), 0.1, 1);
|
||||
|
||||
const [cx, cy] = grid.points[cellId];
|
||||
const points = getGridPolygon(cellId, grid).map(([x, y]: Point) => [
|
||||
rn(lerp(cx, x, size), 2),
|
||||
rn(lerp(cy, y, size), 2),
|
||||
]);
|
||||
|
||||
pack.ice.push({
|
||||
i: this.getNextId(),
|
||||
points,
|
||||
type: "iceberg",
|
||||
cellId,
|
||||
size,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addIceberg(cellId: number, size: number) {
|
||||
const [cx, cy] = grid.points[cellId];
|
||||
const points = getGridPolygon(cellId, grid).map(([x, y]: Point) => [
|
||||
rn(lerp(cx, x, size), 2),
|
||||
rn(lerp(cy, y, size), 2),
|
||||
]);
|
||||
const id = this.getNextId();
|
||||
pack.ice.push({
|
||||
i: id,
|
||||
points,
|
||||
type: "iceberg",
|
||||
cellId,
|
||||
size,
|
||||
});
|
||||
redrawIceberg(id);
|
||||
}
|
||||
|
||||
removeIce(id: number) {
|
||||
const index = pack.ice.findIndex((element) => element.i === id);
|
||||
if (index !== -1) {
|
||||
const type = pack.ice.find((element) => element.i === id).type;
|
||||
pack.ice.splice(index, 1);
|
||||
if (type === "glacier") {
|
||||
redrawGlacier(id);
|
||||
} else {
|
||||
redrawIceberg(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
randomizeIcebergShape(id: number) {
|
||||
const iceberg = pack.ice.find((element) => element.i === id);
|
||||
if (!iceberg) return;
|
||||
|
||||
const cellId = iceberg.cellId;
|
||||
const size = iceberg.size;
|
||||
const [cx, cy] = grid.points[cellId];
|
||||
|
||||
// Get a different random cell for the polygon template
|
||||
const i = ra(grid.cells.i);
|
||||
const cn = grid.points[i];
|
||||
const poly = getGridPolygon(i, grid).map((p: Point) => [
|
||||
p[0] - cn[0],
|
||||
p[1] - cn[1],
|
||||
]);
|
||||
const points = poly.map((p: Point) => [
|
||||
rn(cx + p[0] * size, 2),
|
||||
rn(cy + p[1] * size, 2),
|
||||
]);
|
||||
|
||||
iceberg.points = points;
|
||||
}
|
||||
|
||||
changeIcebergSize(id: number, newSize: number) {
|
||||
const iceberg = pack.ice.find((element) => element.i === id);
|
||||
if (!iceberg) return;
|
||||
|
||||
const cellId = iceberg.cellId;
|
||||
const [cx, cy] = grid.points[cellId];
|
||||
const oldSize = iceberg.size;
|
||||
|
||||
const flat = iceberg.points.flat();
|
||||
const pairs = [];
|
||||
while (flat.length) pairs.push(flat.splice(0, 2));
|
||||
const poly = pairs.map((p) => [
|
||||
(p[0] - cx) / oldSize,
|
||||
(p[1] - cy) / oldSize,
|
||||
]);
|
||||
const points = poly.map((p) => [
|
||||
rn(cx + p[0] * newSize, 2),
|
||||
rn(cy + p[1] * newSize, 2),
|
||||
]);
|
||||
|
||||
iceberg.points = points;
|
||||
iceberg.size = newSize;
|
||||
}
|
||||
}
|
||||
|
||||
window.Ice = new IceModule();
|
||||
|
|
@ -14,3 +14,7 @@ import "./zones-generator";
|
|||
import "./religions-generator";
|
||||
import "./labels";
|
||||
import "./provinces-generator";
|
||||
import "./emblem";
|
||||
import "./ice";
|
||||
import "./markers-generator";
|
||||
import "./fonts";
|
||||
|
|
|
|||
1802
src/modules/markers-generator.ts
Normal file
1802
src/modules/markers-generator.ts
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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({
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ declare global {
|
|||
var mapName: HTMLInputElement;
|
||||
var religionsNumber: HTMLInputElement;
|
||||
var distanceUnitInput: HTMLInputElement;
|
||||
var heightUnit: HTMLSelectElement;
|
||||
|
||||
var rivers: Selection<SVGElement, unknown, null, undefined>;
|
||||
var oceanLayers: Selection<SVGGElement, unknown, null, undefined>;
|
||||
|
|
@ -46,6 +47,7 @@ declare global {
|
|||
var defs: Selection<SVGDefsElement, unknown, null, undefined>;
|
||||
var coastline: Selection<SVGGElement, unknown, null, undefined>;
|
||||
var lakes: Selection<SVGGElement, unknown, null, undefined>;
|
||||
var provs: Selection<SVGGElement, unknown, null, undefined>;
|
||||
var getColorScheme: (scheme: string | null) => (t: number) => string;
|
||||
var getColor: (height: number, scheme: (t: number) => string) => string;
|
||||
var svgWidth: number;
|
||||
|
|
@ -62,7 +64,6 @@ declare global {
|
|||
icons: string[][];
|
||||
cost: number[];
|
||||
};
|
||||
var COA: any;
|
||||
var notes: any[];
|
||||
var style: {
|
||||
burgLabels: { [key: string]: { [key: string]: string } };
|
||||
|
|
@ -74,16 +75,18 @@ declare global {
|
|||
var layerIsOn: (layerId: string) => boolean;
|
||||
var drawRoute: (route: any) => void;
|
||||
var invokeActiveZooming: () => void;
|
||||
var COArenderer: { trigger: (id: string, coa: any) => void };
|
||||
var FlatQueue: any;
|
||||
|
||||
var tip: (
|
||||
message: string,
|
||||
autoHide?: boolean,
|
||||
type?: "info" | "warning" | "error",
|
||||
type?: "info" | "warn" | "error" | "success",
|
||||
timeout?: number,
|
||||
) => void;
|
||||
var locked: (settingId: string) => boolean;
|
||||
var unlock: (settingId: string) => void;
|
||||
var $: (selector: any) => any;
|
||||
var scale: number;
|
||||
var changeFont: () => void;
|
||||
var getFriendlyHeight: (coords: [number, number]) => string;
|
||||
}
|
||||
|
|
|
|||
379
src/utils/probabilityUtils.test.ts
Normal file
379
src/utils/probabilityUtils.test.ts
Normal file
|
|
@ -0,0 +1,379 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
biased,
|
||||
each,
|
||||
gauss,
|
||||
generateSeed,
|
||||
getNumberInRange,
|
||||
P,
|
||||
Pint,
|
||||
ra,
|
||||
rand,
|
||||
rw,
|
||||
} from "./probabilityUtils";
|
||||
|
||||
describe("rand", () => {
|
||||
describe("when called with no arguments", () => {
|
||||
it("should return a float between 0 and 1", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = rand();
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThan(1);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("when called with one argument (max)", () => {
|
||||
it("should return an integer between 0 and max (inclusive)", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = rand(10);
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThanOrEqual(10);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should return 0 when max is 0", () => {
|
||||
expect(rand(0)).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when called with two arguments (min, max)", () => {
|
||||
it("should return an integer between min and max (inclusive)", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = rand(5, 15);
|
||||
expect(result).toBeGreaterThanOrEqual(5);
|
||||
expect(result).toBeLessThanOrEqual(15);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should handle negative ranges", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = rand(-10, -5);
|
||||
expect(result).toBeGreaterThanOrEqual(-10);
|
||||
expect(result).toBeLessThanOrEqual(-5);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should return the same value when min equals max", () => {
|
||||
expect(rand(7, 7)).toBe(7);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("P", () => {
|
||||
it("should always return true when probability is 1", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
expect(P(1)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should always return true when probability is greater than 1", () => {
|
||||
expect(P(1.5)).toBe(true);
|
||||
expect(P(100)).toBe(true);
|
||||
});
|
||||
|
||||
it("should always return false when probability is 0", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
expect(P(0)).toBe(false);
|
||||
}
|
||||
});
|
||||
|
||||
it("should always return false when probability is negative", () => {
|
||||
expect(P(-0.5)).toBe(false);
|
||||
expect(P(-1)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return boolean for probabilities between 0 and 1", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = P(0.5);
|
||||
expect(typeof result).toBe("boolean");
|
||||
}
|
||||
});
|
||||
|
||||
it("should approximately match the given probability over many trials", () => {
|
||||
const trials = 10000;
|
||||
let trueCount = 0;
|
||||
const probability = 0.3;
|
||||
|
||||
for (let i = 0; i < trials; i++) {
|
||||
if (P(probability)) trueCount++;
|
||||
}
|
||||
|
||||
const observedProbability = trueCount / trials;
|
||||
// Allow 5% tolerance
|
||||
expect(observedProbability).toBeGreaterThan(probability - 0.05);
|
||||
expect(observedProbability).toBeLessThan(probability + 0.05);
|
||||
});
|
||||
});
|
||||
|
||||
describe("each", () => {
|
||||
it("should return true every n times starting from 0", () => {
|
||||
const every3 = each(3);
|
||||
expect(every3(0)).toBe(true);
|
||||
expect(every3(1)).toBe(false);
|
||||
expect(every3(2)).toBe(false);
|
||||
expect(every3(3)).toBe(true);
|
||||
expect(every3(4)).toBe(false);
|
||||
expect(every3(5)).toBe(false);
|
||||
expect(every3(6)).toBe(true);
|
||||
});
|
||||
|
||||
it("should work with n=1 (always true)", () => {
|
||||
const every1 = each(1);
|
||||
expect(every1(0)).toBe(true);
|
||||
expect(every1(1)).toBe(true);
|
||||
expect(every1(2)).toBe(true);
|
||||
});
|
||||
|
||||
it("should work with larger intervals", () => {
|
||||
const every10 = each(10);
|
||||
expect(every10(0)).toBe(true);
|
||||
expect(every10(5)).toBe(false);
|
||||
expect(every10(10)).toBe(true);
|
||||
expect(every10(20)).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("gauss", () => {
|
||||
it("should return a number", () => {
|
||||
const result = gauss();
|
||||
expect(typeof result).toBe("number");
|
||||
});
|
||||
|
||||
it("should respect min and max bounds", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = gauss(50, 20, 10, 90, 0);
|
||||
expect(result).toBeGreaterThanOrEqual(10);
|
||||
expect(result).toBeLessThanOrEqual(90);
|
||||
}
|
||||
});
|
||||
|
||||
it("should use default values when no arguments provided", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = gauss();
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThanOrEqual(300);
|
||||
}
|
||||
});
|
||||
|
||||
it("should round to specified decimal places", () => {
|
||||
const result = gauss(100, 30, 0, 300, 2);
|
||||
const decimalPlaces = (result.toString().split(".")[1] || "").length;
|
||||
expect(decimalPlaces).toBeLessThanOrEqual(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Pint", () => {
|
||||
it("should return the integer part for whole numbers", () => {
|
||||
expect(Pint(5)).toBe(5);
|
||||
expect(Pint(0)).toBe(0);
|
||||
expect(Pint(10)).toBe(10);
|
||||
});
|
||||
|
||||
it("should return at least the integer part for floats", () => {
|
||||
// The function returns floor + (0 or 1 based on probability)
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = Pint(5.5);
|
||||
expect(result).toBeGreaterThanOrEqual(5);
|
||||
expect(result).toBeLessThanOrEqual(6);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should always return floor for very small decimals", () => {
|
||||
// With very small decimal, almost always returns floor
|
||||
let sumResults = 0;
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
sumResults += Pint(5.001);
|
||||
}
|
||||
// Most should be 5, very few 6
|
||||
expect(sumResults / 1000).toBeCloseTo(5, 0);
|
||||
});
|
||||
|
||||
it("should return floor+1 more often for larger decimals", () => {
|
||||
// With 0.9 decimal, should return floor+1 about 90% of the time
|
||||
let count6 = 0;
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
if (Pint(5.9) === 6) count6++;
|
||||
}
|
||||
expect(count6 / 1000).toBeGreaterThan(0.8);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ra", () => {
|
||||
it("should return an element from the array", () => {
|
||||
const array = [1, 2, 3, 4, 5];
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = ra(array);
|
||||
expect(array).toContain(result);
|
||||
}
|
||||
});
|
||||
|
||||
it("should return the only element for single-element array", () => {
|
||||
expect(ra([42])).toBe(42);
|
||||
});
|
||||
|
||||
it("should work with arrays of different types", () => {
|
||||
const stringArray = ["a", "b", "c"];
|
||||
const result = ra(stringArray);
|
||||
expect(stringArray).toContain(result);
|
||||
|
||||
const objectArray = [{ id: 1 }, { id: 2 }];
|
||||
const objResult = ra(objectArray);
|
||||
expect(objectArray).toContain(objResult);
|
||||
});
|
||||
|
||||
it("should return undefined for empty array", () => {
|
||||
expect(ra([])).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("rw", () => {
|
||||
it("should return a key from the object", () => {
|
||||
const obj = { a: 1, b: 2, c: 3 };
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = rw(obj);
|
||||
expect(["a", "b", "c"]).toContain(result);
|
||||
}
|
||||
});
|
||||
|
||||
it("should respect weights (higher weight = more likely)", () => {
|
||||
const obj = { rare: 1, common: 99 };
|
||||
let commonCount = 0;
|
||||
const trials = 1000;
|
||||
|
||||
for (let i = 0; i < trials; i++) {
|
||||
if (rw(obj) === "common") commonCount++;
|
||||
}
|
||||
|
||||
// 'common' should appear much more frequently
|
||||
expect(commonCount / trials).toBeGreaterThan(0.9);
|
||||
});
|
||||
|
||||
it("should work with single key", () => {
|
||||
expect(rw({ only: 5 })).toBe("only");
|
||||
});
|
||||
|
||||
it("should handle keys with weight 0 (never selected)", () => {
|
||||
const obj = { never: 0, always: 10 };
|
||||
for (let i = 0; i < 100; i++) {
|
||||
expect(rw(obj)).toBe("always");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("biased", () => {
|
||||
it("should return a number between min and max", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = biased(0, 100, 2);
|
||||
expect(result).toBeGreaterThanOrEqual(0);
|
||||
expect(result).toBeLessThanOrEqual(100);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should be biased towards min with higher exponent", () => {
|
||||
const trials = 1000;
|
||||
let sumLowBias = 0;
|
||||
let sumHighBias = 0;
|
||||
|
||||
for (let i = 0; i < trials; i++) {
|
||||
sumLowBias += biased(0, 100, 1); // No bias (uniform)
|
||||
sumHighBias += biased(0, 100, 3); // Strong bias towards min
|
||||
}
|
||||
|
||||
const avgLowBias = sumLowBias / trials;
|
||||
const avgHighBias = sumHighBias / trials;
|
||||
|
||||
// Higher exponent should result in lower average
|
||||
expect(avgHighBias).toBeLessThan(avgLowBias);
|
||||
});
|
||||
|
||||
it("should return min or max at boundaries", () => {
|
||||
expect(biased(5, 5, 2)).toBe(5);
|
||||
});
|
||||
|
||||
it("should work with negative ranges", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = biased(-50, -10, 2);
|
||||
expect(result).toBeGreaterThanOrEqual(-50);
|
||||
expect(result).toBeLessThanOrEqual(-10);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("getNumberInRange", () => {
|
||||
it("should parse simple integers", () => {
|
||||
expect(getNumberInRange("5")).toBe(5);
|
||||
expect(getNumberInRange("0")).toBe(0);
|
||||
expect(getNumberInRange("100")).toBe(100);
|
||||
});
|
||||
|
||||
it("should parse range strings and return value within range", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = getNumberInRange("3-7");
|
||||
expect(result).toBeGreaterThanOrEqual(3);
|
||||
expect(result).toBeLessThanOrEqual(7);
|
||||
expect(Number.isInteger(result)).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it("should handle negative start in range", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = getNumberInRange("-5-10");
|
||||
expect(result).toBeGreaterThanOrEqual(-5);
|
||||
expect(result).toBeLessThanOrEqual(10);
|
||||
}
|
||||
});
|
||||
|
||||
it("should return 0 for non-string input", () => {
|
||||
expect(getNumberInRange(5 as unknown as string)).toBe(0);
|
||||
expect(getNumberInRange(null as unknown as string)).toBe(0);
|
||||
});
|
||||
|
||||
it("should handle float strings with probability-based rounding", () => {
|
||||
// "2.5" should return 2 or 3 based on probability
|
||||
const results = new Set<number>();
|
||||
for (let i = 0; i < 100; i++) {
|
||||
results.add(getNumberInRange("2.5"));
|
||||
}
|
||||
// Should see both 2 and 3
|
||||
expect(results.has(2) || results.has(3)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return 0 for invalid format without range separator", () => {
|
||||
expect(getNumberInRange("abc")).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("generateSeed", () => {
|
||||
it("should return a string", () => {
|
||||
const result = generateSeed();
|
||||
expect(typeof result).toBe("string");
|
||||
});
|
||||
|
||||
it("should return a numeric string", () => {
|
||||
const result = generateSeed();
|
||||
expect(Number.isNaN(Number(result))).toBe(false);
|
||||
});
|
||||
|
||||
it("should generate seeds less than 1 billion", () => {
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const result = generateSeed();
|
||||
expect(Number(result)).toBeLessThan(1e9);
|
||||
expect(Number(result)).toBeGreaterThanOrEqual(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("should generate different seeds on multiple calls (with high probability)", () => {
|
||||
const seeds = new Set<string>();
|
||||
for (let i = 0; i < 100; i++) {
|
||||
seeds.add(generateSeed());
|
||||
}
|
||||
// Should have many unique seeds (allow for some rare collisions)
|
||||
expect(seeds.size).toBeGreaterThan(90);
|
||||
});
|
||||
});
|
||||
|
|
@ -2,18 +2,18 @@ import { randomNormal } from "d3";
|
|||
import { minmax, rn } from "./numberUtils";
|
||||
|
||||
/**
|
||||
* Creates a random number between min and max (inclusive).
|
||||
* Creates a random number between min and max (inclusive). If only one argument is provided, it will be considered as max and min will be 0. If no arguments are provided, it returns a random float between 0 and 1.
|
||||
* @param {number} min - minimum value
|
||||
* @param {number} max - maximum value
|
||||
* @return {number} random integer between min and max
|
||||
*/
|
||||
export const rand = (min: number, max?: number): number => {
|
||||
export const rand = (min?: number, max?: number): number => {
|
||||
if (min === undefined && max === undefined) return Math.random();
|
||||
if (max === undefined) {
|
||||
max = min;
|
||||
min = 0;
|
||||
}
|
||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
return Math.floor(Math.random() * (max! - min! + 1)) + min!;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
export const byId = document.getElementById.bind(document);
|
||||
export const byId = <T extends HTMLElement>(id: string): T | undefined =>
|
||||
document.getElementById(id) as T;
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue