Create well-designed posters, layouts, and graphics using DrawBot with automatic enforcement of typography principles from Hochuli, Bringhurst, and MΓΌller-Brockmann...
Create professional posters, layouts, and graphics with automatic enforcement of design principles.
Before touching templates, commit to a bold creative direction:
Pick an extreme. Mediocrity is the enemy. Choose from:
| Direction | Characteristics |
|---|---|
| Swiss Modernism | Grid worship, Helvetica, mathematical precision, asymmetry |
| Punk Zine | Photocopied texture, ransom-note type, deliberate chaos |
| Japanese Minimalism | Vast emptiness, one perfect element, asymmetric balance |
| Constructivist | Diagonal energy, red/black, bold geometry, propaganda feel |
| Psychedelic | Melting forms, vibrating colors, horror vacui |
| Corporate Brutalism | Oversized type, stark contrast, confrontational |
| Art Deco | Geometric ornament, gold accents, symmetry, luxury |
| Editorial/Magazine | Pull quotes, drop caps, sophisticated grid breaks |
| Bauhaus | Primary colors, geometric shapes, form follows function |
| Vernacular/Found | Hand-painted signs, imperfect type, authentic roughness |
| Tech Noir | Dark themes, neon accents, high contrast, terminal aesthetic |
| Organic/Natural | Flowing forms, earth tones, hand-drawn elements |
Ask: "What's the ONE thing someone will remember 5 seconds after looking away?"
If you can't answer this, the design isn't ready.
Only after committing to direction β open design-vocabulary.md β map to technical choices β use the design system.
When user says something like "create a bold modern poster":
User says: "Make an elegant invitation for a gala"
Design thinking:
Technical mapping:
Result:
Activate when the user requests:
This skill automatically enforces:
CRITICAL: Always use the design system. Never write manual calculations.
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).parent.parent / "lib"))
import drawBot as db
from drawbot_grid import Grid
from drawbot_design_system import (
POSTER_SCALE, # or MAGAZINE_SCALE, BOOK_SCALE, REPORT_SCALE
get_output_path,
draw_wrapped_text,
setup_poster_page
)
# Page setup (creates canvas automatically)
WIDTH, HEIGHT, MARGIN = setup_poster_page("letter", margin_ratio=1/10)
# Grid (automatically reads canvas size)
grid = Grid.from_margins(
(-MARGIN, -MARGIN, -MARGIN, -MARGIN),
column_subdivisions=12,
row_subdivisions=16
)
# β
CORRECT: Grid coordinates
header = (*grid[(0, 14)], *grid*(12, 2)) # Full width, top 2 rows
# β WRONG: Manual calculations
header = (MARGIN, HEIGHT - 200, WIDTH - MARGIN*2, 150)
# β
CORRECT: Point-based wrapping
draw_wrapped_text(text, x, y, width, height, font, size)
# β WRONG: Character-count heuristics
wrapped = textwrap.wrap(text, width=70)
# β
CORRECT: Works on any machine
db.saveImage(str(get_output_path("output.pdf")))
# β WRONG: Hardcoded path
db.saveImage("/Users/you/...")
minimal_poster.py - Simple postertwo_column.py - Magazine layoutcard_layout.py - Color-coded cards../../examples/minimal_poster_example.py - 80-line working posterlongitudinalbench_poster_v7.py - 352-line production poster../../docs/design-system-usage.md - Complete usage guidelayout-design-principles.md - Grid theory, CRAP, decision matricestypography-style-guide.md - Hochuli's spacing, line length, readabilityprint-production-checklist.md - Bleed, CMYK, export settings../../assets/ - 1,807 textures| Context | Scale | Base | Ratio | When to Use |
|---|---|---|---|---|
| Poster | POSTER_SCALE | 18pt | 1.5 | Posters, displays |
| Magazine | MAGAZINE_SCALE | 11pt | 1.25 | Magazines, newsletters |
| Book | BOOK_SCALE | 11pt | 1.2 | Books, long-form |
| Report | REPORT_SCALE | 12pt | 1.25 | Reports, docs |
Access sizes:
scale = POSTER_SCALE
scale.caption # 12pt
scale.body # 18pt
scale.h3 # 27pt
scale.h2 # 40.5pt
scale.h1 # 60.75pt
scale.title # 91.125pt
Generate harmonious color palettes from a single base color:
from drawbot_design_system import (
generate_color_palette,
hex_to_rgb,
check_contrast_ratio,
get_accessible_text_color
)
# Generate palette from base color
base = hex_to_rgb("#2E86AB") # Ocean blue
palette = generate_color_palette(base, harmony="complementary")
# Returns: {'background': (light), 'text': (dark), 'accent': base, 'accent2': complement}
# Available harmonies:
# - "complementary": Base + opposite (high contrast)
# - "analogous": Base + neighbors (harmonious)
# - "triadic": Base + 2 evenly spaced (vibrant)
# - "split_complementary": Base + split opposite (balanced)
# - "monochromatic": Base + light/dark variations (subtle)
# Check accessibility
ratio, level = check_contrast_ratio(palette['text'], palette['background'])
print(f"Contrast: {ratio:.1f}:1 ({level})") # "Contrast: 8.2:1 (AAA)"
# Get accessible text for any background
text_color = get_accessible_text_color(palette['accent'])
Enable professional typography features:
from drawbot_design_system import (
set_opentype_features,
get_available_opentype_features
)
import drawBot as db
# Check what features a font supports
db.font("Adobe Garamond Pro")
features = get_available_opentype_features()
print(features) # {'liga': 'Standard ligatures', 'smcp': 'Small capitals', ...}
# Enable small caps + oldstyle figures
set_opentype_features(['smcp', 'onum'])
db.text("The Quick Brown Fox 1234", (x, y))
# Common features:
# - 'liga': Standard ligatures (fi, fl, ff)
# - 'smcp': Small capitals
# - 'onum': Oldstyle figures (varying heights)
# - 'tnum': Tabular figures (monospaced)
# - 'frac': Automatic fractions (1/2 β Β½)
# - 'ss01'-'ss20': Stylistic sets
Control variable font axes dynamically:
from drawbot_design_system import (
set_font_variation,
get_font_variation_axes
)
import drawBot as db
# Check available axes
db.font("Skia") # Or any variable font
axes = get_font_variation_axes()
print(axes) # {'wght': {'minValue': 100, 'maxValue': 900, ...}, ...}
# Set axis values
set_font_variation(wght=600, wdth=85) # Semi-bold, slightly condensed
db.text("Variable Font Text", (x, y))
# Common axes:
# - wght: Weight (100=thin, 400=regular, 700=bold, 900=black)
# - wdth: Width (50=condensed, 100=normal, 200=extended)
# - slnt: Slant (-90 to 90 degrees)
# - ital: Italic (0=upright, 1=italic)
# - opsz: Optical size (optimize for display vs text)
Set up print-ready documents with bleed:
from drawbot_design_system import (
setup_print_page,
validate_print_ready,
PRINT_PRESETS
)
import drawBot as db
# Set up page with bleed (US standard: 0.125")
specs = setup_print_page("letter", include_bleed=True)
# Draw background to FULL canvas (into bleed area)
db.fill(0.2, 0.4, 0.8)
db.rect(0, 0, specs['canvas_width'], specs['canvas_height'])
# Position content relative to trim + safe margin
content_x = specs['trim_x'] + specs['safe_margin']
content_y = specs['trim_y'] + specs['safe_margin']
# Use CMYK for print colors
db.cmykFill(0.6, 0.4, 0.4, 1.0) # Rich black
# Validate before export
is_valid, warnings = validate_print_ready()
for w in warnings:
print(w)
# See docs/print-production-checklist.md for complete guide
header = (*grid[(0, 14)], *grid*(12, 2)) # All columns, 2 rows
left = (*grid[(0, 1)], *grid*(5, 13)) # Cols 0-4
right = (*grid[(7, 1)], *grid*(5, 13)) # Cols 7-11
# Columns 5-6 = automatic gutter
section1 = (*grid[(0, 10)], *grid*(12, 3)) # Rows 10-12
section2 = (*grid[(0, 6)], *grid*(12, 3)) # Rows 6-8
section3 = (*grid[(0, 2)], *grid*(12, 3)) # Rows 2-4
| Content | Grid | Typography | Line Length |
|---|---|---|---|
| Poster | 12Γ16 | POSTER_SCALE | 20-30 CPL |
| Magazine | 12Γ8 | MAGAZINE_SCALE | 45-50 CPL |
| Book | 6Γ8 | BOOK_SCALE | 60-65 CPL |
| Report | 12Γ8 | REPORT_SCALE | 50-60 CPL |
Before finalizing code, verify:
lib/ directorysetup_poster_page() BEFORE gridGrid.from_margins()draw_wrapped_text() (not textwrap.wrap)get_output_path() (not hardcoded)β Hardcode page size in grid
β Use character counts for wrapping
β Approximate line height with fontSize
β Manual calculations instead of grid
β Truncate text with [:N]
β Hardcode absolute paths
β Let grid read canvas size β Use point-based wrapping β Use real font metrics β Use semantic grid coordinates β Draw all text that fits β Use portable path helpers
CRITICAL: These patterns make work look machine-generated. Avoid them:
β Helvetica Neue for everything β It's fine, but predictable. Try Akzidenz-Grotesk, Univers, or something unexpected. β Safe font pairings (Montserrat + Open Sans) β Too common. Be bolder. β Centered everything β Easy but lazy. Asymmetry creates energy. β Even text sizes (24pt, 18pt, 14pt) β Use the scale ratios; they create proper tension. β Justified text in narrow columns β Creates rivers of whitespace.
β Blue gradient on white β The default "tech startup" look. β Purple/pink gradients β Overused in AI-generated content. β Gray text on white (#666 on #fff) β Low contrast, looks washed out. β Rainbow gradients β Almost never appropriate. β Equal color distribution β Use 70-20-10, not 33-33-33.
β Perfect symmetry everywhere β Real design has controlled asymmetry. β Everything centered vertically AND horizontally β Creates static, lifeless compositions. β Uniform margins β Vary them intentionally; tension creates interest. β Clip art shapes (perfect circles, rounded rectangles) β Too geometric, too safe. β Stock photo compositions β If it looks like a template, it is.
If your design has 3+ of these, reconsider:
Make ONE bold choice that a template wouldn't:
templates/minimal_poster.py to ../../examples/ or your working directoryexamples/, update the import path to use .parent.parent instead of .parent.parent.parent.parent.parentget_output_path()uv run python your_file.pytemplates/two_column.py to ../../examples/templates/card_layout.py to ../../examples/grid.draw(show_index=True) before saveImage()grid.draw() for final output| Problem | Cause | Fix |
|---|---|---|
| Text overflows | Character-count wrapping | Use draw_wrapped_text() |
| Grid doesn't match | Created before newPage() |
Create page FIRST |
| Wrong sizes | Wrong scale for context | Use POSTER_SCALE for posters |
| Paths don't work | Hardcoded paths | Use get_output_path() |
See reference.md for detailed troubleshooting.
User: "Create a poster for an AI conference"
Response:
templates/minimal_poster.pyai_conference.pyuv run python examples/ai_conference.pyResult: Professional poster following all design principles automatically.
Start with templates, refer to examples and reference as needed:
templates/minimal_poster.pyexamples.md for patternsreference.md for API detailsfilters.md for images/textures (when needed)../../docs/ for theoryClaude loads resources progressively as needed (saves context).
No two designs should look the same. Before finalizing, ask:
Cycle through these to avoid convergence:
Fonts (never default to the same one):
Color temperature:
Layout energy:
DrawBot is capable of extraordinary creative work.
The design system handles the rulesβgrids, scales, metrics. That's the foundation.
But foundations are invisible. What people see is the vision on top.
Don't settle for "correct." Aim for unforgettable.
The difference between good and great:
Every poster should have that moment. Find it before you write code.
Trust the system. Then transcend it.
The design system makes it impossible to violate design principles. That's the floor, not the ceiling.
Hochuli gives you the rules. MΓΌller-Brockmann gives you the grid. You give it soul.