Add Legendary Moses card and production guidance

This commit is contained in:
2026-09-17 09:26:45 -07:00
parent ee0113442d
commit 5e49435127
514 changed files with 9974 additions and 13 deletions

View File

@@ -0,0 +1,36 @@
# Moses — provisional Legendary threshold composition
This requested preview tests the selected v03 illustration with real P052 typography and a bespoke threshold-driven Normal layout. It is a composition candidate, not production assembly.
- [Composed preview](composed-preview-1000.png)
- [500 × 700 preview](composed-preview-500.png)
- [Curtain comparison](curtain-comparison.png)
- [Enlarged curtain/backing junction](curtain-junction-detail.png)
- [Authored curtain foreground](foreground-curtain.svg)
- [Frame and backing source](border-backing-preview.svg)
- [Deterministic text source](text-preview.svg)
- [Validation](preview-validation.json)
- [Reproducible builder](build-preview.py)
## Governing idea
The outer frame uses narrow antique gold, lapis, ivory and tent-derived geometric bands. The upper-right plaque occupies open sky without covering Moses. The lower ivory textile backing begins below his folded hands and reserves a wide central-right field for the four-line verse.
The complete attached burgundy curtain is selected from the original illustration with an authored full-canvas contour. It composes above the frame and backing, crossing the left perimeter and far-left backing corner while remaining visibly attached to the tent. It does not intersect the lettering. Moses stays behind the backing, avoiding a second character-mantle treatment like David.
The narrative verse is presented without quotation marks:
And there has not arisen<br>
a prophet since in Israel<br>
like Moses, whom the LORD<br>
knew face to face
Deuteronomy 34:10 • ESV
P052 Bold 700 renders MOSES at 138px. Sanctification P052 Medium 500 renders the verse at 80px with 94px baselines and the reference at 57px. The measured verse ink has 54 master pixels above and 53 below within its reserved band.
## Scope
Only the provisional Normal composition is rendered. The proposed printing behavior remains a hypothesis until this layout is accepted: Normal would use frame, backings, curtain, and text; Borderless would use backings, curtain, and text; Textless would use frame and curtain; Boundless would use the unmodified illustration.
No production printings, finish masks, text masks, harness fixtures, moving-light review, or final approval were created.

View File

