From 7dfce0e128c4dede2286386df273be4227ed0031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:58:54 +0200 Subject: [PATCH 1/2] assets: isolate VDM lettering and add matching Theory letterforms --- NOTICE.md | 2 +- web/static/BRAND-NOTICE.txt | 8 ++++++-- web/static/wordmark/development.webp | Bin 0 -> 6350 bytes web/static/wordmark/h.webp | Bin 0 -> 666 bytes web/static/wordmark/r.webp | Bin 0 -> 850 bytes web/static/wordmark/vast.webp | Bin 0 -> 2674 bytes web/static/wordmark/y.webp | Bin 0 -> 966 bytes 7 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 web/static/wordmark/development.webp create mode 100644 web/static/wordmark/h.webp create mode 100644 web/static/wordmark/r.webp create mode 100644 web/static/wordmark/vast.webp create mode 100644 web/static/wordmark/y.webp diff --git a/NOTICE.md b/NOTICE.md index 75ea700..210f095 100644 --- a/NOTICE.md +++ b/NOTICE.md @@ -8,4 +8,4 @@ The built website uses MathJax 3.2.2 (Apache-2.0) for SVG mathematical typesetti Python build dependencies retain their own licenses: Mistune (BSD-3-Clause), Jinja2 (BSD-3-Clause), PyYAML (MIT), Pillow (HPND), Beautiful Soup (MIT), and Playwright (Apache-2.0). They are development/build dependencies, not copies of the theory. -The VDM wordmark is a resized derivative of the author-supplied branding. The small mark and favicon use official VDM branding: the build requests https://www.vdm.io/VDM.png first and can use the official organization's GitHub avatar if that endpoint rejects acquisition. The selected source and digest are recorded, not silently substituted. Brand assets are excluded from the prose and code licenses; no trademark or endorsement rights are granted. +The VDM Theory wordmark isolates the original blue lettering from the author-supplied branding, removes the mosaic background, and adds matching THEORY lettering on the same baseline. The asset uses source glyph construction, not a separately distributed font. The small mark and favicon use official VDM branding: the build requests https://www.vdm.io/VDM.png first and can use the official organization's GitHub avatar if that endpoint rejects acquisition. The selected source and digest are recorded, not silently substituted. Brand assets are excluded from the prose and code licenses; no trademark or endorsement rights are granted. diff --git a/web/static/BRAND-NOTICE.txt b/web/static/BRAND-NOTICE.txt index 07b6683..d264d29 100644 --- a/web/static/BRAND-NOTICE.txt +++ b/web/static/BRAND-NOTICE.txt @@ -1,6 +1,10 @@ VDM branding identifies this official Vast Development Method publication. -wordmark.webp is a resized derivative of vast_development_method.jpg supplied -by the publication's originator. +The wordmark/ assets isolate blue lettering from the originator-supplied +vast_development_method.jpg. The homepage composes them into one accessible, +transparent, single-line SVG wordmark: VAST DEVELOPMENT METHOD THEORY. +Existing letter shapes are reused; the R and Y extend the source construction. +There is no separately loaded font, no mosaic backdrop, and no detached caption. +The SVG is a layout for raster lettering; it is not represented as a vector font. The small mark and favicon are derived from official VDM branding. The build first requests https://www.vdm.io/VDM.png. When that endpoint rejects automated diff --git a/web/static/wordmark/development.webp b/web/static/wordmark/development.webp new file mode 100644 index 0000000000000000000000000000000000000000..df38c2363c2365db3f1f1fe805caade12c2a3dfb GIT binary patch literal 6350 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/web/static/wordmark/r.webp b/web/static/wordmark/r.webp new file mode 100644 index 0000000000000000000000000000000000000000..5a16fe520f1af7534e191077ae52eb99bef84c02 GIT binary patch literal 850 zcmV-Y1Fig0Nk&FW0{{S5MM6+kP&iCI0{{RoEWi^GC&4PVZ6)*Ea4Hal{xk0KO8|GP z!6pE}By;y65$HloigEM03*$(#QsE9af+a@6;HKYQib<_)PrhIO=U1!@pf+d<(18v_ zKoWoe*y*uo5-hv-#>BJ!Smpgsp(FvXJzy7i_@_PJ#d`*iWczYGE}z+_-kslLqGhj_a*M$ zed*0dW8f$#`v^M)f`O84+ihD(2Ke*+UUy>QR2V;}-0=x8^<*fFrK!vEIVJHV3sY(C;+7#x=yBrQ12cbCZ4qkvUCv#= zpH#J&dQ#UV&0XBQ{HgS(rhZG8Ik7GkQopq+ctx*7ntDo=hS+P|L?5&R_YQFT0H;Js zoy6c3mR>&g>Jw@A>I18|Ai)}!aNmLSIKxBZTktBoI+N}~~ zP=Enq=!aq;b_KRdNh7c$5rSAr><5Eb9SV>LDMoM;3_$ACPJxM~T#6M+GO}6#1CZRI zAQ~YX>1q&I`p9D`?yB^*RbZEcYx1x*OGFgddmfu$%QTNf;}+Q~5kS|D36fEQeH?a2-tND80DwM|F#rGn literal 0 HcmV?d00001 diff --git a/web/static/wordmark/vast.webp b/web/static/wordmark/vast.webp new file mode 100644 index 0000000000000000000000000000000000000000..b00f6868a907453c802e90c24a9543537831f43f GIT binary patch literal 2674 zcmV-&3XSzrNk&F$3IG6CMM6+kP&iCo3IG5vtH2Wwhru?oZ6)*Fk(iX?sER6R!wc|; z%-z~x9NShJ++|4#kkpd~(?p80oy!L%wrwl?_-5VDNQ!8FzNyM^!196c@e4ZyP38>k6hHrO&YQN1c zFvI~$P=J~NUTA_c<}T?4g%S654tUr3fA^*b==u!MZw0gbfg28>dzy`Usc+~O0+*n< z1t4ETCkOiR@4rCeef%c39Q8q>mXN*(H#fQ`^iyl}L2>1JNbGGV%fE_Cic+#`F{Eku z3x+R@QqUQEYuj5ll5JZpm}o5}0Iju1GdC5mWMu@alF{~!_kVe!WLeqTS>ODBME@tC z{cny>o!|aLy!I|XK|J>#wLFu|FoTztt{V_ge*q z`2nx-Tpzovp7HP_m~}94;DZJj$ttZIRR>fw@^VnF81--ihF?~>nvyu4$AmGNu*O3^ zLX*H4y`dUKYqX=kRj84aW0NJDJL)DN4yPVM@kCJbLr@bbj;Rwhk-|D$4+=mmJ#@p; zgAci|cp~Y;eAtE4V966bH(to6K?RBM8V3zXkG4369kbYqV;uI67B#Ic8n2B3PxM5N z&y7D0_*Omnqn4kBq+q4_>7a?1TqTi??~PAn9@E;B54U#Ut!jF>Mf-4;%U!=?v6TZZG#;|K4&< zYgyX#(wK)t!G;bKKJEKm42h)Wr*`}D{;~aidOz~h1uxfke&mObNdBA06v6T%m&DT37a2|B!xpDf6Cfe}?l3t^I`um;_*RW1$e|@{Q(@wWGZ!K-} z%1b-)w<$EShchjgt@&Ym!&Evp1UT=S=H=JH zlaOA%e_7a;!8%y7tvGypi)qJq*%A+D6zo+Sp;^s zf&^EFS|Z=}LI(ZDkWoOo!miHrvXxk3Jf4Isu85)4sr<`TnJN;RSLiDnYWNn^OgaD8Ub{)8r@V% zUP)C0fn1Yl)X{WL z9eWv4bsylO7^`H&&m`vy02^9RwUcEfRS5!;F?8-F>X3oQyzCo~vCjKBu8oi^J>)v- zTCxDhS`|G}0NmXhYnJ@^A^bsJR-=mIFv)TflBMGYR6qf4p^geTEJN<662Mpm$d4g8 zWdTM7Ah<)eaH2^7)Ad-D5Cx^HRY4MRWEO=eIo5oF5MaV_~jZp!^ zAq2P~z^{#e_&x9$LGZu~0jffF{5awtuczT*RXY@5-kfgBZJr{p01%ae49KG^l)lPK z+wNKKy`9KF1pxvC*wYOcZ7&m#%Sa}x7@Vr z#`bROzJb|l;gUDr`O>BCK+Lc~5>5dhuVsZE@^Ho#XL zp#%Ur;*h~etT}?@r)c(TFV0HFeOF;Z)fByNX1n;RT3qN=aR$0(c@Z6DkK zcJTgsCay$fC2mTL+NE1=$3oo*fEaNGhq>f-7kVH*wNuN6kScT=H=Kxr0%E%62z3B> zkcr!J$Ywit00uzd3ZtXyhM^t&B)Wl7xq7Svh<2C!G#^C`4ufcZHrG)N1Sp!1BGh33 zS8MVi;1KP;wfz(sHv+A=J9^{YJ#YWvm{+aL`TcJm-2FwwVvlsvzmy=6z6)MFPWTt<;zuALo}45%D0i{e$Jaml4>F*P?Dvtk|c+Vh*&3?H;=iH z;bJO2f@Egq!E)GkDU2TG z?uHRP$lj-64ueMYQ|@jN;eeTssYgVQ0e8S7f?4*IWJCbwz|bBMc<_}*^z*0OT~86= za0ebnMCgFS;Ss^SD>W2X2YQSLa{wCA%i}#t=^A~E&YaLrSm1XpLS%lMe9+x&P?g oaNWO0_-62R;k)EtmpjbifPWn^nK{gSn)o#|hN`M-F#q2M0NkJQGynhq literal 0 HcmV?d00001 From 0d62c421d05dc4496510c5e2278cdadec48d9ac7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?eW=C9=98yn?= <5607939+Llewellynvdm@users.noreply.github.com> Date: Tue, 15 Sep 2026 18:00:15 +0200 Subject: [PATCH 2/2] fix: place Theory beside the source wordmark on a transparent background --- tests/test_branding.py | 53 +++++++++++++++++++++++++++++++++++++++ web/static/wordmark.css | 16 ++++++++++++ web/static/wordmark.webp | Bin 5566 -> 0 bytes web/templates/page.html | 21 +++++++++++++++- 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 tests/test_branding.py create mode 100644 web/static/wordmark.css delete mode 100644 web/static/wordmark.webp diff --git a/tests/test_branding.py b/tests/test_branding.py new file mode 100644 index 0000000..51e47e8 --- /dev/null +++ b/tests/test_branding.py @@ -0,0 +1,53 @@ +"""Source-derived wordmark transparency and responsive placement contracts. MIT.""" +from pathlib import Path +import unittest +from bs4 import BeautifulSoup +from PIL import Image + +ROOT = Path(__file__).resolve().parents[1] + + +class WordmarkTests(unittest.TestCase): + def test_all_lettering_assets_have_transparent_margins(self): + paths = sorted((ROOT / 'web/static/wordmark').glob('*.webp')) + self.assertEqual(len(paths), 5) + for path in paths: + with self.subTest(asset=path.name), Image.open(path) as image: + self.assertEqual(image.height, 80) + alpha = image.convert('RGBA').getchannel('A') + self.assertEqual(alpha.getextrema()[0], 0) + self.assertGreaterEqual(alpha.getextrema()[1], 250) + self.assertIsNone(alpha.crop((0, 0, image.width, 8)).getbbox()) + self.assertIsNone(alpha.crop((0, 72, image.width, 80)).getbbox()) + + def test_wordmark_has_one_accessible_label_and_no_caption(self): + soup = BeautifulSoup((ROOT / 'web/templates/page.html').read_text(), 'html.parser') + wordmark = soup.select_one('.wordmark') + self.assertIsNotNone(wordmark) + root = wordmark.find('svg', recursive=False) + self.assertIsNotNone(root) + self.assertEqual(root.get('role'), 'img') + self.assertEqual(root.find('title').text, 'Vast Development Method Theory') + self.assertIsNone(wordmark.find('span')) + self.assertEqual(root.get('viewbox'), '0 0 1200 80') + + def test_all_svg_image_references_exist(self): + soup = BeautifulSoup((ROOT / 'web/templates/page.html').read_text(), 'html.parser') + for image in soup.select('.wordmark image'): + href = image.get('href', '') + self.assertTrue(href.startswith('/assets/wordmark/')) + self.assertTrue((ROOT / 'web/static' / href.removeprefix('/assets/')).is_file()) + + def test_glyphs_share_one_baseline(self): + soup = BeautifulSoup((ROOT / 'web/templates/page.html').read_text(), 'html.parser') + for image in soup.select('.wordmark image'): + self.assertEqual(image.get('height'), '80') + self.assertIn(image.get('y'), (None, '0')) + + def test_wordmark_styles_are_scoped_and_loaded_after_the_theme(self): + css = (ROOT / 'web/static/wordmark.css').read_text() + for declaration in ('width: 100%', 'max-width: none', 'background: transparent', 'border: 0', 'padding: 0'): + self.assertIn(declaration, css) + soup = BeautifulSoup((ROOT / 'web/templates/page.html').read_text(), 'html.parser') + sheets = [node.get('href') for node in soup.select('link[rel="stylesheet"]')] + self.assertGreater(sheets.index('/assets/wordmark.css'), sheets.index('/assets/site.css')) diff --git a/web/static/wordmark.css b/web/static/wordmark.css new file mode 100644 index 0000000..80f6ae7 --- /dev/null +++ b/web/static/wordmark.css @@ -0,0 +1,16 @@ +/* Source-lettering wordmark only; the publication theme is unchanged. */ +.wordmark { + display: block; + width: 100%; + max-width: none; + margin: 4px 0 28px; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; +} +.wordmark > svg { + display: block; + width: 100%; + height: auto; +} diff --git a/web/static/wordmark.webp b/web/static/wordmark.webp deleted file mode 100644 index d96dd18c3ed3acc8fe3326250a2ee337d8d664e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5566 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 + @@ -50,7 +51,25 @@
- {% if article.path == 'index.md' %}
Vast Development MethodTHEORY
{% endif %} + {% if article.path == 'index.md' %}
+ +Vast Development Method Theory + + + + + + + + + + + + + + + +
{% endif %}
Read MarkdownDownload MarkdownSource
{{ article.rendered|safe }}
Evidence profile{{ article.meta.evidence }}How to read a claim