Skip to main content

Brand-first slide deck library. Full creative control, zero abstraction tax.

Project description

openslides

Python 3.9+ License: MIT Tests

Brand-first Python slide deck generator. Create pitch decks, investor presentations, and sales slides with full creative control. Extract brand colors and fonts from any website, write HTML/CSS slides, export to PNG or PDF.

Generate professional slide decks programmatically. No templates, no themes, no fighting the framework.

openslides demo

from openslides import Brand, export, base_html

brand = Brand.from_domain("scaile.tech")  # Auto-extract colors, fonts, logo

def slide_hero():
    return f'''
    {base_html(brand)}
    <body style="background:{brand.background}; padding:80px;">
        <h1 style="font-family:'{brand.font_headline}'; font-size:72px; color:{brand.text};">
            Get into <span style="color:{brand.primary};">ChatGPT</span> answers.
        </h1>
    </body></html>
    '''

export([slide_hero()], "/tmp/my-deck/")  # → PNG files

Why openslides?

Most slide libraries force you into preset themes that never match your brand. You end up fighting the abstraction.

openslides is different:

  • Brand-first: Extract colors/fonts from any website, or define manually
  • Full control: You write HTML/CSS, the library just helps with boilerplate
  • No magic: Brand values are explicit in your code, not hidden in themes
  • ~300 lines: Simple enough to understand in 10 minutes

Install

pip install openslides
playwright install chromium

# Optional: for brand extraction from URLs
pip install aiohttp

Quick Start

Option 1: Extract brand from website

from openslides import Brand, export, base_html

# Auto-extract colors, fonts, logo from website
brand = Brand.from_domain("stripe.com")

print(brand.primary)        # "#635bff"
print(brand.font_headline)  # "Inter"

Option 2: Define brand manually

brand = Brand(
    primary="#054dfe",      # Main accent (CTAs, highlights)
    secondary="#15aebf",    # Secondary accent
    background="#fdfbf5",   # Slide background
    surface="#ffffff",      # Cards, elevated surfaces
    text="#191919",         # Primary text
    muted="#6b6b6b",        # Secondary text
    font_headline="Syne",   # Headlines
    font_body="Inter",      # Body text
)

Create slides

Each slide is a function returning HTML. Use f-strings to inject brand values:

def slide_hero():
    return f'''
    {base_html(brand)}
    <body style="background:{brand.background}; padding:80px;">
        <div style="font-size:12px; color:{brand.primary}; text-transform:uppercase; letter-spacing:2px;">
            The Problem
        </div>
        <h1 style="font-family:'{brand.font_headline}'; font-size:64px; color:{brand.text}; margin-top:20px;">
            Your buyers don't Google anymore.
            <span style="color:{brand.muted};">They ask ChatGPT.</span>
        </h1>
    </body></html>
    '''

def slide_solution():
    return f'''
    {base_html(brand)}
    <body style="background:{brand.surface}; padding:80px;">
        <h1 style="font-family:'{brand.font_headline}'; font-size:64px;">
            We make AI recommend <span style="color:{brand.primary};">your brand.</span>
        </h1>
    </body></html>
    '''

Export to PNG/PDF

slides = [slide_hero(), slide_solution()]

# Export to PNG (default)
paths = export(slides, "/tmp/my-deck/")
# Creates: /tmp/my-deck/slide-01.png, slide-02.png, ...

# Export to PDF
paths = export(slides, "/tmp/my-deck/", format="pdf")
# Or use convenience function:
paths = export_pdf(slides, "/tmp/my-deck/")

CLI

Build decks from the command line:

# Build to PNG
openslides build examples/scaile.py -o /tmp/scaile-deck/

# Build to PDF
openslides build examples/scaile.py -o /tmp/scaile-deck/ -f pdf

# List slides in a deck file
openslides list examples/scaile.py

# Custom dimensions
openslides build examples/scaile.py -W 1280 -H 720