@@ -0,0 +1,150 @@
#!/usr/bin/env python3
"""Provisional BP-001 Moses Legendary composition; no production assembly."""
from pathlib import Path
import hashlib,json,os,subprocess
from xml.sax.saxutils import escape
import numpy as np
from PIL import Image,ImageDraw,ImageFont
P=Path(__file__).resolve().parent
REV=P.parents[1]
REPO=next(p for p in P.parents if (p/'docs/card-layer-pipeline.md').is_file())
ART=REV/'source/art-master.png'
FONTS=REPO/'fonts'
sha=lambda p:hashlib.sha256(p.read_bytes()).hexdigest()
art_hash=sha(ART)
font_manifest=json.loads((FONTS/'manifest.json').read_text())
font_files={'title':'P052-Bold.otf','verse':'SanctificationP052-Medium.otf','reference':'SanctificationP052-Medium.otf'}
for name in set(font_files.values()):
assert sha(FONTS/name)==font_manifest['files'][name]['sha256']
(P/'font-cache').mkdir(exist_ok=True)
(P/'fonts.conf').write_text(f'<fontconfig><dir>{FONTS}</dir><cachedir>{P/"font-cache"}</cachedir></fontconfig>')
env=dict(os.environ,FONTCONFIG_FILE=str(P/'fonts.conf'))
def ink(*args):return subprocess.check_output(['inkscape',*map(str,args)],env=env,text=True,stderr=subprocess.PIPE).strip()
def render(src,dst):ink(src,'--export-type=png',f'--export-filename={dst}','--export-width=2000','--export-height=2800')
def resolve(family,style):return Path(subprocess.check_output(['fc-match','-f','%{file}',f'{family}:style={style}'],env=env,text=True).strip()).resolve()
assert resolve('P052','Bold')==(FONTS/'P052-Bold.otf').resolve()
assert resolve('Sanctification P052','Medium')==(FONTS/'SanctificationP052-Medium.otf').resolve()
head='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="2000" height="2800" viewBox="0 0 2000 2800">'
defs='''<defs>
<linearGradient id="paper" x1="0" y1="0" x2="1" y2="1"><stop offset="0" stop-color="#fbf3df"/><stop offset=".5" stop-color="#f4ead4"/><stop offset="1" stop-color="#e8d4b0"/></linearGradient>
<linearGradient id="gold" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#f0d47d"/><stop offset=".48" stop-color="#bd8b31"/><stop offset="1" stop-color="#71501e"/></linearGradient>
<pattern id="weave" width="44" height="44" patternUnits="userSpaceOnUse"><path d="M0 11H44 M0 33H44 M11 0V44 M33 0V44" stroke="#9d783d" stroke-width="1" opacity=".045"/><path d="M22 7l7 15-7 15-7-15Z" fill="none" stroke="#806438" stroke-width="1" opacity=".07"/></pattern>
<pattern id="lapis-band" width="34" height="34" patternUnits="userSpaceOnUse"><path d="M17 2L32 17 17 32 2 17Z" fill="#173e59" stroke="#d7b35a" stroke-width="3"/><circle cx="17" cy="17" r="4" fill="url(#gold)"/></pattern>
<clipPath id="curtain-clip"><path d="M-10-10 H770 C734 204 694 395 650 585 C610 770 566 972 522 1170 C474 1388 426 1604 378 1818 C338 2000 302 2190 286 2380 C276 2510 304 2640 412 2810 H-10Z"/></clipPath>
</defs>'''
base='<image xlink:href="../../source/art-master.png" width="2000" height="2800"/>'
frame='''<g id="legendary-frame">
<rect x="14" y="14" width="1972" height="2772" rx="34" fill="none" stroke="#2c2115" stroke-width="28"/>
<rect x="25" y="25" width="1950" height="2750" rx="27" fill="none" stroke="url(#gold)" stroke-width="14"/>
<rect x="43" y="43" width="1914" height="2714" rx="20" fill="none" stroke="#173e59" stroke-width="10"/>
<rect x="55" y="55" width="1890" height="2690" rx="15" fill="none" stroke="#d7b35a" stroke-width="4"/>
<path d="M68 260V68H260 M1740 68H1932V260 M68 2540V2732H260 M1740 2732H1932V2540" fill="none" stroke="#9b6d26" stroke-width="6"/>
<g fill="url(#gold)" stroke="#533810" stroke-width="3"><path d="M68 68l14 14-14 14-14-14Z"/><path d="M1932 68l14 14-14 14-14-14Z"/><path d="M68 2732l14 14-14 14-14-14Z"/><path d="M1932 2732l14 14-14 14-14-14Z"/></g>
<rect x="1906" y="430" width="27" height="255" fill="url(#lapis-band)" opacity=".95"/><rect x="1906" y="2115" width="27" height="255" fill="url(#lapis-band)" opacity=".95"/>
</g>'''
title_path='M1110 66 H1888 L1938 116 V320 L1895 364 H1110 L1060 314 V116 Z'
verse_path='M205 2075 H1892 Q1942 2075 1942 2125 V2715 Q1942 2765 1892 2765 H205 Q164 2765 164 2724 V2116 Q164 2075 205 2075 Z'
title_inner='<path d="M1125 84 H1878 L1918 124 V310 L1884 344 H1124 L1080 302 V126 Z" fill="none" stroke="#9b732b" stroke-width="3"/><path d="M1326 312H1438 M1562 312H1674" stroke="#98702a" stroke-width="4"/><path d="M1500 299l13 13-13 13-13-13Z" fill="url(#gold)" stroke="#654516" stroke-width="2"/>'
verse_inner='<path d="M222 2095 H1882 Q1922 2095 1922 2135 V2705 Q1922 2745 1882 2745 H220 Q184 2745 184 2709 V2131 Q184 2095 222 2095Z" fill="none" stroke="#9b732b" stroke-width="3"/><path d="M1138 2150H1268 M1372 2150H1502" stroke="#98702a" stroke-width="4"/><path d="M1320 2137l13 13-13 13-13-13Z" fill="url(#gold)" stroke="#654516" stroke-width="2"/><path d="M1148 2705H1273 M1367 2705H1492" stroke="#98702a" stroke-width="4"/><path d="M1320 2692l13 13-13 13-13-13Z" fill="url(#gold)" stroke="#654516" stroke-width="2"/><path d="M1880 2180v120 M1880 2538v120" stroke="#173e59" stroke-width="7"/><path d="M1863 2180h34v120h-34z M1863 2538h34v120h-34z" fill="url(#lapis-band)" stroke="#8c6827" stroke-width="3"/>'
def panel(path,inner,ident):return f'<g id="{ident}"><path d="{path}" fill="url(#paper)" stroke="#5f431d" stroke-width="10"/><path d="{path}" fill="url(#weave)" stroke="url(#gold)" stroke-width="5"/>{inner}</g>'
panels=panel(title_path,title_inner,'title-backing')+panel(verse_path,verse_inner,'verse-backing')
curtain=f'<g id="curtain-foreground" clip-path="url(#curtain-clip)"><image xlink:href="../../source/art-master.png" width="2000" height="2800"/></g>'
(P/'foreground-curtain.svg').write_text(head+defs+curtain+'</svg>');render(P/'foreground-curtain.svg',P/'foreground-curtain.png')
fg=Image.open(P/'foreground-curtain.png').convert('RGBA')
fa=np.asarray(fg.getchannel('A'))
assert fa.max()==255 and fa.min()==0
rows=[
('title','MOSES',1500,244,138,'P052',700),
('verse-0','And there has not arisen',1320,2276,80,'Sanctification P052',500),
('verse-1','a prophet since in Israel',1320,2370,80,'Sanctification P052',500),
('verse-2','like Moses, whom the LORD',1320,2464,80,'Sanctification P052',500),
('verse-3','knew face to face',1320,2558,80,'Sanctification P052',500),
('reference','Deuteronomy 34:10 • ESV',1320,2655,57,'Sanctification P052',500),
]
texts=''.join(f'<text id="{ident}" x="{x}" y="{y}" font-family="{family}" font-weight="{weight}" font-size="{size}" text-anchor="middle" fill="#263f50">{escape(text)}</text>' for ident,text,x,y,size,family,weight in rows)
(P/'text-preview.svg').write_text(head+texts+'</svg>');render(P/'text-preview.svg',P/'text-preview.png')
text_image=Image.open(P/'text-preview.png').convert('RGBA');ta=np.asarray(text_image.getchannel('A'))
assert not np.any((ta>0)&(fa>0))
(P/'border-backing-preview.svg').write_text(head+defs+frame+panels+'</svg>');render(P/'border-backing-preview.svg',P/'border-backing-preview.png')
backing=np.asarray(Image.open(P/'border-backing-preview.png').convert('RGBA').getchannel('A'))
checks=[];verse_bounds=[]
for ident,text,x,y,size,family,weight in rows:
node=next(v for v in texts.split('</text>') if f'id="{ident}"' in v)+'</text>'
src=P/(ident+'-ink.svg');dst=P/(ident+'-ink.png');src.write_text(head+node+'</svg>');render(src,dst)
alpha=np.asarray(Image.open(dst).convert('RGBA').getchannel('A'));ys,xs=np.where(alpha>0);assert len(xs)
bounds=[int(xs.min()),int(ys.min()),int(xs.max()+1),int(ys.max()+1)]
safe=[1100,90,1905,340] if ident=='title' else [570,2165,1900,2690]
assert safe[0]<=bounds[0] and safe[1]<=bounds[1] and bounds[2]<=safe[2] and bounds[3]<=safe[3],(ident,bounds,safe)
assert np.all(backing[alpha>0]==255),ident
assert not np.any((alpha>0)&(fa>0)),ident
checks.append({'id':ident,'text':text,'baseline':y,'font':family,'weight':weight,'size':size,'inkBounds':bounds,'safeBounds':safe,'glyphPixelsOutsideOpaqueBacking':0,'foregroundIntersectionPixels':0})
if ident.startswith('verse-'):verse_bounds.append(bounds)
assert ' '.join(c['text'] for c in checks if c['id'].startswith('verse-'))==json.loads((REV/'card.json').read_text())['excerpt']
assert checks[-1]['text']==json.loads((REV/'card.json').read_text())['referenceDisplay']
union=[min(b[0] for b in verse_bounds),min(b[1] for b in verse_bounds),max(b[2] for b in verse_bounds),max(b[3] for b in verse_bounds)]
upper=2163;ref_top=2613;above=union[1]-upper;below=ref_top-union[3]
assert min(above,below)>=35 and abs(above-below)<=4,(above,below)
for name,include_curtain in [('composed-preview',True),('without-curtain',False)]:
body=base+frame+panels+(curtain if include_curtain else '')+texts
src=P/(name+'.svg');src.write_text(head+defs+body+'</svg>');render(src,P/(name+'-2000.png'))
master=Image.open(P/(name+'-2000.png')).convert('RGB')
master.resize((1000,1400),Image.Resampling.LANCZOS).save(P/(name+'-1000.png'))
master.resize((500,700),Image.Resampling.LANCZOS).save(P/(name+'-500.png'))
# Compare the structural effect of the attached curtain.
board=Image.new('RGB',(1000,750),'#11161c');draw=ImageDraw.Draw(board)
for i,(label,path) in enumerate([('Backing and frame alone',P/'without-curtain-1000.png'),('Threshold curtain overlap',P/'composed-preview-1000.png')]):
draw.text((i*500+12,12),label,fill='#f4ead4')
image=Image.open(path).convert('RGB');image.thumbnail((480,672));board.paste(image,(i*500+10,45))
board.save(P/'curtain-comparison.png')
# A focused junction comparison at master crop.
detail=Image.new('RGB',(1200,620),'#11161c');draw=ImageDraw.Draw(detail)
for i,(label,path) in enumerate([('Without foreground',P/'without-curtain-2000.png'),('Curtain over frame/backing',P/'composed-preview-2000.png')]):
draw.text((i*600+12,12),label,fill='#f4ead4')
image=Image.open(path).convert('RGB').crop((0,1780,900,2800));image.thumbnail((575,545));detail.paste(image,(i*600+12,52))
detail.save(P/'curtain-junction-detail.png')
frame_alpha=np.asarray(Image.open(P/'border-backing-preview.png').convert('RGBA').getchannel('A'))
foreground_frame_overlap=int(np.count_nonzero((fa>0)&(frame_alpha>0)))
report={
'status':'passed',
'scope':'Provisional Legendary Normal composition only',
'canvas':[2000,2800],
'sourceArtwork':{'path':str(ART.relative_to(REPO)),'sha256':art_hash,'unchanged':sha(ART)==art_hash},
'template':{
'governingIdea':'Tent threshold',
'titleBackingPath':title_path,
'verseBackingPath':verse_path,
'compositionOrder':['base-art','frame-and-backings','attached-curtain-foreground','deterministic-text'],
'curtainContour':'foreground-curtain.svg',
'curtainAlphaBounds':list(Image.fromarray(fa).getbbox()),
'curtainFrameOrBackingOverlapPixels':foreground_frame_overlap,
},
'typography':{
'fontManifestSHA256':sha(FONTS/'manifest.json'),
'checks':checks,
'verseInkUnion':union,
'upperFlourishToVerseInk':above,
'verseInkToReferenceLineBox':below,
'centeringDifference':abs(above-below),
'lineBaselineGap':94,
},
'structuralChecks':{
'curtainTextIntersectionPixels':int(np.count_nonzero((ta>0)&(fa>0))),
'glyphPixelsOutsideOpaqueBacking':0,
'artworkSHA256Unchanged':True,
},
'notPerformed':['Borderless/Textless/Boundless composition','Production finish masks','Production text masks','Harness fixture installation','GPU moving-light validation','Final card approval'],
'staticReview':'pending user review'
}
(P/'preview-validation.json').write_text(json.dumps(report,indent=2)+'\n')
assert sha(ART)==art_hash
print(json.dumps({'status':'passed','preview':str((P/'composed-preview-1000.png').relative_to(REPO)),'curtainOverlapPixels':foreground_frame_overlap,'spacing':[above,below]},indent=2))

