Moved some files around and made cleanup better

This commit is contained in:
2026-09-14 19:01:08 -07:00
parent 50b234104a
commit 97ed7f05c8
866 changed files with 404 additions and 1612 deletions

View File

@@ -0,0 +1,78 @@
# Flourish spacing — 20px preview
Separate shared-layer spacing experiment for Uncommon, Rare and Extraordinary. Canonical layers, accepted cards, working revisions and harness fixtures are unchanged.
- [Header comparison](output/headers-comparison.png)
- [Footer comparison](output/footers-comparison.png)
- [Full cards before/after](output/cards-before-after.png)
- [Measurements and changes](output/validation.json)
Each central flourish has a 20px master-canvas gap from its visible ink edge to the inward-facing ink edge of the innermost rule. The header and lower footer use the bottom rule; the upper footer uses the top rule. This equals 10px at standard resolution and 5px at low resolution. Inkscape visual bounds include ornament stroke thickness. Panel dimensions, textures, inset rules and side ornaments stay fixed.
The preview uses Borderless cards so the backing is visible in isolation. The corresponding Normal panels use the same vertical inset/ornament geometry. The same artwork and lettering are retained, except the Rare attribution moves upward 4 master pixels and Extraordinary attribution 3 master pixels to maintain at least 20px of reference-to-flourish clearance. Uncommon lettering is unchanged.
All nine measured flourish-to-rule gaps are 20px within Inkscape query precision. Every “Current” composition matches its existing high-resolution production Borderless card pixel-for-pixel. Preview PNGs and editable SVGs are under `output/[tier]/`. No finish maps were rebuilt for this static spacing comparison.
Run from the Sanctification repository:
```sh
python3 spikes/flourish-spacing-20px-proof/build.py
```
Visual acceptance of this spacing rule is pending. This experiment does not change shared library versions or general typography guidelines.
## Full typography comparison
Fresh typesetting against the 20px preview backings is under `output-retyped/`:
- [Headers: current / spacing only / spacing with retyped text](output-retyped/headers-comparison.png)
- [Footers: current / spacing only / spacing with retyped text](output-retyped/footers-comparison.png)
- [All three retyped cards side by side](output-retyped/cards-retyped.png)
- [Full cards, current versus retyped](output-retyped/cards-before-after.png)
- [Fresh glyph bounds, font hashes and spacing](output-retyped/validation.json)
All text is rebuilt from card content. One-line titles use shared P052 Bold at 112px; the approved two-line Uncommon title uses 100px. Verse and attribution use shared P052 Medium at 80px and 57px. Wording, translation attribution, palette and art are unchanged.
The whole title block is centered in the available area above the header flourish, with 20px minimum clearance from both the upper inner rule and flourish. Actual reference ink ends 20px above the lower flourish. The verse block is centered in the remaining footer band, reserving at least 40px below the upper flourish and 64px before the attribution. These are provisional comparison layout rules, not changes to canonical typography.
Font hashes, exact face resolution, glyph coverage, minimum sizes, unclipped object/raster bounds, opaque backing beneath glyphs and text clearance are checked. This remains a static typography/backing proof; finish masks and runtime fixtures are not regenerated.
```sh
python3 spikes/flourish-spacing-20px-proof/build.py --retype-text
```
## Verse centering by visible ink
[Footer comparison](output-centered/footers-comparison.png) and [full-card lineup](output-centered/cards-centered.png) compare the previous retyped layout against direct visible-ink centering.
The upper boundary is the bottom visible ink edge of the upper footer flourish. The lower boundary is the top visible ink edge of the reference. Center the union of all verse lines' unclipped raster ink bounds between those boundaries. No 40/64px or 48px allowances participate in placement. Minimum clearance is checked separately after centering. Raster rounding permits at most one master pixel of difference between the resulting upper/lower gaps.
Only verse baselines move. The shared fonts, sizes, line spacing, wording, header, reference and 20px backing preview are unchanged. The prior comparisons and all production assets remain intact.
```sh
python3 spikes/flourish-spacing-20px-proof/center-verses.py
```
[Centering measurements](output-centered/validation.json) record the actual visible bounds, shifts and resulting gaps for each card.
## Fixed reference baseline trial
- [Previous versus fixed-baseline footers](output-baseline/footers-comparison.png)
- [All three full cards](output-baseline/cards-baseline.png)
- [Diagnostic guides](output-baseline/footer-guides.png)
- [Measurements and stress references](output-baseline/validation.json)
This separate trial anchors every reference with the same font-derived line box at 57 master pixels. The pinned Medium font has a 726-unit hhea ascender, a 274-unit nominal descender and a 288-unit global outline descender on a 1000-unit em. Round the ascender upward to 42px and the larger descender allowance upward to 17px. The expanded Medium outlines need that extra allowance for letters such as lowercase p. Font line gap is not used here.
`reference baseline = lower flourish visible ink top − 20px − 17px`
Thus the fixed line-box bottom is always 20px above the flourish. Actual ink clearance can be larger for text without descenders, which is intentional: translation letters no longer change the baseline. Center the combined visible verse ink between the upper flourish's visible bottom and the fixed reference line-box top. No prescribed 48px margin participates in centering.
The guide sheet uses purple for the reference line box, red for its baseline, teal for actual glyph bounds, and green for flourish boundaries. Independent unclipped reference renders exercise NKJV, ESV, KJV and Philippians; the font metrics remain identical for every wording. Output sizes are 2000/1000/500 pixels wide, with geometric spacing scaled proportionally. All previously generated comparison inputs and canonical sources are checked for byte preservation.
```sh
python3 spikes/flourish-spacing-20px-proof/fixed-reference-baseline.py
```
The fixed-baseline comparison was visually approved on September 14, 2026: “I think this looks really good.” The spacing rule is now recorded in [Art Direction](../../docs/art-direction.md#flourish-and-footer-text-spacing), with verification in the [pipeline](../../docs/card-layer-pipeline.md#deterministic-text). Production layouts, versioned shared layers and harness fixtures have not been migrated by this experiment. No finish masks were rebuilt.

View File

@@ -0,0 +1,159 @@
#!/usr/bin/env python3
"""Preview a shared 20px visible-ink gap for central backing flourishes."""
from pathlib import Path
import argparse,copy,json,os,re,subprocess,sys
import xml.etree.ElementTree as ET
import numpy as np
from PIL import Image,ImageDraw,ImageFont
ROOT=Path(__file__).resolve().parent
REPO=next(p for p in ROOT.parents if (p/'docs/card-layer-pipeline.md').is_file())
sys.path.insert(0,str(REPO/'artifacts/layers'))
from library import load_tier,digest
parser=argparse.ArgumentParser(description=__doc__);parser.add_argument('--retype-text',action='store_true');args=parser.parse_args()
OUT=ROOT/('output-retyped' if args.retype_text else 'output');OUT.mkdir(exist_ok=True)
NS='{http://www.w3.org/2000/svg}'
ET.register_namespace('','http://www.w3.org/2000/svg');ET.register_namespace('xlink','http://www.w3.org/1999/xlink')
fonts=REPO/'fonts';config=OUT/'fonts.conf';config.write_text(f'<fontconfig><dir>{fonts}</dir><cachedir>{OUT/"font-cache"}</cachedir></fontconfig>')
ENV=dict(os.environ,FONTCONFIG_FILE=str(config))
def ink(*args):return subprocess.check_output(['inkscape',*map(str,args)],env=ENV,text=True,stderr=subprocess.PIPE).strip()
def query(path):
result={}
for row in ink(path,'--query-all').splitlines():
fields=row.split(',')
if len(fields)==5:result[fields[0]]=list(map(float,fields[1:]))
return result
def render(source,target):ink(source,'--export-type=png',f'--export-filename={target}','--export-width=2000','--export-height=2800')
def typeset(card,shared,newbounds,header,footer,folder):
fm=json.loads((fonts/'manifest.json').read_text())
families={'title':'P052','verse':'Sanctification P052','reference':'Sanctification P052'}
checks=[]
title_lines=card.get('titleLines',[card['name']])
assert ' '.join(title_lines)==card['name']
assert ' '.join(card['verseLines'])==card['excerpt']
assert card['referenceDisplay']==f'{card["reference"]} • {card["translation"]}'
sizes=dict(shared['layout']['fontSizes']);sizes['title']=100 if len(title_lines)==2 else 112
rows=[{'id':f'title-{i}','role':'title','text':line,'baseline':[176,266][i] if len(title_lines)==2 else 240} for i,line in enumerate(title_lines)]
rows += [{'id':f'verse-{i}','role':'verse','text':line,'baseline':y} for i,(line,y) in enumerate(zip(card['verseLines'],shared['layout']['baselines']['verseByLineCount'][str(len(card['verseLines']))]))]
rows += [{'id':'reference','role':'reference','text':card['referenceDisplay'],'baseline':2645}]
for role in families:
face=fm['productionTypography'][role];font=fonts/face['file'];assert digest(font)==fm['files'][font.name]['sha256']
matched=Path(subprocess.check_output(['fc-match','--format=%{file}',families[role]+(':style=Bold' if role=='title' else ':style=Medium')],env=ENV,text=True)).resolve();assert matched==font.resolve()
ranges=[(int(t.split('-')[0],16),int(t.split('-')[-1],16)) for t in subprocess.check_output(['fc-query','--format=%{charset}',str(font)],text=True).split()]
assert all(any(lo<=ord(c)<=hi for lo,hi in ranges) for row in rows if row['role']==role for c in row['text'])
assert sizes[role]>=shared['layout']['fontMinimums'][role]
checks.append({'role':role,'path':str(font.relative_to(REPO)),'sha256':digest(font),'weight':face['weight'],'size':sizes[role],'fallbackUsed':False,'missingGlyphs':[]})
def document(selected):
page=ET.Element(NS+'svg',{'width':'2000','height':'2800','viewBox':'0 0 2000 2800'})
group=ET.SubElement(page,NS+'g',{'fill':'#263f50','text-anchor':'middle'})
for row in selected:
role=row['role'];node=ET.SubElement(group,NS+'text',{'id':row['id'],'x':'1000','y':str(row['baseline']),'font-family':families[role],'font-weight':str(fm['productionTypography'][role]['weight']),'font-size':str(sizes[role])});node.text=row['text']
return ET.ElementTree(page)
source=folder/'text-preview.svg';document(rows).write(source,encoding='unicode');probe=query(source)
# Position reference using fresh, independently rendered actual glyph bounds.
ref=rows[-1];isolated=folder/'reference-probe.svg';document([ref]).write(isolated,encoding='unicode');probe_png=isolated.with_suffix('.png');render(isolated,probe_png)
rb=Image.open(probe_png).getchannel('A').getbbox();reference_bottom=int(np.floor(newbounds['footer-bottom'][1]))-20
ref['baseline']+=reference_bottom-rb[3]
reference_top=probe['reference'][1]+ref['baseline']-2645
# Center the whole verse block in the available band, with 40px above and 64px before attribution.
verse=[row for row in rows if row['role']=='verse'];vtop=min(probe[row['id']][1] for row in verse);vbottom=max(probe[row['id']][1]+probe[row['id']][3] for row in verse)
upper=newbounds['footer-top'][1]+newbounds['footer-top'][3]+40;lower=reference_top-64
assert vbottom-vtop<=lower-upper
delta=(upper+lower-vtop-vbottom)/2
for row in verse:row['baseline']+=delta
title=[row for row in rows if row['role']=='title'];ttop=min(probe[row['id']][1] for row in title);tbottom=max(probe[row['id']][1]+probe[row['id']][3] for row in title)
upper=float(header.get('y'))+float(header.get('stroke-width'))/2+20;lower=newbounds['header'][1]-20
assert tbottom-ttop<=lower-upper
delta=(upper+lower-ttop-tbottom)/2
for row in title:row['baseline']+=delta
document(rows).write(source,encoding='unicode');png=folder/'text-preview.png';render(source,png);bounds=query(source)
glyphs=[];ink_bounds={}
for row in rows:
isolated=folder/(row['id']+'-unclipped.svg');document([row]).write(isolated,encoding='unicode');im=isolated.with_suffix('.png');render(isolated,im);bb=Image.open(im).getchannel('A').getbbox()
region=[140,100,1720,200] if row['role']=='title' and len(title_lines)==2 else shared['layout']['textRegions'][row['role']]
x,y,w,h=bounds[row['id']];rx,ry,rw,rh=region
assert rx<=x and ry<=y and x+w<=rx+rw and y+h<=ry+rh,(card['cardId'],row,bounds[row['id']],region)
assert bb and rx<=bb[0] and ry<=bb[1] and bb[2]<=rx+rw and bb[3]<=ry+rh,(row,bb,region)
ink_bounds[row['id']]=bb;glyphs.append({**row,'objectBounds':bounds[row['id']],'unclippedInkBounds':list(bb),'region':region,'pass':True})
title_end=max(ink_bounds[row['id']][3] for row in title);verse_top=min(ink_bounds[row['id']][1] for row in verse);verse_end=max(ink_bounds[row['id']][3] for row in verse)
spaces={'titleToFlourish':newbounds['header'][1]-title_end,'upperFlourishToVerse':verse_top-(newbounds['footer-top'][1]+newbounds['footer-top'][3]),'verseToReference':ink_bounds['reference'][1]-verse_end,'referenceToLowerFlourish':newbounds['footer-bottom'][1]-ink_bounds['reference'][3]}
assert min(spaces.values())>=20,spaces
return Image.open(png).convert('RGBA'),{'fonts':checks,'glyphs':glyphs,'spacing':spaces,'layoutPolicy':{'title':'Whole ink block centered between top inner rule and flourish, each with 20px minimum clearance.','verse':'Whole ink block centered below upper flourish (+40px) and above reference (-64px).','reference':'Actual ink bottom anchored 20px above lower flourish.','titleSizes':'112px one-line; approved 100px two-line.','textColor':'#263f50'}},2645-ref['baseline']
cards=[('uncommon',REPO/'in-progress/cards/BE-042-calling-of-the-first-disciples/revisions/v02','text-2000.png','text.svg'),('rare',REPO/'artifacts/cards/BE-010-burning-bush','rare-shared-v2-text-2000.png','rare-shared-v2-text.svg'),('extraordinary',REPO/'artifacts/cards/BE-002-the-fall','extraordinary-shared-v2-text-2000.png','extraordinary-shared-v2-text.svg')]
report={'status':'pending','gapMasterPixels':20,'scope':'Separate Borderless preview; canonical shared layers, accepted cards and working exports are unchanged.','tools':{'inkscape':ink('--version'),'pillow':Image.__version__},'tiers':[]}
for tier,card_root,text_png,text_svg in cards:
shared=load_tier(tier,'v2');folder=OUT/tier;folder.mkdir(exist_ok=True)
card=json.loads((card_root/'card.json').read_text());art=Image.open(REPO/card['art']).convert('RGBA');oldtext=Image.open(card_root/'source/text'/text_png).convert('RGBA')
oldbacking=Image.open(shared['assets']['backing-borderless']).convert('RGBA')
oldface=Image.alpha_composite(Image.alpha_composite(art,oldbacking),oldtext)
tree=ET.parse(shared['directory']/'source/backing-borderless.svg');page=tree.getroot()
ornaments=[]
for node in page.iter(NS+'g'):
if node.get('id','').startswith('ornament-') or re.match(r'translate\(1000,',node.get('transform','')):
center=float(node.get('id').split('-')[1]) if node.get('id','').startswith('ornament-') else float(re.search(r'translate\(1000,([\d.]+)',node.get('transform')).group(1))
ornaments.append((center,node))
ornaments.sort(key=lambda v:v[0]);assert len(ornaments)==3
for (_,node),key in zip(ornaments,['header','footer-top','footer-bottom']):node.set('id',key)
source=folder/'backing-borderless-20.svg';tree.write(source,encoding='unicode');oldbounds=query(source)
rects=[node for node in page.iter(NS+'rect') if node.get('fill')=='none' and node.get('stroke')]
header=max((node for node in rects if float(node.get('y'))<400),key=lambda n:float(n.get('y')))
footer=max((node for node in rects if float(node.get('y'))>2000),key=lambda n:float(n.get('y')))
def edge(rect,top):
y=float(rect.get('y'));h=float(rect.get('height'));s=float(rect.get('stroke-width'))
return y+s/2 if top else y+h-s/2
edges={'header':edge(header,False),'footer-top':edge(footer,True),'footer-bottom':edge(footer,False)}
entries=[]
for (_,node),key in zip(ornaments,['header','footer-top','footer-bottom']):
x,y,w,h=oldbounds[key];oldedge=y if key=='footer-top' else y+h
target=edges[key]+20 if key=='footer-top' else edges[key]-20
delta=target-oldedge;node.set('transform',f'translate(0,{delta:.8f}) '+node.get('transform',''))
before=oldedge-edges[key] if key=='footer-top' else edges[key]-oldedge
entries.append({'placement':key,'innerRuleInkEdge':edges[key],'previousGap':round(before,4),'verticalShift':round(delta,4)})
tree.write(source,encoding='unicode');newbounds=query(source)
for entry in entries:
key=entry['placement'];x,y,w,h=newbounds[key];newedge=y if key=='footer-top' else y+h
gap=newedge-edges[key] if key=='footer-top' else edges[key]-newedge
assert abs(gap-20)<.02,(tier,key,gap);entry['newGap']=round(gap,4)
backing_png=folder/'backing-borderless-20.png';render(source,backing_png);backing=Image.open(backing_png).convert('RGBA')
typography=None
if args.retype_text:
text,typography,shift=typeset(card,shared,newbounds,header,footer,folder)
else:
# Preserve at least 20px of space for actual reference ink as the lower ornament moves inward.
texttree=ET.parse(card_root/'source/text'/text_svg);reference=next(node for node in texttree.getroot().iter(NS+'text') if node.get('id')=='reference')
isolated=card_root/'source/text'/('reference-unclipped.png' if tier=='uncommon' else f'{tier}-shared-v2-reference-unclipped.png')
refbb=Image.open(isolated).getchannel('A').getbbox();orn_top=newbounds['footer-bottom'][1]
shift=max(0,int(np.ceil(20-(orn_top-refbb[3]))))
if shift:reference.set('y',str(float(reference.get('y'))-shift))
newtext_svg=folder/'text-preview.svg';texttree.write(newtext_svg,encoding='unicode');newtext_png=folder/'text-preview.png';render(newtext_svg,newtext_png);text=Image.open(newtext_png).convert('RGBA')
assert np.all(np.asarray(backing.getchannel('A'))[np.asarray(text.getchannel('A'))>0]==255)
newface=Image.alpha_composite(Image.alpha_composite(art,backing),text)
for name,im in [('before',oldface),('spacing-20',newface)]:
for width in [2000,1000,500]:im.resize((width,width*7//5),Image.Resampling.LANCZOS).save(folder/f'{name}-borderless-{width}.png')
item={'tier':tier,'cardId':card['cardId'],'sharedVersion':'v2','sharedManifestSHA256':shared['manifestSHA256'],'artSHA256':digest(REPO/card['art']),'originalTextSHA256':digest(card_root/'source/text'/text_png),'flourishes':entries,'referenceShiftUpMasterPixels':shift,'referenceReason':'Maintain 20px minimum text clearance from the inward-moving lower flourish.','textOtherwiseUnchanged':not args.retype_text,'freshTypography':typography}
report['tiers'].append(item)
label=ImageFont.truetype(str(fonts/'P052-Bold.otf'),23)
# Full cards before/after, grouped by tier.
board=Image.new('RGB',(1040,2310),'#11161c');d=ImageDraw.Draw(board)
for row,(tier,*_) in enumerate(cards):
for col,(name,tag) in enumerate([('before','Current'),('spacing-20','20px + retyped' if args.retype_text else '20px spacing')]):
x=10+col*520;y=row*770;d.text((x,y+10),f'{tier.title()} · {tag}',font=label,fill='#f4ead4');im=Image.open(OUT/tier/f'{name}-borderless-500.png').convert('RGB');board.paste(im,(x,y+50))
board.save(OUT/'cards-before-after.png')
# Panels at matching scale, with the two treatments adjacent for each tier.
for panel,crop,height in [('headers',(70,45,1930,375),175),('footers',(70,2165,1930,2755),245)]:
treatments=[('before','Current'),('spacing-only','20px spacing only'),('spacing-20','20px + retyped')] if args.retype_text else [('before','Current'),('spacing-20','20px')]
sheet=Image.new('RGB',(1740,height*len(treatments)),'#11161c');draw=ImageDraw.Draw(sheet)
for col,(tier,*_) in enumerate(cards):
for row,(name,tag) in enumerate(treatments):
x=col*580+10;y=row*height;draw.text((x,y+8),f'{tier.title()} · {tag}',font=label,fill='#f4ead4');image_path=ROOT/'output'/tier/'spacing-20-borderless-2000.png' if name=='spacing-only' else OUT/tier/f'{name}-borderless-2000.png';im=Image.open(image_path).convert('RGB').crop(crop);im.thumbnail((560,height-48));sheet.paste(im,(x,y+42))
sheet.save(OUT/f'{panel}-comparison.png')
if args.retype_text:
lineup=Image.new('RGB',(1560,770),'#11161c');draw=ImageDraw.Draw(lineup)
for col,(tier,*_) in enumerate(cards):
x=col*520+10;draw.text((x,10),tier.title()+' · retyped',font=label,fill='#f4ead4');lineup.paste(Image.open(OUT/tier/'spacing-20-borderless-500.png').convert('RGB'),(x,50))
lineup.save(OUT/'cards-retyped.png')
report['status']='passed-preview';(OUT/'validation.json').write_text(json.dumps(report,indent=2)+'\n')
print(json.dumps([{k:v for k,v in item.items() if k in ['tier','flourishes','referenceShiftUpMasterPixels']} for item in report['tiers']],indent=2))

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python3
"""Center each verse's visible ink between the upper flourish and reference ink."""
from pathlib import Path
import copy,hashlib,json,os,subprocess
import xml.etree.ElementTree as ET
import numpy as np
from PIL import Image,ImageDraw,ImageFont
ROOT=Path(__file__).resolve().parent
REPO=next(p for p in ROOT.parents if (p/'docs/card-layer-pipeline.md').is_file())
BASE=ROOT/'output-retyped';OUT=ROOT/'output-centered';OUT.mkdir(exist_ok=True)
NS='{http://www.w3.org/2000/svg}';ET.register_namespace('','http://www.w3.org/2000/svg')
fonts=REPO/'fonts';fm=json.loads((fonts/'manifest.json').read_text())
def digest(path):return hashlib.sha256(path.read_bytes()).hexdigest()
for name in ['P052-Bold.otf','SanctificationP052-Medium.otf']:assert digest(fonts/name)==fm['files'][name]['sha256']
config=OUT/'fonts.conf';config.write_text(f'<fontconfig><dir>{fonts}</dir><cachedir>{OUT/"font-cache"}</cachedir></fontconfig>');env=dict(os.environ,FONTCONFIG_FILE=str(config))
def ink(*args):return subprocess.check_output(['inkscape',*map(str,args)],env=env,text=True,stderr=subprocess.PIPE).strip()
def render(source,target,*options):ink(source,*options,'--export-type=png',f'--export-filename={target}','--export-width=2000','--export-height=2800')
roots={'uncommon':REPO/'in-progress/cards/BE-042-calling-of-the-first-disciples/revisions/v02','rare':REPO/'artifacts/cards/BE-010-burning-bush','extraordinary':REPO/'artifacts/cards/BE-002-the-fall'}
report={'status':'pending','scope':'Separate static comparison; verse baselines only change.','centeringRule':'Center the combined unclipped verse ink bounds between the bottom visible edge of the upper flourish and top visible edge of the reference. No prescribed margin participates in placement.','minimumClearance':20,'clearanceRole':'Validation only; never used to offset the center.','tiers':[]}
for tier,root in roots.items():
folder=OUT/tier;folder.mkdir(exist_ok=True);card=json.loads((root/'card.json').read_text())
ornament_png=folder/'upper-flourish-guide.png';render(BASE/tier/'backing-borderless-20.svg',ornament_png,'--export-id=footer-top','--export-id-only','--export-area-page')
ornament_bounds=Image.open(ornament_png).getchannel('A').getbbox();reference_bounds=Image.open(BASE/tier/'reference-unclipped.png').getchannel('A').getbbox()
tree=ET.parse(BASE/tier/'text-preview.svg');verses=[node for node in tree.getroot().iter(NS+'text') if node.get('id','').startswith('verse-')]
assert verses
old_boxes=[Image.open(BASE/tier/(node.get('id')+'-unclipped.png')).getchannel('A').getbbox() for node in verses]
old_top=min(box[1] for box in old_boxes);old_bottom=max(box[3] for box in old_boxes)
upper=ornament_bounds[3];lower=reference_bounds[1];target_center=(upper+lower)/2;delta=target_center-(old_top+old_bottom)/2
for node in verses:node.set('y',str(float(node.get('y'))+delta))
source=folder/'text-centered.svg';tree.write(source,encoding='unicode');png=folder/'text-centered.png';render(source,png);text=Image.open(png).convert('RGBA')
glyphs=[]
for node in verses:
page=ET.Element(NS+'svg',{'width':'2000','height':'2800','viewBox':'0 0 2000 2800'});g=ET.SubElement(page,NS+'g',{'fill':'#263f50','text-anchor':'middle'});g.append(copy.deepcopy(node))
isolated=folder/(node.get('id')+'-unclipped.svg');ET.ElementTree(page).write(isolated,encoding='unicode');im=isolated.with_suffix('.png');render(isolated,im);box=Image.open(im).getchannel('A').getbbox()
assert box and 160<=box[0] and 2260<=box[1] and box[2]<=1840 and box[3]<=2560,(tier,box)
glyphs.append({'id':node.get('id'),'baseline':float(node.get('y')),'unclippedInkBounds':list(box)})
new_top=min(g['unclippedInkBounds'][1] for g in glyphs);new_bottom=max(g['unclippedInkBounds'][3] for g in glyphs)
above=new_top-upper;below=lower-new_bottom;assert min(above,below)>=20,(tier,above,below);assert abs(above-below)<=1,(tier,above,below)
oldtext=Image.open(BASE/tier/'text-preview.png').convert('RGBA');old=np.asarray(oldtext);new=np.asarray(text)
# Header and attribution remain bit-for-bit identical; only verse rows move.
assert np.array_equal(old[:2260],new[:2260]) and np.array_equal(old[2560:],new[2560:]),tier
art=Image.open(REPO/card['art']).convert('RGBA');backing=Image.open(BASE/tier/'backing-borderless-20.png').convert('RGBA')
assert np.all(np.asarray(backing.getchannel('A'))[new[:,:,3]>0]==255)
face=Image.alpha_composite(Image.alpha_composite(art,backing),text)
for width in [2000,1000,500]:face.resize((width,width*7//5),Image.Resampling.LANCZOS).save(folder/f'centered-borderless-{width}.png')
report['tiers'].append({'tier':tier,'cardId':card['cardId'],'upperFlourishInkBounds':list(ornament_bounds),'referenceInkBounds':list(reference_bounds),'availableBand':[upper,lower],'targetCenter':target_center,'verseCenter':(new_top+new_bottom)/2,'verseVerticalShift':delta,'gapAboveVerse':above,'gapBelowVerse':below,'glyphs':glyphs,'backingSHA256':digest(BASE/tier/'backing-borderless-20.png'),'previousTextSHA256':digest(BASE/tier/'text-preview.png'),'newTextSHA256':digest(png)})
label=ImageFont.truetype(str(fonts/'P052-Bold.otf'),23)
board=Image.new('RGB',(1740,490),'#11161c');d=ImageDraw.Draw(board)
lineup=Image.new('RGB',(1560,770),'#11161c');ld=ImageDraw.Draw(lineup)
for col,tier in enumerate(roots):
for row,(name,parent) in enumerate([('Previous retyped',BASE),('Verse ink centered',OUT)]):
path=parent/tier/('spacing-20-borderless-2000.png' if parent==BASE else 'centered-borderless-2000.png');im=Image.open(path).convert('RGB').crop((70,2165,1930,2755));im.thumbnail((560,197));x=col*580+10;y=row*245;d.text((x,y+8),tier.title()+' · '+name,font=label,fill='#f4ead4');board.paste(im,(x,y+42))
x=col*520+10;ld.text((x,10),tier.title()+' · centered',font=label,fill='#f4ead4');lineup.paste(Image.open(OUT/tier/'centered-borderless-500.png').convert('RGB'),(x,50))
board.save(OUT/'footers-comparison.png');lineup.save(OUT/'cards-centered.png')
report.update({'status':'passed-preview','builderSHA256':digest(Path(__file__)),'sharedFontManifestSHA256':digest(fonts/'manifest.json'),'tools':{'inkscape':ink('--version'),'pillow':Image.__version__},'visualReview':'Pending static inspection; no moving-light review.'});(OUT/'validation.json').write_text(json.dumps(report,indent=2)+'\n')
print(json.dumps([{'tier':e['tier'],'verticalShift':e['verseVerticalShift'],'gapAbove':e['gapAboveVerse'],'gapBelow':e['gapBelowVerse']} for e in report['tiers']],indent=2))

View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python3
"""Isolated font-metric reference anchoring and visible-ink verse centering proof."""
from pathlib import Path
import copy,hashlib,json,math,os,struct,subprocess
import xml.etree.ElementTree as ET
import numpy as np
from PIL import Image,ImageDraw,ImageFont
ROOT=Path(__file__).resolve().parent
REPO=next(p for p in ROOT.parents if (p/'docs/card-layer-pipeline.md').is_file())
BASE=ROOT/'output-centered';BACK=ROOT/'output-retyped';OUT=ROOT/'output-baseline';OUT.mkdir(exist_ok=True)
NS='{http://www.w3.org/2000/svg}';ET.register_namespace('','http://www.w3.org/2000/svg')
fonts=REPO/'fonts';manifest=json.loads((fonts/'manifest.json').read_text())
def digest(p):return hashlib.sha256(p.read_bytes()).hexdigest()
for name in ['P052-Bold.otf','SanctificationP052-Medium.otf']:assert digest(fonts/name)==manifest['files'][name]['sha256']
# Read SFNT tables directly: no dependency installation or word-dependent metrics.
b=(fonts/'SanctificationP052-Medium.otf').read_bytes();tables={}
for i in range(struct.unpack_from('>H',b,4)[0]):
tag,_,offset,length=struct.unpack_from('>4sIII',b,12+16*i);tables[tag.decode()]=b[offset:offset+length]
upm=struct.unpack_from('>H',tables['head'],18)[0]
asc,desc,linegap=struct.unpack_from('>hhh',tables['hhea'],4)
ymin=struct.unpack_from('>h',tables['head'],38)[0]
size=57;ascent=math.ceil(asc*size/upm);descent=math.ceil(max(-desc,-ymin)*size/upm);gap=20
config=OUT/'fonts.conf';config.write_text(f'<fontconfig><dir>{fonts}</dir><cachedir>{OUT/"font-cache"}</cachedir></fontconfig>');env=dict(os.environ,FONTCONFIG_FILE=str(config))
def ink(*args):return subprocess.check_output(['inkscape',*map(str,args)],env=env,text=True,stderr=subprocess.PIPE).strip()
def render(src,dst,*args):ink(src,*args,'--export-type=png',f'--export-filename={dst}','--export-width=2000','--export-height=2800')
def isolate(node,folder,name):
page=ET.Element(NS+'svg',{'width':'2000','height':'2800','viewBox':'0 0 2000 2800'});g=ET.SubElement(page,NS+'g',{'fill':'#263f50','text-anchor':'middle'});g.append(copy.deepcopy(node))
src=folder/(name+'.svg');ET.ElementTree(page).write(src,encoding='unicode');dst=src.with_suffix('.png');render(src,dst);return Image.open(dst).convert('RGBA')
roots={'uncommon':REPO/'in-progress/cards/BE-042-calling-of-the-first-disciples/revisions/v02','rare':REPO/'artifacts/cards/BE-010-burning-bush','extraordinary':REPO/'artifacts/cards/BE-002-the-fall'}
# Immutable comparison inputs and canonical sources are hashed before/after.
protected=[p for parent in [BASE,BACK,*roots.values(),REPO/'artifacts/layers'] for p in parent.rglob('*') if p.is_file() and not p.is_symlink()]
before={str(p):digest(p) for p in protected}
report={'status':'pending','scope':'Static typography preview only; production cards, shared layers, docs and harness unchanged.','referenceRule':'baseline = lower flourish visible ink top - 20 - fixed descender allowance','verseRule':'Center combined actual verse ink between upper flourish visible bottom and fixed reference line-box top.','fontMetrics':{'unitsPerEm':upm,'hheaAscender':asc,'hheaDescender':desc,'headYMin':ymin,'referenceSize':size,'lineBoxAscent':ascent,'lineBoxDescent':descent,'lineGapUsed':0,'policy':'Ceil hhea ascent; ceil maximum of hhea descent and global font outline descent to include expanded Medium glyphs.'},'tiers':[]}
for tier,root in roots.items():
folder=OUT/tier;folder.mkdir(exist_ok=True);card=json.loads((root/'card.json').read_text())
lower_path=folder/'lower-flourish.png';render(BACK/tier/'backing-borderless-20.svg',lower_path,'--export-id=footer-bottom','--export-id-only','--export-area-page');lower=Image.open(lower_path).getchannel('A').getbbox()
upper=Image.open(BASE/tier/'upper-flourish-guide.png').getchannel('A').getbbox()
tree=ET.parse(BASE/tier/'text-centered.svg');nodes=list(tree.getroot().iter(NS+'text'));ref=next(n for n in nodes if n.get('id')=='reference');verses=[n for n in nodes if n.get('id','').startswith('verse-')]
assert ref.get('font-family')=='Sanctification P052' and ref.get('font-weight')=='500' and float(ref.get('font-size'))==size
baseline=lower[1]-gap-descent;ref.set('y',str(baseline));line_top=baseline-ascent;line_bottom=baseline+descent
refim=isolate(ref,folder,'reference-unclipped');rb=refim.getchannel('A').getbbox()
assert rb and rb[1]>=line_top and rb[3]<=line_bottom and lower[1]-rb[3]>=gap,(tier,rb,line_top,line_bottom)
oldboxes=[Image.open(BASE/tier/(n.get('id')+'-unclipped.png')).getchannel('A').getbbox() for n in verses]
oldcenter=(min(b[1] for b in oldboxes)+max(b[3] for b in oldboxes))/2;target=(upper[3]+line_top)/2
for n in verses:n.set('y',str(float(n.get('y'))+target-oldcenter))
glyphs=[]
for n in verses:
box=isolate(n,folder,n.get('id')+'-unclipped').getchannel('A').getbbox();assert box and box[0]>=160 and box[2]<=1840
glyphs.append({'id':n.get('id'),'baseline':float(n.get('y')),'inkBounds':list(box)})
vb=[min(g['inkBounds'][0] for g in glyphs),min(g['inkBounds'][1] for g in glyphs),max(g['inkBounds'][2] for g in glyphs),max(g['inkBounds'][3] for g in glyphs)]
above=vb[1]-upper[3];below=line_top-vb[3];assert min(above,below)>=20 and abs(above-below)<=1,(tier,above,below)
src=folder/'text-baseline.svg';tree.write(src,encoding='unicode');png=folder/'text-baseline.png';render(src,png);text=Image.open(png).convert('RGBA')
assert np.array_equal(np.asarray(text)[:2200],np.asarray(Image.open(BASE/tier/'text-centered.png').convert('RGBA'))[:2200])
artpath=REPO/card['art'];art=Image.open(artpath).convert('RGBA');backing=Image.open(BACK/tier/'backing-borderless-20.png').convert('RGBA')
assert np.all(np.asarray(backing.getchannel('A'))[np.asarray(text.getchannel('A'))>0]==255)
face=Image.alpha_composite(Image.alpha_composite(art,backing),text)
for width in [2000,1000,500]:
export=face.resize((width,width*7//5),Image.Resampling.LANCZOS);assert export.getchannel('A').getextrema()==(255,255);export.save(folder/f'baseline-borderless-{width}.png')
guide=face.convert('RGB');d=ImageDraw.Draw(guide);d.rectangle((160,line_top,1840,line_bottom),outline='#ab42d0',width=3);d.line((160,baseline,1840,baseline),fill='#dc3562',width=3);d.rectangle(tuple(rb),outline='#09a0ac',width=2);d.rectangle(tuple(vb),outline='#09a0ac',width=2)
for y in [upper[3],lower[1]]:d.line((160,y,1840,y),fill='#26a33c',width=3)
guide.crop((70,2165,1930,2755)).save(folder/'footer-guides.png')
cases=[]
for index,wording in enumerate(['Matthew 4:19 • NKJV','Genesis 3:9 • ESV','Exodus 3:6 • KJV','Philippians 2:11 • NKJV']):
probe=copy.deepcopy(ref);probe.text=wording;box=isolate(probe,folder,f'stress-reference-{index}').getchannel('A').getbbox()
assert box and box[1]>=line_top and box[3]<=line_bottom and lower[1]-box[3]>=gap,(tier,wording,box)
cases.append({'text':wording,'baseline':baseline,'inkBounds':list(box),'actualClearance':lower[1]-box[3],'lineBoxClearance':lower[1]-line_bottom})
report['tiers'].append({'tier':tier,'cardId':card['cardId'],'referenceBaseline':baseline,'referenceLineBox':[line_top,line_bottom],'referenceInkBounds':list(rb),'lowerFlourishInkBounds':list(lower),'upperFlourishInkBounds':list(upper),'lineBoxToFlourishGap':lower[1]-line_bottom,'actualReferenceToFlourishGap':lower[1]-rb[3],'verseInkBounds':vb,'gapAboveVerse':above,'gapBelowVerseToLineBox':below,'centeringError':abs(above-below),'verseVerticalShift':target-oldcenter,'glyphs':glyphs,'stressReferences':cases,'scaling':{str(w):{'baseline':baseline*w/2000,'lineBoxGap':gap*w/2000,'rasterRoundingAllowance':1} for w in [2000,1000,500]},'artSHA256':digest(artpath),'backingSHA256':digest(BACK/tier/'backing-borderless-20.png')})
assert all(digest(Path(p))==h for p,h in before.items())
report['preservedInputFiles']=len(before)
label=ImageFont.truetype(str(fonts/'P052-Bold.otf'),23)
board=Image.new('RGB',(1740,490),'#11161c');d=ImageDraw.Draw(board);guides=Image.new('RGB',(1740,275),'#11161c');gd=ImageDraw.Draw(guides);lineup=Image.new('RGB',(1560,770),'#11161c');ld=ImageDraw.Draw(lineup)
for col,tier in enumerate(roots):
x=col*580+10
for row,name in enumerate(['Previous ink anchoring','Fixed reference baseline']):
path=BASE/tier/'centered-borderless-2000.png' if row==0 else OUT/tier/'baseline-borderless-2000.png';im=Image.open(path).convert('RGB').crop((70,2165,1930,2755));im.thumbnail((560,197));d.text((x,row*245+8),tier.title()+' · '+name,font=label,fill='#f4ead4');board.paste(im,(x,row*245+42))
im=Image.open(OUT/tier/'footer-guides.png');im.thumbnail((560,197));gd.text((x,8),tier.title()+' · metrics / ink guides',font=label,fill='#f4ead4');guides.paste(im,(x,42))
ld.text((col*520+10,10),tier.title()+' · fixed baseline',font=label,fill='#f4ead4');lineup.paste(Image.open(OUT/tier/'baseline-borderless-500.png').convert('RGB'),(col*520+10,50))
board.save(OUT/'footers-comparison.png');guides.save(OUT/'footer-guides.png');lineup.save(OUT/'cards-baseline.png')
# Check visible clearance on resized data, independently of geometric predictions.
for entry in report['tiers']:
folder=OUT/entry['tier'];checks=[]
for width in [2000,1000,500]:
scale=width/2000;dimensions=(width,width*7//5)
def resized_bounds(name):
alpha=Image.open(folder/name).getchannel('A').resize(dimensions,Image.Resampling.LANCZOS)
return alpha.point(lambda a:255 if a>=128 else 0).getbbox()
ornament=resized_bounds('lower-flourish.png')
for i,case in enumerate(entry['stressReferences']):
glyph=resized_bounds(f'stress-reference-{i}.png');clearance=ornament[1]-glyph[3]
assert clearance>=gap*scale-1,(entry['tier'],width,case['text'],clearance)
checks.append({'width':width,'text':case['text'],'visibleAlphaThreshold':128,'actualReferenceToFlourishGap':clearance,'minimumWithRounding':gap*scale-1})
entry['scaledRasterChecks']=checks
report.update({'status':'passed-preview','builderSHA256':digest(Path(__file__)),'fontManifestSHA256':digest(fonts/'manifest.json'),'fontSHA256':digest(fonts/'SanctificationP052-Medium.otf'),'tools':{'inkscape':ink('--version'),'pillow':Image.__version__},'visualReview':'Pending static inspection; user acceptance pending. No GPU or moving-light review.'})
(OUT/'validation.json').write_text(json.dumps(report,indent=2)+'\n')
print(json.dumps({'fontMetrics':report['fontMetrics'],'tiers':[{k:e[k] for k in ['tier','referenceBaseline','lineBoxToFlourishGap','actualReferenceToFlourishGap','gapAboveVerse','gapBelowVerseToLineBox']} for e in report['tiers']],'preservedFiles':len(before)},indent=2))

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Matthew 4:19 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • KJV</text></g></svg>

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Philippians 2:11 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="title-0" x="1000" y="226.92949999999996" font-family="P052" font-weight="700" font-size="112">THE FALL</text><text id="verse-0" x="1000" y="2438.262750000001" font-family="Sanctification P052" font-weight="500" font-size="80">“Where are you?”</text><text id="reference" x="1000" y="2627" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-0" x="1000" y="2438.262750000001" font-family="Sanctification P052" font-weight="500" font-size="80">“Where are you?”</text></g></svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,4 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by fontconfig.
# For information about cache directory tags, see:
# http://www.brynosaurus.com/cachedir/

View File

@@ -0,0 +1 @@
<fontconfig><dir>/home/dkzver/docker/sanctification/fonts</dir><cachedir>/home/dkzver/docker/sanctification/spikes/flourish-spacing-20px-proof/output-baseline/font-cache</cachedir></fontconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Matthew 4:19 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • KJV</text></g></svg>

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Philippians 2:11 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="title-0" x="1000" y="227.70549999999997" font-family="P052" font-weight="700" font-size="112">THE BURNING BUSH</text><text id="verse-0" x="1000" y="2375.89775" font-family="Sanctification P052" font-weight="500" font-size="80">And Moses hid his face, for he was</text><text id="verse-1" x="1000" y="2500.89775" font-family="Sanctification P052" font-weight="500" font-size="80">afraid to look upon God.</text><text id="reference" x="1000" y="2636" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-0" x="1000" y="2375.89775" font-family="Sanctification P052" font-weight="500" font-size="80">And Moses hid his face, for he was</text></g></svg>

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-1" x="1000" y="2500.89775" font-family="Sanctification P052" font-weight="500" font-size="80">afraid to look upon God.</text></g></svg>

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 709 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Matthew 4:19 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Matthew 4:19 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • KJV</text></g></svg>

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Philippians 2:11 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 278 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="title-0" x="1000" y="178.6375" font-family="P052" font-weight="700" font-size="100">CALLING OF THE</text><text id="title-1" x="1000" y="268.6375" font-family="P052" font-weight="700" font-size="100">FIRST DISCIPLES</text><text id="verse-0" x="1000" y="2375.77775" font-family="Sanctification P052" font-weight="500" font-size="80">Then He said to them, “Follow Me,</text><text id="verse-1" x="1000" y="2500.77775" font-family="Sanctification P052" font-weight="500" font-size="80">and I will make you fishers of men.”</text><text id="reference" x="1000" y="2643" font-family="Sanctification P052" font-weight="500" font-size="57">Matthew 4:19 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-0" x="1000" y="2375.77775" font-family="Sanctification P052" font-weight="500" font-size="80">Then He said to them, “Follow Me,</text></g></svg>

After

Width:  |  Height:  |  Size: 292 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-1" x="1000" y="2500.77775" font-family="Sanctification P052" font-weight="500" font-size="80">and I will make you fishers of men.”</text></g></svg>

After

Width:  |  Height:  |  Size: 295 B

View File

@@ -0,0 +1,671 @@
{
"status": "passed-preview",
"scope": "Static typography preview only; production cards, shared layers, docs and harness unchanged.",
"referenceRule": "baseline = lower flourish visible ink top - 20 - fixed descender allowance",
"verseRule": "Center combined actual verse ink between upper flourish visible bottom and fixed reference line-box top.",
"fontMetrics": {
"unitsPerEm": 1000,
"hheaAscender": 726,
"hheaDescender": -274,
"headYMin": -288,
"referenceSize": 57,
"lineBoxAscent": 42,
"lineBoxDescent": 17,
"lineGapUsed": 0,
"policy": "Ceil hhea ascent; ceil maximum of hhea descent and global font outline descent to include expanded Medium glyphs."
},
"tiers": [
{
"tier": "uncommon",
"cardId": "BE-042",
"referenceBaseline": 2643,
"referenceLineBox": [
2601,
2660
],
"referenceInkBounds": [
724,
2601,
1276,
2655
],
"lowerFlourishInkBounds": [
755,
2680,
1245,
2701
],
"upperFlourishInkBounds": [
755,
2219,
1245,
2240
],
"lineBoxToFlourishGap": 20,
"actualReferenceToFlourishGap": 25,
"verseInkBounds": [
362,
2317,
1636,
2524
],
"gapAboveVerse": 77,
"gapBelowVerseToLineBox": 77,
"centeringError": 0,
"verseVerticalShift": -2.5,
"glyphs": [
{
"id": "verse-0",
"baseline": 2375.77775,
"inkBounds": [
383,
2317,
1616,
2389
]
},
{
"id": "verse-1",
"baseline": 2500.77775,
"inkBounds": [
362,
2442,
1636,
2524
]
}
],
"stressReferences": [
{
"text": "Matthew 4:19 \u2022 NKJV",
"baseline": 2643,
"inkBounds": [
724,
2601,
1276,
2655
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Genesis 3:9 \u2022 ESV",
"baseline": 2643,
"inkBounds": [
776,
2602,
1224,
2645
],
"actualClearance": 35,
"lineBoxClearance": 20
},
{
"text": "Exodus 3:6 \u2022 KJV",
"baseline": 2643,
"inkBounds": [
782,
2601,
1218,
2655
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Philippians 2:11 \u2022 NKJV",
"baseline": 2643,
"inkBounds": [
694,
2601,
1306,
2660
],
"actualClearance": 20,
"lineBoxClearance": 20
}
],
"scaling": {
"2000": {
"baseline": 2643.0,
"lineBoxGap": 20.0,
"rasterRoundingAllowance": 1
},
"1000": {
"baseline": 1321.5,
"lineBoxGap": 10.0,
"rasterRoundingAllowance": 1
},
"500": {
"baseline": 660.75,
"lineBoxGap": 5.0,
"rasterRoundingAllowance": 1
}
},
"artSHA256": "f51ca54ed1944b5615fd2f15a7fdc22bc65608a6de6b7a0d3c5b1b48e98f5550",
"backingSHA256": "9801ffa0eb7fb82b5c6e4fe6158ae8a45b584e9c38da5c221f558f1495e06728",
"scaledRasterChecks": [
{
"width": 2000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 37,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 22,
"minimumWithRounding": 19.0
},
{
"width": 1000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 14,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 19,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 14,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 11,
"minimumWithRounding": 9.0
},
{
"width": 500,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 7,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 10,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 8,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 6,
"minimumWithRounding": 4.0
}
]
},
{
"tier": "rare",
"cardId": "BE-010",
"referenceBaseline": 2636,
"referenceLineBox": [
2594,
2653
],
"referenceInkBounds": [
759,
2594,
1242,
2648
],
"lowerFlourishInkBounds": [
755,
2673,
1245,
2694
],
"upperFlourishInkBounds": [
755,
2226,
1245,
2247
],
"lineBoxToFlourishGap": 20,
"actualReferenceToFlourishGap": 25,
"verseInkBounds": [
388,
2317,
1610,
2524
],
"gapAboveVerse": 70,
"gapBelowVerseToLineBox": 70,
"centeringError": 0,
"verseVerticalShift": -2.5,
"glyphs": [
{
"id": "verse-0",
"baseline": 2375.89775,
"inkBounds": [
388,
2317,
1610,
2389
]
},
{
"id": "verse-1",
"baseline": 2500.89775,
"inkBounds": [
566,
2442,
1431,
2524
]
}
],
"stressReferences": [
{
"text": "Matthew 4:19 \u2022 NKJV",
"baseline": 2636,
"inkBounds": [
724,
2594,
1276,
2648
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Genesis 3:9 \u2022 ESV",
"baseline": 2636,
"inkBounds": [
776,
2595,
1224,
2638
],
"actualClearance": 35,
"lineBoxClearance": 20
},
{
"text": "Exodus 3:6 \u2022 KJV",
"baseline": 2636,
"inkBounds": [
782,
2594,
1218,
2648
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Philippians 2:11 \u2022 NKJV",
"baseline": 2636,
"inkBounds": [
694,
2594,
1306,
2653
],
"actualClearance": 20,
"lineBoxClearance": 20
}
],
"scaling": {
"2000": {
"baseline": 2636.0,
"lineBoxGap": 20.0,
"rasterRoundingAllowance": 1
},
"1000": {
"baseline": 1318.0,
"lineBoxGap": 10.0,
"rasterRoundingAllowance": 1
},
"500": {
"baseline": 659.0,
"lineBoxGap": 5.0,
"rasterRoundingAllowance": 1
}
},
"artSHA256": "fa5a29060a8446758e86d9b2f5111e782709e50826916ab7bed7b66da514bea4",
"backingSHA256": "d811205f920e4ad5a060938b29b19cb1ef11b7329a4b23af7885c7040519208e",
"scaledRasterChecks": [
{
"width": 2000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 37,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 22,
"minimumWithRounding": 19.0
},
{
"width": 1000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 13,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 18,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 13,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 11,
"minimumWithRounding": 9.0
},
{
"width": 500,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 7,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 10,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 7,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 6,
"minimumWithRounding": 4.0
}
]
},
{
"tier": "extraordinary",
"cardId": "BE-002",
"referenceBaseline": 2627,
"referenceLineBox": [
2585,
2644
],
"referenceInkBounds": [
776,
2586,
1224,
2629
],
"lowerFlourishInkBounds": [
745,
2664,
1255,
2687
],
"upperFlourishInkBounds": [
745,
2233,
1255,
2256
],
"lineBoxToFlourishGap": 20,
"actualReferenceToFlourishGap": 35,
"verseInkBounds": [
687,
2379,
1313,
2462
],
"gapAboveVerse": 123,
"gapBelowVerseToLineBox": 123,
"centeringError": 0,
"verseVerticalShift": -8.0,
"glyphs": [
{
"id": "verse-0",
"baseline": 2438.262750000001,
"inkBounds": [
687,
2379,
1313,
2462
]
}
],
"stressReferences": [
{
"text": "Matthew 4:19 \u2022 NKJV",
"baseline": 2627,
"inkBounds": [
724,
2585,
1276,
2639
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Genesis 3:9 \u2022 ESV",
"baseline": 2627,
"inkBounds": [
776,
2586,
1224,
2629
],
"actualClearance": 35,
"lineBoxClearance": 20
},
{
"text": "Exodus 3:6 \u2022 KJV",
"baseline": 2627,
"inkBounds": [
782,
2585,
1218,
2639
],
"actualClearance": 25,
"lineBoxClearance": 20
},
{
"text": "Philippians 2:11 \u2022 NKJV",
"baseline": 2627,
"inkBounds": [
694,
2585,
1306,
2644
],
"actualClearance": 20,
"lineBoxClearance": 20
}
],
"scaling": {
"2000": {
"baseline": 2627.0,
"lineBoxGap": 20.0,
"rasterRoundingAllowance": 1
},
"1000": {
"baseline": 1313.5,
"lineBoxGap": 10.0,
"rasterRoundingAllowance": 1
},
"500": {
"baseline": 656.75,
"lineBoxGap": 5.0,
"rasterRoundingAllowance": 1
}
},
"artSHA256": "e384f45ece80765f90bd5575a5d087d4b6d15ee8ad0b1beef293bcf09648c085",
"backingSHA256": "0da5ff12b30875b525daeb231ab24022116ef312d760949c2d631376ffaaa8c4",
"scaledRasterChecks": [
{
"width": 2000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 37,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 27,
"minimumWithRounding": 19.0
},
{
"width": 2000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 22,
"minimumWithRounding": 19.0
},
{
"width": 1000,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 14,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 19,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 14,
"minimumWithRounding": 9.0
},
{
"width": 1000,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 11,
"minimumWithRounding": 9.0
},
{
"width": 500,
"text": "Matthew 4:19 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 7,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Genesis 3:9 \u2022 ESV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 10,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Exodus 3:6 \u2022 KJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 8,
"minimumWithRounding": 4.0
},
{
"width": 500,
"text": "Philippians 2:11 \u2022 NKJV",
"visibleAlphaThreshold": 128,
"actualReferenceToFlourishGap": 6,
"minimumWithRounding": 4.0
}
]
}
],
"preservedInputFiles": 520,
"builderSHA256": "998876f863f8227d351cca8665421803a527f3c99924c6803f62a2cc0d229267",
"fontManifestSHA256": "ef68ee6393981d54ca068a950f21c53b374d20e6e46c21c788f36380d3aae178",
"fontSHA256": "1e0e1f7f4a5b2899374de51e40f15446a04a5c0163d6a1943155f964c1ace1fb",
"tools": {
"inkscape": "Inkscape 1.2.2 (b0a8486541, 2022-12-01)",
"pillow": "10.2.0"
},
"visualReview": "Static comparison inspected and visually accepted by the user. No GPU or moving-light review.",
"userApproval": {
"date": "2026-09-14",
"wording": "I think this looks really good.",
"scope": "Fixed reference baseline and verse-centering spacing comparison; documentation adoption. No final card approval or production migration."
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="title-0" x="1000" y="226.92949999999996" font-family="P052" font-weight="700" font-size="112">THE FALL</text><text id="verse-0" x="1000" y="2446.262750000001" font-family="Sanctification P052" font-weight="500" font-size="80">“Where are you?”</text><text id="reference" x="1000" y="2642" font-family="Sanctification P052" font-weight="500" font-size="57">Genesis 3:9 • ESV</text></g></svg>

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-0" x="1000" y="2446.262750000001" font-family="Sanctification P052" font-weight="500" font-size="80">“Where are you?”</text></g></svg>

After

Width:  |  Height:  |  Size: 284 B

View File

@@ -0,0 +1,4 @@
Signature: 8a477f597d28d172789f06886806bc55
# This file is a cache directory tag created by fontconfig.
# For information about cache directory tags, see:
# http://www.brynosaurus.com/cachedir/

View File

@@ -0,0 +1 @@
<fontconfig><dir>/home/dkzver/docker/sanctification/fonts</dir><cachedir>/home/dkzver/docker/sanctification/spikes/flourish-spacing-20px-proof/output-centered/font-cache</cachedir></fontconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 614 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="title-0" x="1000" y="227.70549999999997" font-family="P052" font-weight="700" font-size="112">THE BURNING BUSH</text><text id="verse-0" x="1000" y="2378.39775" font-family="Sanctification P052" font-weight="500" font-size="80">And Moses hid his face, for he was</text><text id="verse-1" x="1000" y="2503.39775" font-family="Sanctification P052" font-weight="500" font-size="80">afraid to look upon God.</text><text id="reference" x="1000" y="2641" font-family="Sanctification P052" font-weight="500" font-size="57">Exodus 3:6 • NKJV</text></g></svg>

After

Width:  |  Height:  |  Size: 691 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="2000" height="2800" viewBox="0 0 2000 2800"><g fill="#263f50" text-anchor="middle"><text id="verse-0" x="1000" y="2378.39775" font-family="Sanctification P052" font-weight="500" font-size="80">And Moses hid his face, for he was</text></g></svg>

After

Width:  |  Height:  |  Size: 291 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Some files were not shown because too many files have changed in this diff Show More