or run

tessl search
Log in

elegant-reports

tessl install github:jdrhyne/agent-skills --skill elegant-reports

github.com/jdrhyne/agent-skills

Generate beautifully designed PDF reports with Nordic/Scandinavian aesthetic. Uses Nutrient DWS API for HTML-to-PDF conversion.

Review Score

76%

Validation Score

12/16

Implementation Score

100%

Activation Score

33%

elegant-reports

Generate minimalist, elegant PDF reports inspired by Scandinavian design principles.

Quick Start

cd ~/clawd-nuri-internal/skills/elegant-reports

# Generate a report (dense layout)
node generate.js report.md output.pdf --template report

# Generate a presentation (bold slides)
node generate.js data.md slides.pdf --template presentation

# Dark mode
node generate.js report.md --template report --theme dark

# List templates
node generate.js --list

Templates

TemplateStyleUse Case
reportDense, multi-columnDeep dives, analysis, competitive intel
presentationBig & bold, one idea/pageExec briefings, board decks

Each template supports --theme light (default) or --theme dark.

Frontmatter

Add YAML frontmatter to control output:

---
title: Q4 Competitive Analysis
subtitle: Market Intelligence Report
author: Nuri
template: report
theme: dark
---

Your content here...

Design Philosophy

Based on Nordic/Scandinavian design principles:

  • Bold typography — Poppins for headlines, Inter for body
  • High contrast — Dark headers, clear hierarchy
  • Generous whitespace — Content breathes
  • One accent color — Blue (#2563EB) used sparingly
  • Functional beauty — Form follows function

See NORDIC_DESIGN_RESEARCH.md for complete design documentation.

Creating New Templates

The Visual Iteration Workflow

This is how to create new templates with visual feedback:

Step 1: Research References

# Use browser tool to study design examples
browser navigate https://www.canva.com/templates/...
browser screenshot

# Look for:
# - Typography choices (font, size, weight)
# - Color palette (backgrounds, text, accents)
# - Layout patterns (grids, spacing)
# - Component styles (cards, tables, callouts)

Step 2: Create Theme CSS

Create a new CSS file in themes/:

/* themes/my-theme.css */

@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@600;700;800&family=Inter:wght@400;500&display=swap');

:root {
  /* Color tokens */
  --color-bg: #FAFAFA;
  --color-surface: #FFFFFF;
  --color-text-primary: #0A0A0A;
  --color-text-secondary: #404040;
  --color-accent: #2563EB;
  
  /* Typography tokens */
  --font-display: 'Poppins', sans-serif;
  --font-body: 'Inter', sans-serif;
  
  /* Spacing tokens */
  --space-4: 1rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
}

/* Component styles... */

Step 3: Create Template HTML

Create HTML in templates/:

<!-- templates/my-template.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>{{title}}</title>
  <style>
{{styles}}
  </style>
</head>
<body>
  <div class="page">
    <h1>{{title}}</h1>
    <p>{{subtitle}}</p>
    {{content}}
  </div>
</body>
</html>

Available variables: {{title}}, {{subtitle}}, {{author}}, {{date}}, {{content}}, {{styles}}

Step 4: Test with Visual Feedback

# Generate test HTML manually
node -e "
const fs = require('fs');
const css = fs.readFileSync('themes/my-theme.css', 'utf8');
let html = fs.readFileSync('templates/my-template.html', 'utf8');
html = html.replace('{{styles}}', css);
html = html.replace(/\{\{title\}\}/g, 'Test Title');
html = html.replace(/\{\{subtitle\}\}/g, 'Test Subtitle');
html = html.replace(/\{\{date\}\}/g, 'January 2026');
html = html.replace(/\{\{author\}\}/g, 'Nuri');
html = html.replace(/\{\{content\}\}/g, '<p>Test content</p>');
fs.writeFileSync('test-output.html', html);
"

# Preview in browser
browser navigate file://$(pwd)/test-output.html
browser screenshot

# See what's wrong, fix it, repeat

Step 5: Register in Generator

Add to TEMPLATES object in generate.js:

const TEMPLATES = {
  // ...existing templates...
  
  'my-template': {
    description: 'My custom template description',
    template: 'my-template.html',
    themes: {
      light: 'my-theme.css',
      dark: 'my-theme-dark.css'
    }
  }
};

Step 6: Test PDF Generation

node generate.js test.md output.pdf --template my-template --output-html

Design Tokens Reference

Typography Scale

TokenSizeUse
--text-xs11-12pxLabels, captions
--text-sm13-14pxBody (dense)
--text-base14-16pxBody (normal)
--text-lg16-18pxLead paragraphs
--text-xl18-20pxSection headers
--text-2xl20-24pxH3
--text-3xl24-32pxH2
--text-4xl32-40pxH1 (report)
--text-5xl48-56pxH1 (presentation)
--text-6xl64-72pxHero text

Spacing Scale

TokenSizeUse
--space-12-4pxTight gaps
--space-24-8pxInline spacing
--space-38-12pxComponent padding
--space-412-16pxCard padding
--space-620-24pxSection gaps
--space-828-32pxMajor sections
--space-1036-40pxPage sections
--space-1244-48pxPage margins

Color Palette

Light Mode:

--color-bg: #FAFAFA;
--color-surface: #FFFFFF;
--color-text-primary: #0A0A0A;
--color-text-secondary: #404040;
--color-text-muted: #737373;
--color-accent: #2563EB;

Dark Mode:

--color-bg: #09090B;
--color-surface: #18181B;
--color-text-primary: #FAFAFA;
--color-text-secondary: #D4D4D8;
--color-text-muted: #A1A1AA;
--color-accent: #3B82F6;

Component Patterns

KPI Strip (horizontal metrics)

<div class="kpi-strip">
  <div class="kpi-item">
    <div class="kpi-value">$10.8M</div>
    <div class="kpi-label">Revenue</div>
    <div class="kpi-change positive">+12%</div>
  </div>
  <!-- more items -->
</div>

Key Findings Box

<div class="key-findings">
  <div class="key-findings-title">Key Points</div>
  <ul>
    <li><strong>Point 1</strong> — Details</li>
    <li><strong>Point 2</strong> — Details</li>
  </ul>
</div>

Two-Column Layout

<div class="two-col">
  <div>Left column content</div>
  <div>Right column content</div>
</div>

Callouts

<div class="callout callout-tip">
  <div class="callout-title">Tip</div>
  <p>Content here</p>
</div>

Types: callout-tip (green), callout-warning (amber), callout-danger (red)

Tables with Dark Headers

<table class="no-break">
  <thead>
    <tr><th>Header</th><th class="num">Value</th></tr>
  </thead>
  <tbody>
    <tr><td>Row</td><td class="num">123</td></tr>
  </tbody>
</table>

Page Break Control

Add these classes to prevent awkward breaks:

<div class="no-break">This won't split across pages</div>
<div class="page-break">Forces new page before this</div>

Tables, cards, callouts, and KPI strips have page-break-inside: avoid by default.

Files Structure

elegant-reports/
├── SKILL.md                    # This file
├── NORDIC_DESIGN_RESEARCH.md   # Design principles documentation
├── generate.js                 # Main generator script
├── package.json
├── themes/
│   ├── nordic-v2.css           # Presentation light
│   ├── nordic-report.css       # Report light
│   └── nordic-report-dark.css  # Report dark
├── templates/
│   ├── executive-v2.html       # Presentation template
│   └── report-v2.html          # Report template
└── examples/
    └── sample-executive.md     # Example input

Dependencies

  • Node.js 18+
  • axios, form-data (npm install)
  • Nutrient DWS API key (configured in mcporter or NUTRIENT_DWS_API_KEY env var)

API Usage

const { generateReport } = require('./generate.js');

await generateReport({
  input: 'report.md',
  output: 'report.pdf',
  template: 'report',
  theme: 'dark',
  title: 'My Report',
  author: 'Nuri'
});