881 lines
20 KiB
Markdown
881 lines
20 KiB
Markdown
---
|
|
name: policyengine-design
|
|
description: 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:**
|
|
```python
|
|
TEAL_ACCENT = "#39C6C0" # Primary color (teal)
|
|
BLUE_PRIMARY = "#2C6496" # Secondary color (blue)
|
|
DARK_GRAY = "#616161" # Text color
|
|
```
|
|
|
|
**Extended palette:**
|
|
```python
|
|
# 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:**
|
|
```bash
|
|
cat policyengine-app/src/style/colors.js
|
|
```
|
|
|
|
#### Plotly Chart Formatting
|
|
|
|
**Standard PolicyEngine chart:**
|
|
|
|
```python
|
|
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:**
|
|
```bash
|
|
# 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:
|
|
```python
|
|
colors = ["#2C6496", "#39C6C0", "#17354F", "#227773"]
|
|
```
|
|
|
|
#### Typography
|
|
|
|
**Charts:**
|
|
```python
|
|
font=dict(family="Roboto Serif", size=14, color="black")
|
|
```
|
|
|
|
**Axis labels:**
|
|
```python
|
|
xaxis=dict(
|
|
title=dict(text="Label", font=dict(size=14)),
|
|
tickfont=dict(size=12)
|
|
)
|
|
```
|
|
|
|
**Load Roboto font:**
|
|
```python
|
|
# 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):**
|
|
|
|
```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:**
|
|
```bash
|
|
cat givecalc/.streamlit/config.toml
|
|
cat salt-amt-calculator/.streamlit/config.toml # Other calculators
|
|
```
|
|
|
|
### Logo Usage
|
|
|
|
**Logo URLs:**
|
|
|
|
```python
|
|
# 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:**
|
|
```bash
|
|
ls policyengine-app/src/images/logos/policyengine/
|
|
```
|
|
|
|
### Complete Example: Branded Chart
|
|
|
|
```python
|
|
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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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):**
|
|
|
|
```typescript
|
|
// 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:**
|
|
```bash
|
|
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):**
|
|
|
|
```javascript
|
|
// 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:**
|
|
```bash
|
|
cat policyengine-app/src/style/colors.js
|
|
```
|
|
|
|
**Usage in React (app-v2):**
|
|
```typescript
|
|
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):**
|
|
```python
|
|
# 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):**
|
|
```python
|
|
font=dict(family="Roboto Serif")
|
|
```
|
|
|
|
**For web apps:**
|
|
```javascript
|
|
// System font stack
|
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, ...
|
|
```
|
|
|
|
**Loading Google Fonts:**
|
|
```html
|
|
<!-- 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:**
|
|
|
|
```bash
|
|
# GiveCalc format_fig function
|
|
cat givecalc/ui/visualization.py
|
|
|
|
# Shows:
|
|
# - Roboto Serif font
|
|
# - White background
|
|
# - Logo placement
|
|
# - Margin configuration
|
|
```
|
|
|
|
**Pattern to follow:**
|
|
```python
|
|
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:**
|
|
|
|
```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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
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:**
|
|
```python
|
|
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:**
|
|
```python
|
|
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:**
|
|
```javascript
|
|
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:**
|
|
```bash
|
|
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:**
|
|
```python
|
|
TEAL_ACCENT = "#39C6C0"
|
|
BLUE_PRIMARY = "#2C6496"
|
|
```
|
|
|
|
2. **Create chart:**
|
|
```python
|
|
fig = go.Figure()
|
|
fig.add_trace(go.Scatter(x=x, y=y, line=dict(color=TEAL_ACCENT)))
|
|
```
|
|
|
|
3. **Apply branding:**
|
|
```python
|
|
fig = format_fig(fig) # See implementation above
|
|
```
|
|
|
|
### Task 2: Setup Streamlit Branding
|
|
|
|
1. **Create config directory:**
|
|
```bash
|
|
mkdir .streamlit
|
|
```
|
|
|
|
2. **Copy theme config:**
|
|
```bash
|
|
cat givecalc/.streamlit/config.toml > .streamlit/config.toml
|
|
```
|
|
|
|
3. **Verify in app:**
|
|
```python
|
|
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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# 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:**
|
|
```bash
|
|
# Charts in app
|
|
cat policyengine-app/src/pages/policy/output/DistributionalImpact.jsx
|
|
```
|
|
|
|
### Don't Use These
|
|
|
|
**❌ Wrong colors:**
|
|
```python
|
|
# Don't use random colors
|
|
color = "#FF5733"
|
|
color = "red"
|
|
color = "green"
|
|
```
|
|
|
|
**❌ Wrong fonts:**
|
|
```python
|
|
# Don't use other fonts for charts
|
|
font = dict(family="Arial")
|
|
font = dict(family="Times New Roman")
|
|
```
|
|
|
|
**❌ Missing logo:**
|
|
```python
|
|
# 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:**
|
|
```bash
|
|
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:**
|
|
```python
|
|
# 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):**
|
|
- Google Fonts: https://fonts.google.com/specimen/Roboto
|
|
- Family: Roboto Serif
|
|
- Weights: 300 (light), 400 (regular), 500 (medium), 700 (bold)
|
|
|
|
**Loading:**
|
|
```html
|
|
<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):**
|
|
```bash
|
|
cat policyengine-app/src/style/colors.js
|
|
```
|
|
|
|
**Python (calculators, analysis):**
|
|
```python
|
|
# 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 |
|
|
|
|
## Related Skills
|
|
|
|
- **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
|