Files
2025-11-30 08:47:52 +08:00

20 KiB

name, description
name description
policyengine-design PolicyEngine visual identity - colors, fonts, logos, and branding for web apps, calculators, charts, and research

PolicyEngine Design System

PolicyEngine's visual identity and branding guidelines for creating consistent user experiences across web apps, calculators, charts, and research outputs.

For Users 👥

PolicyEngine Visual Identity

Brand colors:

  • Teal (#39C6C0) - Primary accent color (buttons, highlights, interactive elements)
  • Blue (#2C6496) - Secondary color (links, charts, headers)

Typography:

  • Charts: Roboto Serif
  • Web app: System fonts (sans-serif)
  • Streamlit apps: Default sans-serif

Logo:

  • Used in charts (bottom right)
  • Blue version for light backgrounds
  • White version for dark backgrounds

Recognizing PolicyEngine Content

You can identify PolicyEngine content by:

  • Teal accent color (#39C6C0) on buttons and interactive elements
  • Blue (#2C6496) in charts and links
  • Roboto Serif font in charts
  • PolicyEngine logo in chart footer
  • Clean, minimal white backgrounds
  • Data-focused, quantitative presentation

For Analysts 📊

Chart Branding

When creating charts for PolicyEngine analysis, follow these guidelines:

Color Palette

Primary colors:

TEAL_ACCENT = "#39C6C0"   # Primary color (teal)
BLUE_PRIMARY = "#2C6496"  # Secondary color (blue)
DARK_GRAY = "#616161"     # Text color

Extended palette:

# Blues
BLUE = "#2C6496"
BLUE_LIGHT = "#D8E6F3"
BLUE_PRESSED = "#17354F"
BLUE_98 = "#F7FAFD"
DARK_BLUE_HOVER = "#1d3e5e"
DARKEST_BLUE = "#0C1A27"

# Teals
TEAL_ACCENT = "#39C6C0"
TEAL_LIGHT = "#F7FDFC"
TEAL_PRESSED = "#227773"

# Grays
DARK_GRAY = "#616161"
GRAY = "#808080"
MEDIUM_LIGHT_GRAY = "#BDBDBD"
MEDIUM_DARK_GRAY = "#D2D2D2"
LIGHT_GRAY = "#F2F2F2"

# Accents
WHITE = "#FFFFFF"
BLACK = "#000000"
DARK_RED = "#b50d0d"  # For negative values

See current colors:

cat policyengine-app/src/style/colors.js

Plotly Chart Formatting

Standard PolicyEngine chart:

import plotly.graph_objects as go

def format_fig(fig):
    """Format chart with PolicyEngine branding."""
    fig.update_layout(
        # Typography
        font=dict(
            family="Roboto Serif",
            color="black"
        ),

        # Background
        plot_bgcolor="white",
        template="plotly_white",

        # Margins (leave room for logo)
        margin=dict(
            l=50,
            r=100,
            t=50,
            b=120,
            pad=4
        ),

        # Chart size
        height=600,
        width=800,
    )

    # Add PolicyEngine logo (bottom right)
    fig.add_layout_image(
        dict(
            source="https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png",
            xref="paper",
            yref="paper",
            x=1.0,
            y=-0.10,
            sizex=0.10,
            sizey=0.10,
            xanchor="right",
            yanchor="bottom"
        )
    )

    # Clean modebar
    fig.update_layout(
        modebar=dict(
            bgcolor="rgba(0,0,0,0)",
            color="rgba(0,0,0,0)"
        )
    )

    return fig

# Usage
fig = go.Figure()
fig.add_trace(go.Scatter(x=x_data, y=y_data, line=dict(color=TEAL_ACCENT)))
fig = format_fig(fig)

Current implementation:

# See format_fig in action
cat givecalc/ui/visualization.py
cat policyengine-app/src/pages/policy/output/...

Chart Colors

For line charts:

  • Primary line: Teal (#39C6C0) or Blue (#2C6496)
  • Background lines: Light gray (rgb(180, 180, 180))
  • Markers: Teal with 70% opacity

For bar charts:

  • Positive values: Teal (#39C6C0)
  • Negative values: Dark red (#b50d0d)
  • Neutral: Gray

For multiple series: Use variations of blue and teal, or discrete color scale:

colors = ["#2C6496", "#39C6C0", "#17354F", "#227773"]

Typography

Charts:

font=dict(family="Roboto Serif", size=14, color="black")

Axis labels:

xaxis=dict(
    title=dict(text="Label", font=dict(size=14)),
    tickfont=dict(size=12)
)

Load Roboto font:

# In Streamlit apps
st.markdown("""
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
""", unsafe_allow_html=True)

Streamlit App Branding

Streamlit configuration (.streamlit/config.toml):

[theme]
base = "light"
primaryColor = "#39C6C0"          # Teal accent
backgroundColor = "#FFFFFF"        # White background
secondaryBackgroundColor = "#F7FDFC"  # Teal light
textColor = "#616161"              # Dark gray

[client]
toolbarMode = "minimal"

Current implementation:

cat givecalc/.streamlit/config.toml
cat salt-amt-calculator/.streamlit/config.toml  # Other calculators

Logo Usage

Logo URLs:

# Blue logo (for light backgrounds)
LOGO_BLUE = "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png"

# White logo (for dark backgrounds)
LOGO_WHITE = "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/white.png"

# SVG versions (scalable)
LOGO_BLUE_SVG = "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.svg"
LOGO_WHITE_SVG = "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/white.svg"

Logo placement in charts:

  • Bottom right corner
  • 10% of chart width
  • Slightly below bottom edge (y=-0.10)

Current logos:

ls policyengine-app/src/images/logos/policyengine/

Complete Example: Branded Chart

import plotly.graph_objects as go

# PolicyEngine colors
TEAL_ACCENT = "#39C6C0"
BLUE_PRIMARY = "#2C6496"

# Create chart
fig = go.Figure()

# Add data
fig.add_trace(go.Scatter(
    x=incomes,
    y=taxes,
    mode='lines',
    name='Tax liability',
    line=dict(color=TEAL_ACCENT, width=3)
))

# Apply PolicyEngine branding
fig.update_layout(
    # Typography
    font=dict(family="Roboto Serif", size=14, color="black"),

    # Title and labels
    title="Tax liability by income",
    xaxis_title="Income",
    yaxis_title="Tax ($)",

    # Formatting
    xaxis_tickformat="$,.0f",
    yaxis_tickformat="$,.0f",

    # Appearance
    plot_bgcolor="white",
    template="plotly_white",

    # Size and margins
    height=600,
    width=800,
    margin=dict(l=50, r=100, t=50, b=120, pad=4)
)

# Add logo
fig.add_layout_image(
    dict(
        source="https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png",
        xref="paper",
        yref="paper",
        x=1.0,
        y=-0.10,
        sizex=0.10,
        sizey=0.10,
        xanchor="right",
        yanchor="bottom"
    )
)

# Show
fig.show()

For Contributors 💻

Brand Assets

Repository: PolicyEngine/policyengine-app-v2 (current), PolicyEngine/policyengine-app (legacy)

Logo files:

# Logos in app (both v1 and v2 use same logos)
ls policyengine-app/src/images/logos/policyengine/
# - blue.png - For light backgrounds
# - white.png - For dark backgrounds
# - blue.svg - Scalable blue logo
# - white.svg - Scalable white logo
# - banners/ - Banner variations
# - profile/ - Profile/avatar versions

Access logos:

# View logo files (v1 repo has the assets)
cd policyengine-app/src/images/logos/policyengine/
ls -la

Color Definitions

⚠️ IMPORTANT: App V2 Transition

PolicyEngine is transitioning to policyengine-app-v2 with updated design tokens. Use app-v2 colors for new projects.

Current colors (policyengine-app-v2):

// policyengine-app-v2/app/src/designTokens/colors.ts

// Primary (teal) - 50 to 900 scale
primary[500]: "#319795"  // Main teal
primary[400]: "#38B2AC"  // Lighter teal
primary[600]: "#2C7A7B"  // Darker teal

// Blue scale
blue[700]: "#026AA2"     // Primary blue
blue[500]: "#0EA5E9"     // Lighter blue

// Gray scale
gray[700]: "#344054"     // Dark text
gray[100]: "#F2F4F7"     // Light backgrounds

// Semantic
success: "#22C55E"
warning: "#FEC601"
error: "#EF4444"

// Background
background.primary: "#FFFFFF"
background.secondary: "#F5F9FF"

// Text
text.primary: "#000000"
text.secondary: "#5A5A5A"

To see current design tokens:

cat policyengine-app-v2/app/src/designTokens/colors.ts
cat policyengine-app-v2/app/src/styles/colors.ts  # Mantine integration

Legacy colors (policyengine-app - still used in some projects):

// policyengine-app/src/style/colors.js
TEAL_ACCENT = "#39C6C0"  // Old teal (slightly different from v2)
BLUE = "#2C6496"         // Old blue
DARK_GRAY = "#616161"    // Old dark gray

To see legacy colors:

cat policyengine-app/src/style/colors.js

Usage in React (app-v2):

import { colors } from 'designTokens';

<Button style={{ backgroundColor: colors.primary[500] }} />
<Text style={{ color: colors.text.primary }} />

Usage in Python/Plotly (use legacy colors for now):

# For charts, continue using legacy colors until officially migrated
TEAL_ACCENT = "#39C6C0"  # From original app
BLUE_PRIMARY = "#2C6496"  # From original app

# Or use app-v2 colors
TEAL_PRIMARY = "#319795"  # From app-v2
BLUE_PRIMARY_V2 = "#026AA2"  # From app-v2

Typography

Fonts:

For charts (Plotly):

font=dict(family="Roboto Serif")

For web apps:

// System font stack
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, ...

Loading Google Fonts:

<!-- In Streamlit or HTML -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&family=Roboto+Serif:wght@300;400;500;700&display=swap" rel="stylesheet">

Chart Formatting Function

Reference implementation:

# GiveCalc format_fig function
cat givecalc/ui/visualization.py

# Shows:
# - Roboto Serif font
# - White background
# - Logo placement
# - Margin configuration

Pattern to follow:

def format_fig(fig: go.Figure) -> go.Figure:
    """Format figure with PolicyEngine branding.

    This function is used across PolicyEngine projects to ensure
    consistent chart appearance.
    """
    # Font
    fig.update_layout(
        font=dict(family="Roboto Serif", color="black")
    )

    # Background
    fig.update_layout(
        template="plotly_white",
        plot_bgcolor="white"
    )

    # Size
    fig.update_layout(height=600, width=800)

    # Margins (room for logo)
    fig.update_layout(
        margin=dict(l=50, r=100, t=50, b=120, pad=4)
    )

    # Logo
    fig.add_layout_image(
        dict(
            source="https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png",
            xref="paper",
            yref="paper",
            x=1.0,
            y=-0.10,
            sizex=0.10,
            sizey=0.10,
            xanchor="right",
            yanchor="bottom"
        )
    )

    # Clean modebar
    fig.update_layout(
        modebar=dict(
            bgcolor="rgba(0,0,0,0)",
            color="rgba(0,0,0,0)"
        )
    )

    return fig

Streamlit Theme Configuration

Standard .streamlit/config.toml:

[theme]
base = "light"
primaryColor = "#39C6C0"              # Teal accent
backgroundColor = "#FFFFFF"            # White
secondaryBackgroundColor = "#F7FDFC"  # Teal light
textColor = "#616161"                  # Dark gray
font = "sans serif"

[client]
toolbarMode = "minimal"
showErrorDetails = true

Usage:

# Create .streamlit directory in your project
mkdir .streamlit

# Copy configuration
cat > .streamlit/config.toml << 'EOF'
[theme]
base = "light"
primaryColor = "#39C6C0"
backgroundColor = "#FFFFFF"
secondaryBackgroundColor = "#F7FDFC"
textColor = "#616161"
font = "sans serif"
EOF

Current examples:

cat givecalc/.streamlit/config.toml

Design Patterns by Project Type

Streamlit Calculators (GiveCalc, SALT Calculator, etc.)

Required branding:

  1. .streamlit/config.toml with PolicyEngine theme
  2. Charts use format_fig() function with logo
  3. Teal accent color for interactive elements
  4. Roboto Serif for charts

Example:

import streamlit as st
import plotly.graph_objects as go

# Constants
TEAL_ACCENT = "#39C6C0"

# Streamlit UI
st.title("Calculator Name")  # Uses theme colors automatically
st.button("Calculate", type="primary")  # Teal accent from theme

# Charts
fig = go.Figure()
fig.add_trace(go.Scatter(x=x, y=y, line=dict(color=TEAL_ACCENT)))
fig = format_fig(fig)  # Add branding
st.plotly_chart(fig)

Jupyter Notebooks / Analysis Scripts

Required branding:

  1. Charts use format_fig() with logo
  2. PolicyEngine color palette
  3. Roboto Serif font

Example:

import plotly.graph_objects as go

TEAL_ACCENT = "#39C6C0"
BLUE_PRIMARY = "#2C6496"

fig = go.Figure()
fig.add_trace(go.Scatter(
    x=data.income,
    y=data.tax_change,
    line=dict(color=TEAL_ACCENT, width=3)
))

fig.update_layout(
    font=dict(family="Roboto Serif", size=14),
    title="Tax impact by income",
    xaxis_title="Income",
    yaxis_title="Tax change ($)",
    plot_bgcolor="white"
)

# Add logo
fig.add_layout_image(...)

React App Components

Color usage:

import colors from "style/colors";

// Interactive elements
<Button style={{ backgroundColor: colors.TEAL_ACCENT }}>
  Click me
</Button>

// Links
<a style={{ color: colors.BLUE }}>Learn more</a>

// Text
<p style={{ color: colors.DARK_GRAY }}>Description</p>

Current colors:

cat policyengine-app/src/style/colors.js

Visual Guidelines

Chart Design Principles

  1. Minimal decoration - Let data speak
  2. White backgrounds - Clean, print-friendly
  3. Clear axis labels - Always include units
  4. Formatted numbers - Currency ($), percentages (%), etc.
  5. Logo inclusion - Bottom right, never intrusive
  6. Consistent sizing - 800x600 standard
  7. Roboto Serif - Professional, readable font

Color Usage Rules

Primary actions:

  • Use TEAL_ACCENT (#39C6C0)
  • Buttons, highlights, current selection

Chart lines:

  • Primary data: TEAL_ACCENT or BLUE_PRIMARY
  • Secondary data: BLUE_LIGHT or GRAY
  • Negative values: DARK_RED (#b50d0d)

Backgrounds:

  • Main: WHITE (#FFFFFF)
  • Secondary: TEAL_LIGHT (#F7FDFC) or BLUE_98 (#F7FAFD)
  • Plot area: WHITE

Text:

  • Primary: BLACK (#000000)
  • Secondary: DARK_GRAY (#616161)
  • Muted: GRAY (#808080)

Accessibility

Color contrast requirements:

  • Text on background: 4.5:1 minimum (WCAG AA)
  • DARK_GRAY on WHITE: Passes
  • TEAL_ACCENT on WHITE: Passes for large text
  • Use sufficient line weights for visibility

Don't rely on color alone:

  • Use patterns or labels for different data series
  • Ensure charts work in grayscale

Common Branding Tasks

Task 1: Create Branded Plotly Chart

  1. Define colors:

    TEAL_ACCENT = "#39C6C0"
    BLUE_PRIMARY = "#2C6496"
    
  2. Create chart:

    fig = go.Figure()
    fig.add_trace(go.Scatter(x=x, y=y, line=dict(color=TEAL_ACCENT)))
    
  3. Apply branding:

    fig = format_fig(fig)  # See implementation above
    

Task 2: Setup Streamlit Branding

  1. Create config directory:

    mkdir .streamlit
    
  2. Copy theme config:

    cat givecalc/.streamlit/config.toml > .streamlit/config.toml
    
  3. Verify in app:

    import streamlit as st
    
    st.button("Test", type="primary")  # Should be teal
    

Task 3: Brand Consistency Check

Checklist:

  • Charts use Roboto Serif font
  • Primary color is TEAL_ACCENT (#39C6C0)
  • Secondary color is BLUE_PRIMARY (#2C6496)
  • White backgrounds
  • Logo in charts (bottom right)
  • Currency formatted with $ and commas
  • Percentages formatted with %
  • Streamlit config.toml uses PolicyEngine theme

Reference Implementations

Excellent Examples

Streamlit calculators:

# GiveCalc - Complete example
cat givecalc/ui/visualization.py
cat givecalc/.streamlit/config.toml

# Other calculators
ls salt-amt-calculator/
ls ctc-calculator/

Blog post charts:

# Analysis with branded charts
cat policyengine-app/src/posts/articles/harris-eitc.md
cat policyengine-app/src/posts/articles/montana-tax-cuts-2026.md

React app components:

# Charts in app
cat policyengine-app/src/pages/policy/output/DistributionalImpact.jsx

Don't Use These

Wrong colors:

# Don't use random colors
color = "#FF5733"
color = "red"
color = "green"

Wrong fonts:

# Don't use other fonts for charts
font = dict(family="Arial")
font = dict(family="Times New Roman")

Missing logo:

# Don't skip the logo in charts for publication
# All published charts should include PolicyEngine logo

Assets and Resources

Logo Files

In policyengine-app repository:

policyengine-app/src/images/logos/policyengine/
├── blue.png      # Primary logo (light backgrounds)
├── white.png     # Logo for dark backgrounds
├── blue.svg      # Scalable blue logo
├── white.svg     # Scalable white logo
├── banners/      # Banner variations
└── profile/      # Profile/avatar versions

Raw URLs for direct use:

# Use these URLs in code
LOGO_URL = "https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png"

Font Files

Roboto (charts):

Loading:

<link href="https://fonts.googleapis.com/css2?family=Roboto+Serif:wght@300;400;500;700&display=swap" rel="stylesheet">

Color Reference Files

JavaScript (React app):

cat policyengine-app/src/style/colors.js

Python (calculators, analysis):

# Define in constants.py or at top of file
TEAL_ACCENT = "#39C6C0"
BLUE_PRIMARY = "#2C6496"
DARK_GRAY = "#616161"
WHITE = "#FFFFFF"

Brand Evolution

Current identity (2025):

  • Teal primary (#39C6C0)
  • Blue secondary (#2C6496)
  • Roboto Serif for charts
  • Minimal, data-focused design

If brand evolves:

  • Colors defined in policyengine-app/src/style/colors.js are source of truth
  • Update this skill to point to current definitions
  • Never hardcode - always reference colors.js

Quick Reference

Color Codes

Color Hex Usage
Teal Accent #39C6C0 Primary interactive elements
Blue Primary #2C6496 Secondary, links, charts
Dark Gray #616161 Body text
White #FFFFFF Backgrounds
Teal Light #F7FDFC Secondary backgrounds
Dark Red #b50d0d Negative values, errors

Font Families

Context Font
Charts Roboto Serif
Web app System sans-serif
Streamlit Default sans-serif
Code blocks Monospace

Logo URLs

Background Format URL
Light PNG https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.png
Light SVG https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/blue.svg
Dark PNG https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/white.png
Dark SVG https://raw.githubusercontent.com/PolicyEngine/policyengine-app/master/src/images/logos/policyengine/white.svg
  • policyengine-app-skill - React component styling
  • policyengine-analysis-skill - Chart creation patterns
  • policyengine-writing-skill - Content style (complements visual style)

Resources

Brand assets: PolicyEngine/policyengine-app/src/images/ Color definitions: PolicyEngine/policyengine-app/src/style/colors.js Examples: givecalc, salt-amt-calculator, crfb-tob-impacts