Add SVG cover art to SX Manifesto as s-expression
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m1s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 3m1s
Soviet constructivist poster with paper texture filters, grid lines, aged stain spots, and "(<x>)" symbol in red. Add missing SVG filter primitive tags to both server (html.py) and client (sx.js): feTurbulence, feColorMatrix, feBlend, feComponentTransfer, feFuncR/G/B/A, feDisplacementMap, feComposite, feFlood, feImage, feMorphology, feSpecularLighting, feDiffuseLighting, fePointLight, feSpotLight, feDistantLight. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1020,7 +1020,13 @@
|
||||
"img picture source iframe embed object param video audio track canvas map area " +
|
||||
"svg math path circle ellipse line polygon polyline rect g defs use text tspan " +
|
||||
"clipPath mask linearGradient radialGradient stop filter " +
|
||||
"feGaussianBlur feOffset feMerge feMergeNode animate animateTransform " +
|
||||
"feGaussianBlur feOffset feMerge feMergeNode " +
|
||||
"feTurbulence feColorMatrix feBlend " +
|
||||
"feComponentTransfer feFuncR feFuncG feFuncB feFuncA " +
|
||||
"feDisplacementMap feComposite feFlood feImage " +
|
||||
"feMorphology feSpecularLighting feDiffuseLighting " +
|
||||
"fePointLight feSpotLight feDistantLight " +
|
||||
"animate animateTransform " +
|
||||
"table thead tbody tfoot tr th td caption colgroup col " +
|
||||
"form fieldset legend label input button select option optgroup textarea output " +
|
||||
"datalist progress meter details summary dialog template slot"
|
||||
@@ -1040,7 +1046,13 @@
|
||||
var SVG_TAGS = makeSet(
|
||||
"svg path circle ellipse line polygon polyline rect g defs use text tspan " +
|
||||
"clipPath mask linearGradient radialGradient stop filter " +
|
||||
"feGaussianBlur feOffset feMerge feMergeNode animate animateTransform"
|
||||
"feGaussianBlur feOffset feMerge feMergeNode " +
|
||||
"feTurbulence feColorMatrix feBlend " +
|
||||
"feComponentTransfer feFuncR feFuncG feFuncB feFuncA " +
|
||||
"feDisplacementMap feComposite feFlood feImage " +
|
||||
"feMorphology feSpecularLighting feDiffuseLighting " +
|
||||
"fePointLight feSpotLight feDistantLight " +
|
||||
"animate animateTransform"
|
||||
);
|
||||
|
||||
var SVG_NS = "http://www.w3.org/2000/svg";
|
||||
|
||||
@@ -94,6 +94,11 @@ HTML_TAGS = frozenset({
|
||||
"g", "defs", "use", "text", "tspan", "clipPath", "mask",
|
||||
"linearGradient", "radialGradient", "stop", "filter",
|
||||
"feGaussianBlur", "feOffset", "feMerge", "feMergeNode",
|
||||
"feTurbulence", "feColorMatrix", "feBlend",
|
||||
"feComponentTransfer", "feFuncR", "feFuncG", "feFuncB", "feFuncA",
|
||||
"feDisplacementMap", "feComposite", "feFlood", "feImage",
|
||||
"feMorphology", "feSpecularLighting", "feDiffuseLighting",
|
||||
"fePointLight", "feSpotLight", "feDistantLight",
|
||||
"animate", "animateTransform",
|
||||
# Table
|
||||
"table", "thead", "tbody", "tfoot", "tr", "th", "td",
|
||||
|
||||
@@ -2439,6 +2439,106 @@ def _essay_sx_native() -> str:
|
||||
)
|
||||
|
||||
|
||||
def _manifesto_cover() -> str:
|
||||
"""SVG cover art for the SX Manifesto — Soviet constructivist poster style."""
|
||||
# Helper to generate grid lines
|
||||
def vlines(x1: int, x2: int, ys: list[int], attr: str = "") -> str:
|
||||
return " ".join(
|
||||
f'(line :x1 "{x1}" :y1 "{y}" :x2 "{x2}" :y2 "{y}"{attr})'
|
||||
for y in ys
|
||||
)
|
||||
|
||||
def hlines(y1: int, y2: int, xs: list[int], attr: str = "") -> str:
|
||||
return " ".join(
|
||||
f'(line :x1 "{x}" :y1 "{y1}" :x2 "{x}" :y2 "{y2}"{attr})'
|
||||
for x in xs
|
||||
)
|
||||
|
||||
return (
|
||||
'(div :class "flex justify-center mb-10"'
|
||||
' (svg :xmlns "http://www.w3.org/2000/svg" :viewBox "0 0 1200 1828"'
|
||||
' :width "400" :height "609" :class "rounded shadow-lg"'
|
||||
|
||||
# --- Defs: filters ---
|
||||
' (defs'
|
||||
' (filter :id "paper-texture"'
|
||||
' (feTurbulence :type "fractalNoise" :baseFrequency "0.65"'
|
||||
' :numOctaves "3" :stitchTiles "stitch" :result "noise")'
|
||||
' (feColorMatrix :type "saturate" :values "0" :in "noise" :result "grayNoise")'
|
||||
' (feBlend :in "SourceGraphic" :in2 "grayNoise" :mode "multiply" :result "blended")'
|
||||
' (feComponentTransfer :in "blended"'
|
||||
' (feFuncA :type "linear" :slope "1")))'
|
||||
' (filter :id "aged"'
|
||||
' (feTurbulence :type "turbulence" :baseFrequency "0.02"'
|
||||
' :numOctaves "4" :result "noise")'
|
||||
' (feDisplacementMap :in "SourceGraphic" :in2 "noise"'
|
||||
' :scale "2" :xChannelSelector "R" :yChannelSelector "G")))'
|
||||
|
||||
# --- Red background ---
|
||||
' (rect :width "1200" :height "1828" :fill "#d20f0f")'
|
||||
|
||||
# --- Red panel grid lines ---
|
||||
' (g :opacity "0.35"'
|
||||
+ " ".join(
|
||||
f' (line :x1 "{x}" :y1 "0" :x2 "{x}" :y2 "1828" :stroke "#b00" :stroke-width "3")'
|
||||
for x in [0, 300, 600, 900, 1200]
|
||||
)
|
||||
+ " ".join(
|
||||
f' (line :x1 "0" :y1 "{y}" :x2 "1200" :y2 "{y}" :stroke "#b00" :stroke-width "3")'
|
||||
for y in [0, 457, 914, 1371, 1828]
|
||||
)
|
||||
+ ')'
|
||||
|
||||
# --- White/cream inner panel ---
|
||||
' (rect :x "90" :y "70" :width "1020" :height "1688"'
|
||||
' :fill "#f5f0e8" :filter "url(#paper-texture)")'
|
||||
|
||||
# --- Subtle grid on white panel ---
|
||||
' (g :opacity "0.07" :stroke "#888" :stroke-width "1"'
|
||||
+ " ".join(
|
||||
f' (line :x1 "{x}" :y1 "70" :x2 "{x}" :y2 "1758")'
|
||||
for x in [90, 210, 330, 450, 570, 690, 810, 930, 1050, 1110]
|
||||
)
|
||||
+ " ".join(
|
||||
f' (line :x1 "90" :y1 "{y}" :x2 "1110" :y2 "{y}")'
|
||||
for y in [190, 310, 430, 550, 670, 790, 910, 1030, 1150, 1270, 1390, 1510, 1630, 1758]
|
||||
)
|
||||
+ ')'
|
||||
|
||||
# --- Aged stain spots ---
|
||||
' (ellipse :cx "200" :cy "1500" :rx "30" :ry "18" :fill "#c8b89a" :opacity "0.3")'
|
||||
' (ellipse :cx "980" :cy "1600" :rx "20" :ry "12" :fill "#c8b89a" :opacity "0.25")'
|
||||
' (ellipse :cx "150" :cy "900" :rx "15" :ry "10" :fill "#c8b89a" :opacity "0.2")'
|
||||
|
||||
# --- Title text ---
|
||||
' (text :x "600" :y "260" :font-family "Georgia, serif"'
|
||||
' :font-size "118" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "12" "THE SX")'
|
||||
' (text :x "600" :y "400" :font-family "Georgia, serif"'
|
||||
' :font-size "118" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "8" "MANIFESTO")'
|
||||
|
||||
# --- Symbol: (<x>) in red ---
|
||||
' (text :x "600" :y "720" :font-family "Georgia, serif"'
|
||||
' :font-size "200" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#d20f0f" "(<x>)")'
|
||||
|
||||
# --- Author names ---
|
||||
' (text :x "600" :y "980" :font-family "Georgia, serif"'
|
||||
' :font-size "95" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "6" "CARL MARKDOWN")'
|
||||
' (text :x "600" :y "1110" :font-family "Georgia, serif"'
|
||||
' :font-size "80" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "14" "AND")'
|
||||
' (text :x "600" :y "1250" :font-family "Georgia, serif"'
|
||||
' :font-size "95" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "6" "FRIEDRICH")'
|
||||
' (text :x "600" :y "1390" :font-family "Georgia, serif"'
|
||||
' :font-size "82" :font-weight "bold" :text-anchor "middle"'
|
||||
' :fill "#1a1a1a" :letter-spacing "4" "ANGLEBRACKETS")))'
|
||||
)
|
||||
|
||||
|
||||
def _essay_sx_manifesto() -> str:
|
||||
p = '(p :class "text-stone-600"'
|
||||
em = '(span :class "italic"'
|
||||
@@ -2454,8 +2554,11 @@ def _essay_sx_manifesto() -> str:
|
||||
f' :sx-select "#main-panel" :sx-swap "outerHTML" :sx-push-url "true"'
|
||||
f' :class "{L}" "{text}")')
|
||||
|
||||
cover = _manifesto_cover()
|
||||
|
||||
return (
|
||||
'(~doc-page :title "The SX Manifesto"'
|
||||
f' {cover}'
|
||||
' (p :class "text-stone-500 text-sm italic mb-8"'
|
||||
' "Carl Markdown and Friedrich Anglebrackets")'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user