API Reference

Brand

Dataclass holding brand assets.

Attributes:

  • primary - Main accent color (hex)
  • secondary - Secondary accent color
  • background - Slide background color
  • surface - Card/surface background
  • text - Primary text color
  • muted - Secondary/muted text color
  • font_headline - Headline font family
  • font_body - Body text font family
  • logo_svg - Logo as inline SVG (optional)
  • logo_url - Logo URL (optional)
  • name - Brand name
  • domain - Source domain

Validation:

  • Color fields must be valid hex colors (e.g., #054dfe or #fff)
  • Invalid colors raise ValueError

Methods:

  • Brand.from_domain(url) - Extract brand from website (requires aiohttp)
  • brand.google_fonts_url - Google Fonts URL for brand fonts

base_html(brand)

Generate HTML boilerplate with brand fonts loaded. Returns everything up to <body>.

base_html(brand)
# Returns: <!DOCTYPE html><html>...<head>...<link href="fonts.googleapis.com/...">...</head>

base_styles(brand)

Generate common CSS classes using brand values. Use inside a <style> tag.

f'<style>{base_styles(brand)}</style>'
# Provides: .headline, .body-text, .muted, .accent, .card, .label, .btn

export(slides, output_dir, format="png")

Export slides to PNG or PDF files.

paths = export(slides, "/tmp/deck/", width=1920, height=1080)
paths = export(slides, "/tmp/deck/", format="pdf")

export_pdf(slides, output_dir)

Convenience wrapper for PDF export.

paths = export_pdf(slides, "/tmp/deck/")

export_async(slides, output_dir, format="png")

Async version of export. Use if already in async context.

Logo Helpers

clearbit_logo(domain, size=40) - Get logo img tag via Clearbit (free, no auth):

from openslides import clearbit_logo

logo = clearbit_logo("stripe.com", size=40)
# Returns: <img src="https://logo.clearbit.com/stripe.com" alt="logo" style="height:40px;" />

brand.logo_img(size=40) - Get logo from Brand (uses logo_svg, logo_url, or Clearbit fallback):

logo = brand.logo_img(size=48)
# Uses: brand.logo_svg if set, else brand.logo_url, else Clearbit

brand.clearbit_logo_url - Direct Clearbit URL:

url = brand.clearbit_logo_url
# Returns: "https://logo.clearbit.com/{domain}"

Philosophy

The best slide decks are brand-specific, not generic. openslides gives you:

  1. Brand extraction - Get colors/fonts from any website
  2. Explicit values - Brand values visible in your code
  3. Full control - Write whatever HTML/CSS you want
  4. Simple export - Playwright renders to PNG

No themes. No components. No fighting the framework.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

openslides_ai-1.0.0.tar.gz (17.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

openslides_ai-1.0.0-py3-none-any.whl (13.3 kB view details)

Uploaded Python 3

File details

Details for the file openslides_ai-1.0.0.tar.gz.

File metadata

  • Download URL: openslides_ai-1.0.0.tar.gz
  • Upload date:
  • Size: 17.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for openslides_ai-1.0.0.tar.gz
Algorithm Hash digest
SHA256 19caa09a50c38fcdf34529ce87d90561e42827ba74b7ead5ce5833f5a886dae2
MD5 1f0b9d981dd31a92f676e7e7fd3c8460
BLAKE2b-256 ab693c4da85a69f6549b2b2f24cbfc05f4d0f2b9bf8722a44849745d0fa98ee9

See more details on using hashes here.

File details

Details for the file openslides_ai-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: openslides_ai-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 13.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for openslides_ai-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 698d4453333b80da330882b13a67fdeb6e3926014b2a6876b33af9e151ff4e82
MD5 e568adcf8d3c35d8c4354c3f4e795d25
BLAKE2b-256 1b000f16f7aa93e5b406de2a4684571df600faeef66250766e257a05b6c9e241

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page