View File

@@ -0,0 +1 @@
<fontconfig><dir>/home/dkzver/docker/sanctification/fonts</dir><cachedir>/home/dkzver/docker/sanctification/in-progress/cards/BP-001-moses/revisions/v03/review/layout-preview-v1/font-cache</cachedir></fontconfig>

View File

@@ -0,0 +1,193 @@
{
"status": "passed",
"scope": "Provisional Legendary Normal composition only",
"canvas": [
2000,
2800
],
"sourceArtwork": {
"path": "in-progress/cards/BP-001-moses/revisions/v03/source/art-master.png",
"sha256": "73f933cf34719dfda09b719376948bcf072bec504a88329b5a22e4ac1ed76d85",
"unchanged": true
},
"template": {
"governingIdea": "Tent threshold",
"titleBackingPath": "M1110 66 H1888 L1938 116 V320 L1895 364 H1110 L1060 314 V116 Z",
"verseBackingPath": "M205 2075 H1892 Q1942 2075 1942 2125 V2715 Q1942 2765 1892 2765 H205 Q164 2765 164 2724 V2116 Q164 2075 205 2075 Z",
"compositionOrder": [
"base-art",
"frame-and-backings",
"attached-curtain-foreground",
"deterministic-text"
],
"curtainContour": "foreground-curtain.svg",
"curtainAlphaBounds": [
0,
0,
769,
2800
],
"curtainFrameOrBackingOverlapPixels": 283408
},
"typography": {
"fontManifestSHA256": "ef68ee6393981d54ca068a950f21c53b374d20e6e46c21c788f36380d3aae178",
"checks": [
{
"id": "title",
"text": "MOSES",
"baseline": 244,
"font": "P052",
"weight": 700,
"size": 138,
"inkBounds": [
1251,
148,
1746,
247
],
"safeBounds": [
1100,
90,
1905,
340
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
},
{
"id": "verse-0",
"text": "And there has not arisen",
"baseline": 2276,
"font": "Sanctification P052",
"weight": 500,
"size": 80,
"inkBounds": [
886,
2217,
1755,
2278
],
"safeBounds": [
570,
2165,
1900,
2690
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
},
{
"id": "verse-1",
"text": "a prophet since in Israel",
"baseline": 2370,
"font": "Sanctification P052",
"weight": 500,
"size": 80,
"inkBounds": [
902,
2311,
1739,
2393
],
"safeBounds": [
570,
2165,
1900,
2690
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
},
{
"id": "verse-2",
"text": "like Moses, whom the LORD",
"baseline": 2464,
"font": "Sanctification P052",
"weight": 500,
"size": 80,
"inkBounds": [
813,
2405,
1827,
2477
],
"safeBounds": [
570,
2165,
1900,
2690
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
},
{
"id": "verse-3",
"text": "knew face to face",
"baseline": 2558,
"font": "Sanctification P052",
"weight": 500,
"size": 80,
"inkBounds": [
1019,
2499,
1620,
2560
],
"safeBounds": [
570,
2165,
1900,
2690
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
},
{
"id": "reference",
"text": "Deuteronomy 34:10 \u2022 ESV",
"baseline": 2655,
"font": "Sanctification P052",
"weight": 500,
"size": 57,
"inkBounds": [
991,
2614,
1649,
2672
],
"safeBounds": [
570,
2165,
1900,
2690
],
"glyphPixelsOutsideOpaqueBacking": 0,
"foregroundIntersectionPixels": 0
}
],
"verseInkUnion": [
813,
2217,
1827,
2560
],
"upperFlourishToVerseInk": 54,
"verseInkToReferenceLineBox": 53,
"centeringDifference": 1,
"lineBaselineGap": 94
},
"structuralChecks": {
"curtainTextIntersectionPixels": 0,
"glyphPixelsOutsideOpaqueBacking": 0,
"artworkSHA256Unchanged": true
},
"notPerformed": [
"Borderless/Textless/Boundless composition",
"Production finish masks",
"Production text masks",
"Harness fixture installation",
"GPU moving-light validation",
"Final card approval"
],
"staticReview": "pending user review"
}