Skip to content

Commit fba9a56

Browse files
Merge pull request #82 from open-coder-ai/docs/brand-assets
docs: add the brand assets — social preview card, mark, and their generator
2 parents 6b93a36 + 423815d commit fba9a56

6 files changed

Lines changed: 293 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
<img src="https://raw.githubusercontent.com/open-coder-ai/agentseam/main/docs/assets/logo.svg"
2+
alt="agentseam logo: five unevenly spaced vendor lines converging through a stitched seam into five evenly spaced parallel lines"
3+
width="104" align="right">
4+
15
# agentseam
26

37
**The primitives layer for every coding agent — one handler API over per-agent hooks,

docs/assets/gen_brand_assets.py

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
"""Render agentseam's brand assets: the GitHub social preview card and the mark.
2+
3+
Run from this directory:
4+
5+
pip install cairosvg # asset tooling only
6+
python gen_brand_assets.py
7+
8+
Writes social-preview.svg/.png (1280x640, GitHub's social-preview size) and
9+
logo.svg/logo-512.png (512x512) beside this file.
10+
11+
cairosvg is NOT a dependency of agentseam. The package's runtime path is stdlib-only and
12+
`dependencies` in pyproject.toml stays empty; this script is design tooling a maintainer
13+
runs by hand when the artwork changes, and its output is committed.
14+
15+
The figure states the project's claim, so it has to be true to it. Two invariants, both
16+
enforced by the gap tables below and asserted at render time:
17+
18+
* Nothing crosses. agentseam normalizes the *shape* of a vendor's hook dialect; it does
19+
not reorder anything. Crossing lines would say otherwise.
20+
* Every pair converges: each gap on the dialect side is wider than the matching gap on
21+
the envelope side. A pair that spread apart would read as fan-out, the opposite of
22+
what the layer does.
23+
24+
Text renders in Geist Mono, matching the sibling project's cards. Where that font is
25+
absent the renderer substitutes another monospace face; re-render on a machine that has
26+
it before committing a changed card.
27+
"""
28+
29+
import cairosvg
30+
31+
NAVY = "#0D1626"
32+
GOLD = "#D9B45C"
33+
DIM = "#8A7340"
34+
COOL = "#9FB0C4"
35+
FONT = "Geist Mono"
36+
37+
# Card: 12 dialect lines, one per adapter in src/agentseam/adapters/. Irregular gaps
38+
# (heterogeneous vendor surfaces), but every one exceeds the envelope's 30.5px gap.
39+
GAPS = [0, 32, 45, 34, 47, 33, 43, 36, 46, 35, 41, 40]
40+
# Ragged left edge: the dialects do not start from a tidy margin either.
41+
RAG = [0, 34, 12, 46, 6, 28, 18, 52, 10, 38, 22, 44]
42+
# The mark carries only five lines, so its minimum gap has to clear a wider 44px envelope.
43+
LOGO_GAPS = [0, 1.76, 1.00, 1.36, 1.08]
44+
45+
46+
def spread(y0, y1, gaps):
47+
"""n points from y0 to y1 inclusive; gaps[1:] are the n-1 intervals between them."""
48+
intervals = gaps[1:]
49+
total = sum(intervals)
50+
out = [float(y0)]
51+
acc = 0.0
52+
for gap in intervals:
53+
acc += gap
54+
out.append(y0 + (y1 - y0) * (acc / total))
55+
return out
56+
57+
58+
def check_invariants(left, right):
59+
"""Fail loudly rather than ship a figure that contradicts the claim it illustrates."""
60+
lg = [left[i + 1] - left[i] for i in range(len(left) - 1)]
61+
rg = [right[i + 1] - right[i] for i in range(len(right) - 1)]
62+
assert all(g > 0 for g in lg + rg), "lines cross: agentseam does not reorder"
63+
assert all(a > b for a, b in zip(lg, rg)), "a pair diverges: the figure must converge"
64+
65+
66+
def seam(
67+
x0,
68+
x1,
69+
sx,
70+
ytop,
71+
ybot,
72+
ly0,
73+
ly1,
74+
n,
75+
swl,
76+
swr,
77+
node,
78+
cap=None,
79+
cap_y=None,
80+
cap_size=11,
81+
opl=0.36,
82+
stub=3.0,
83+
rag=1.0,
84+
gaps=None,
85+
):
86+
"""Uneven dialect lines on the left, a stitched seam at sx, an even envelope right."""
87+
ry = spread(ytop, ybot, [1] * n) # ordered, even: the canonical envelope
88+
ly = spread(ly0, ly1, (gaps or GAPS)[:n]) # uneven, wider: the vendor dialects
89+
check_invariants(ly, ry)
90+
parts = []
91+
for i in range(n):
92+
parts.append(
93+
f'<line x1="{x0 + RAG[i % len(RAG)] * rag:.1f}" y1="{ly[i]:.1f}" '
94+
f'x2="{sx:.1f}" y2="{ry[i]:.1f}" stroke="{GOLD}" stroke-width="{swl}" '
95+
f'stroke-opacity="{opl}" stroke-linecap="round"/>'
96+
)
97+
for i in range(n):
98+
parts.append(
99+
f'<line x1="{sx:.1f}" y1="{ry[i]:.1f}" x2="{x1:.1f}" y2="{ry[i]:.1f}" '
100+
f'stroke="{GOLD}" stroke-width="{swr}" stroke-opacity="0.95" stroke-linecap="round"/>'
101+
)
102+
# The seam itself: one continuous join, not a line broken by the stitches.
103+
parts.append(
104+
f'<line x1="{sx:.1f}" y1="{ytop - node * stub:.1f}" x2="{sx:.1f}" '
105+
f'y2="{ybot + node * stub:.1f}" stroke="{GOLD}" stroke-width="{swr}" stroke-opacity="0.42"/>'
106+
)
107+
# Each crossing is a stitch: a node where the two planes are held together.
108+
for i in range(n):
109+
parts.append(
110+
f'<rect x="{sx - node:.1f}" y="{ry[i] - node:.1f}" width="{node * 2:.1f}" '
111+
f'height="{node * 2:.1f}" transform="rotate(45 {sx:.1f} {ry[i]:.1f})" fill="{GOLD}"/>'
112+
)
113+
if cap:
114+
parts.append(
115+
f'<text x="{(x0 + x1) / 2:.1f}" y="{cap_y}" font-family="{FONT}" '
116+
f'font-size="{cap_size}" letter-spacing="3.6" fill="{DIM}" text-anchor="middle">{cap}</text>'
117+
)
118+
return "\n ".join(parts)
119+
120+
121+
def corners(w, h, m=44, length=16, sw=1.4):
122+
return "\n ".join(
123+
f'<path d="M {x + dx * length} {y} L {x} {y} L {x} {y + dy * length}" fill="none" '
124+
f'stroke="{GOLD}" stroke-opacity="0.30" stroke-width="{sw}"/>'
125+
for (x, y, dx, dy) in ((m, m, 1, 1), (w - m, m, -1, 1), (m, h - m, 1, -1), (w - m, h - m, -1, -1))
126+
)
127+
128+
129+
W, H = 1280, 640
130+
S = 512
131+
CARD_ALT = (
132+
"agentseam — the primitives layer for every coding agent: one handler API over "
133+
"per-agent hooks, instruction files, plugin packaging, and config. Twelve unevenly "
134+
"spaced vendor hook dialects converge through a stitched seam into one evenly spaced "
135+
"canonical envelope."
136+
)
137+
LOGO_ALT = (
138+
"agentseam logo: five unevenly spaced vendor lines converging through a stitched seam "
139+
"into five evenly spaced parallel lines."
140+
)
141+
142+
143+
def text(x, y, size, fill, body, weight=None, tracking=None):
144+
attrs = [f'x="{x}"', f'y="{y}"', f'font-family="{FONT}"', f'font-size="{size}"']
145+
if weight:
146+
attrs.append(f'font-weight="{weight}"')
147+
if tracking is not None:
148+
attrs.append(f'letter-spacing="{tracking}"')
149+
attrs.append(f'fill="{fill}"')
150+
return "<text " + " ".join(attrs) + f">{body}</text>"
151+
152+
153+
def build_card():
154+
body = [
155+
f'<rect width="{W}" height="{H}" fill="{NAVY}"/>',
156+
corners(W, H),
157+
text(88, 236, 13, DIM, "PRIMITIVES LAYER", tracking=5.2),
158+
text(84, 322, 78, GOLD, "agentseam", weight=700, tracking=-1.5),
159+
f'<line x1="88" y1="356" x2="566" y2="356" stroke="{GOLD}" stroke-opacity="0.28" stroke-width="1.2"/>',
160+
text(88, 398, 19, COOL, "One handler API over per-agent hooks,"),
161+
text(88, 426, 19, COOL, "instruction files, plugin packaging, config."),
162+
text(88, 524, 12, DIM, "12 ADAPTERS &#183; STDLIB-ONLY &#183; APACHE-2.0", tracking=3.4),
163+
seam(
164+
664,
165+
1192,
166+
930,
167+
152,
168+
488,
169+
104,
170+
536,
171+
12,
172+
1.6,
173+
2.0,
174+
4.2,
175+
cap="VENDOR DIALECTS &#8594; CANONICAL ENVELOPE",
176+
cap_y=576,
177+
),
178+
]
179+
return (
180+
f'<svg xmlns="http://www.w3.org/2000/svg" width="{W}" height="{H}" viewBox="0 0 {W} {H}"\n'
181+
f' role="img" aria-label="{CARD_ALT}">\n ' + "\n ".join(body) + "\n</svg>"
182+
)
183+
184+
185+
def build_logo():
186+
mark = seam(
187+
96,
188+
416,
189+
252,
190+
168,
191+
344,
192+
126,
193+
386,
194+
5,
195+
5.0,
196+
6.5,
197+
9,
198+
opl=0.52,
199+
stub=1.8,
200+
rag=0.55,
201+
gaps=LOGO_GAPS,
202+
)
203+
return (
204+
f'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {S} {S}" role="img"\n'
205+
f' aria-label="{LOGO_ALT}">\n'
206+
f' <rect width="{S}" height="{S}" rx="104" fill="{NAVY}"/>\n ' + mark + "\n</svg>"
207+
)
208+
209+
210+
if __name__ == "__main__":
211+
card, logo = build_card(), build_logo()
212+
for name, source in (("social-preview", card), ("logo", logo)):
213+
with open(f"{name}.svg", "w", encoding="utf-8") as fh:
214+
fh.write(source)
215+
cairosvg.svg2png(bytestring=card.encode(), write_to="social-preview.png", output_width=W, output_height=H)
216+
cairosvg.svg2png(bytestring=logo.encode(), write_to="logo-512.png", output_width=S, output_height=S)
217+
print("rendered social-preview.svg/.png and logo.svg/logo-512.png")

docs/assets/logo-512.png

12.7 KB
Loading

docs/assets/logo.svg

Lines changed: 20 additions & 0 deletions
Loading

docs/assets/social-preview.png

42 KB
Loading

docs/assets/social-preview.svg

Lines changed: 52 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)