3 Commits

Author SHA1 Message Date
HoaiNam 5bad070965 chore: Bump version to 1.0.6 in package.json 2026-04-07 14:46:18 +07:00
HoaiNam ad4af2f3cd docs: Update README.md and workflows for improved clarity and functionality
- Revised Odoo 18 and 19 descriptions in README.md for better clarity and detail.
- Enhanced the structure of the skills section, adding new entries for Slide and Visual Explainer.
- Updated GitHub Actions workflows to streamline tagging and release processes, improving messaging consistency.
- Adjusted release notes generation to reflect the tag name directly, enhancing clarity in release management.
2026-04-07 14:43:54 +07:00
HoaiNam 9ca3d5b7d2 chore: Bump version to 1.0.5 and streamline documentation
- Updated package version in package.json to 1.0.5.
- Removed manual installation instructions from README.md to simplify user guidance.
- Added GitHub Actions workflows for automatic tagging and release management based on version changes in package.json.
- Enhanced Odoo 18 SKILL.md with a more concise description and improved clarity for usage scenarios.
- Introduced new references and detailed patterns in the Odoo 18 data guide for better data processing practices.
2026-04-07 14:39:00 +07:00
7 changed files with 652 additions and 59 deletions
+70
View File
@@ -0,0 +1,70 @@
name: Auto tag and release from package.json
on:
push:
branches:
- "main"
paths:
- "package.json"
permissions:
contents: write
concurrency:
group: auto-tag-${{ github.ref }}
cancel-in-progress: true
jobs:
tag-and-release:
runs-on: ubuntu-latest
if: ${{ !contains(github.event.head_commit.message, '[skip tag]') }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect version bump
id: ver
run: |
set -euo pipefail
CUR="$(node -p "require('./package.json').version")"
PREV="$(git show HEAD~1:package.json 2>/dev/null | node -p "JSON.parse(require('fs').readFileSync(0,'utf8')).version" 2>/dev/null || echo "")"
echo "current=$CUR" >> "$GITHUB_OUTPUT"
echo "previous=$PREV" >> "$GITHUB_OUTPUT"
if [ "$CUR" != "$PREV" ]; then
echo "bumped=true" >> "$GITHUB_OUTPUT"
else
echo "bumped=false" >> "$GITHUB_OUTPUT"
fi
- name: Skip if no version change
if: steps.ver.outputs.bumped != 'true'
run: echo "Version unchanged vs previous commit; skipping."
- name: Tag, push, and create GitHub Release
if: steps.ver.outputs.bumped == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
V="${{ steps.ver.outputs.current }}"
TAG="v${V}"
git fetch --tags --force
if git rev-parse "$TAG" >/dev/null 2>&1; then
echo "Tag $TAG already exists locally; skipping."
exit 0
fi
if git ls-remote --tags origin "refs/tags/$TAG" | grep -q .; then
echo "Tag $TAG already exists on remote; skipping."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git tag -a "$TAG" -m "$TAG"
git push origin "$TAG"
if gh release view "$TAG" >/dev/null 2>&1; then
echo "Release for $TAG already exists; skipping."
else
gh release create "$TAG" --title "$TAG" --generate-notes
fi
+26
View File
@@ -0,0 +1,26 @@
name: GitHub Release
on:
push:
tags:
- "v*.*.*"
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Create release
uses: softprops/action-gh-release@v2
with:
name: ${{ github.ref_name }}
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+28 -37
View File
@@ -30,16 +30,6 @@ npx skills add unclecatvn/agent-skills
That's it! Your AI assistant will now have access to all the skills in this repository.
### Alternative: Manual Installation
```bash
# Install the CLI globally
npm install -g @unclecat/agent-skills-cli
# Initialize a specific skill (e.g., Odoo 19 for Cursor)
agent-skills init --ai cursor odoo --version 19.0
```
---
## What's Inside?
@@ -50,14 +40,16 @@ In-depth guides written specifically for AI consumption:
| Skill | Description |
|-------|-------------|
| **[Odoo 18.0](skills/odoo-18.0/)** | Complete Odoo 18 development guide (ORM, OWL, Web Client, Performance) |
| **[Odoo 19.0](skills/odoo-19.0/)** | Complete Odoo 19 development guide with latest features |
| **[Odoo 18.0](skills/odoo-18.0/)** | Odoo 18 development (ORM, views, security, OWL, reports, migrations, performance) |
| **[Odoo 19.0](skills/odoo-19.0/)** | Odoo 19 development guide with current conventions |
| **[DTG Base](skills/dtg-base/)** | DTGBase utilities (date/period, timezone, batch, barcode, Vietnamese text) |
| **[Payment Integration](skills/payment-integration/)** | Integration guides for SePay, Polar, Stripe, Paddle, Creem.io |
| **[Code Review](skills/code-review/)** | Standards and protocols for automated code review |
| **[Brainstorming](skills/brainstorming/)** | Structured framework for feature ideation |
| **[Writing Skills](skills/writing-skills/)** | Guide for creating and editing AI skills |
| **[MCP Builder](skills/mcp-builder/)** | Guide for building Model Context Protocol servers |
| **[Payment Integration](skills/payment-integration/)** | SePay, Polar, Stripe, Paddle, Creem.io and related patterns |
| **[Code Review](skills/code-review/)** | Standards and workflows for automated code review |
| **[Brainstorming](skills/brainstorming/)** | Structured framework for feature ideation and spec review |
| **[Writing Skills](skills/writing-skills/)** | Creating and editing AI skills (structure, evals, quality) |
| **[MCP Builder](skills/mcp-builder/)** | Building Model Context Protocol servers |
| **[Slide (AI Vibe Slides)](skills/slide/)** | Self-contained HTML/React slide decks for fullscreen presentation |
| **[Visual Explainer](skills/visual-explainer/)** | Self-contained HTML for diagrams, diff/plan review, tables, and visual explanations |
### Agents - Autonomous Reviewers
@@ -65,11 +57,8 @@ Specialized agents that act as senior technical leads:
| Agent | What it does |
|-------|--------------|
| **[Odoo Code Review](agents/odoo-code-review/SKILL.md)** | Automatically reviews Odoo code with scoring (1-10) and detailed feedback |
| **[Odoo Code Tracer](agents/odoo-code-tracer/SKILL.md)** | Traces execution flow from entry point to end, identifying all function calls |
| **[Odoo Module Generator](agents/odoo-module-generator/SKILL.md)** | Scaffolds complete Odoo 18 modules with proper structure |
| **[Odoo Query Optimizer](agents/odoo-query-optimizer/SKILL.md)** | Diagnoses N+1 queries and provides optimization suggestions |
| **[Odoo Migration Helper](agents/odoo-migration-helper/SKILL.md)** | Converts Odoo 16/17 code to Odoo 18 (tree→list, unlink→ondelete, etc.) |
| **[Odoo Code Review](agents/odoo-code-review/SKILL.md)** | Reviews Odoo code with scoring (110) and structured feedback |
| **[Odoo Code Tracer](agents/odoo-code-tracer/SKILL.md)** | Traces execution flow from an entry point through the call graph |
| **[Planner](agents/planner.md)** | Breaks down complex features into actionable implementation steps |
### Rules - Coding Standards
@@ -88,17 +77,19 @@ Enforced patterns for consistent, secure code:
```
agent-skills/
├── skills/
│ ├── odoo-18.0/ # Odoo 18 development guide
│ ├── odoo-19.0/ # Odoo 19 development guide
│ ├── dtg-base/ # DTGBase utilities (date/period, timezone, batch)
│ ├── payment-integration/ # Payment provider integrations
│ ├── code-review/ # Code review standards
│ ├── brainstorming/ # Feature ideation framework
│ ├── writing-skills/ # Guide for creating skills
── mcp-builder/ # MCP server development guide
├── agents/ # Autonomous code reviewers and planners
├── rules/ # Coding standards and security patterns
── lib/ # Shared resources and images
│ ├── odoo-18.0/ # Odoo 18 guides
│ ├── odoo-19.0/ # Odoo 19 guides
│ ├── dtg-base/ # DTGBase utilities
│ ├── payment-integration/ # Payment integrations
│ ├── code-review/ # Code review standards
│ ├── brainstorming/ # Ideation and spec review
│ ├── writing-skills/ # Authoring AI skills
── mcp-builder/ # MCP servers
│ ├── slide/ # HTML/React slide decks
│ └── visual-explainer/ # HTML diagrams and visual explanations
── agents/ # Odoo reviewers + planner
├── rules/ # Coding style and security
└── lib/ # Shared assets (e.g. images)
```
---
@@ -107,7 +98,7 @@ agent-skills/
Agent Skills works with popular AI-powered IDEs:
- **Cursor** - Full integration via CLI
- **Cursor** - Rules, remote rules, or `npx skills add`
- **Claude Code** - Native skill support
- **Windsurf** - Compatible
- **Aider** - Compatible
@@ -139,8 +130,8 @@ graph LR
| Metric | Value |
|--------|-------|
| Documentation | 10,000+ lines |
| Skill Packs | 8 (Odoo 18.0, 19.0, DTG Base, Payment, Code Review, Brainstorming, Writing, MCP) |
| Agents | 6 (Code Review, Tracer, Module Generator, Query Optimizer, Migration Helper, Planner) |
| Skill packs | 10 (Odoo 18.0, 19.0, DTG Base, Payment, Code Review, Brainstorming, Writing Skills, MCP Builder, Slide, Visual Explainer) |
| Agents | 3 (Odoo Code Review, Odoo Code Tracer, Planner) |
| License | MIT |
---
@@ -154,7 +145,7 @@ We welcome contributions! Here's how you can help:
- **Create agents** - Build specialized reviewers or planners
- **Report issues** - Let us know what's missing or broken
See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
Open an issue or discussion on GitHub if you want to propose changes or new skills.
---
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@unclecat/agent-skills-cli",
"version": "0.1.0",
"version": "1.0.6",
"description": "CLI and docs for installing agent skills by version.",
"bin": {
"agent-skills": "bin/agent-skills.js"
+8 -21
View File
@@ -1,26 +1,13 @@
---
name: odoo-18
description: >-
Odoo 18 development knowledge base with 18 specialized guides covering
Actions (ir.actions.*, cron jobs, server actions), Controllers (HTTP
routing, endpoints, auth types), Data files (XML/CSV records, shortcuts,
noupdate), API Decorators (@api.depends, @api.constrains, @api.ondelete,
@api.onchange, @api.model), Module development (manifest, wizards,
reports), Field types (Char, Text, Monetary, relational fields),
Manifest configuration (__manifest__.py, dependencies, asset bundles),
Mixins (mail.thread, mail.activity.mixin, mail.alias.mixin, utm.mixin),
ORM Model methods (search, CRUD, domain filters, recordsets, prefetch),
Migration scripts (pre/post/end hooks, data migration), OWL frontend
components (hooks, services, lifecycle), Performance optimization (N+1
prevention, batch ops, read_group), QWeb Reports (PDF/HTML, paper formats,
barcodes), Security/ACL (record rules, field permissions, multi-company),
Testing (TransactionCase, HttpCase, mocking, query count assertions),
Transactions (savepoints, UniqueViolation, serialization failures),
Translations (i18n, PO files, translatable fields), XML Views
(list/form/search, xpath inheritance, QWeb templates). Use when writing,
reviewing, or debugging any Odoo 18 Python or XML code, creating or
modifying modules, fixing performance issues, or looking up Odoo 18 API
patterns and best practices.
description: >
Odoo 18 development reference for Python models and ORM (search, domain, read_group, compute fields),
XML/CSV data and views, OWL/JS client code, QWeb reports, security (ACL, record rules, groups),
cron and server actions, migrations and module upgrades, tests, i18n, and performance.
Use this skill whenever work involves Odoo 18 or custom addons—even if the user only pastes a traceback,
mentions addons/ or __manifest__.py, describes form/list/kanban/XML errors, HTTP controllers, or
business rules on models—including building features, fixing bugs, refactoring, or reviewing addon code.
globs: "**/*.{py,xml,csv,js,ts}"
---
# Odoo 18 Skill - Master Index
@@ -34,6 +34,7 @@ Complete reference for Odoo 18 data files: XML structure, records, fields, short
6. [Shortcuts](#shortcuts)
7. [CSV Data Files](#csv-data-files)
8. [noupdate Attribute](#noupdate-attribute)
9. [Data Processing Patterns (Partner Merge)](#data-processing-patterns-partner-merge)
---
@@ -650,6 +651,71 @@ Data in `<data noupdate="1">` is only loaded at installation:
---
## Data Processing Patterns (Partner Merge)
Patterns below are extracted from `odoo/addons/base/wizard/base_partner_merge.py` and are useful when building safe data-migration or merge logic in custom modules.
### 1) Normalize Before Grouping
When finding duplicates, normalize values first so grouping is stable:
- `lower(name)` / `lower(email)` for case-insensitive comparisons
- `replace(vat, ' ', '')` to ignore formatting spaces
This avoids false negatives when data is logically equal but formatted differently.
### 2) SQL for Candidate Detection, ORM for Access-Safe Filtering
`base_partner_merge` uses SQL (`min(id), array_agg(id)`) to detect duplicate groups quickly, then re-reads partners with ORM:
```python
self._cr.execute(query)
for min_id, aggr_ids in self._cr.fetchall():
partners = self.env['res.partner'].search([('id', 'in', aggr_ids)])
```
This pattern combines performance (SQL) with Odoo security/record-rule behavior (ORM).
### 3) Generic FK Rewrite with Savepoint Fallback
For merge operations across many tables:
1. Discover FK relations dynamically
2. Try bulk `UPDATE ... SET fk = dst_id WHERE fk IN src_ids`
3. On unique constraint collision, fallback to deleting conflicting rows
4. Keep each table operation isolated in a savepoint
This prevents one collision from rolling back the whole merge process.
### 4) Reference Field Rewrite (`model,res_id`)
For `reference` fields and models like `ir.attachment`, `mail.followers`, `mail.activity`, `mail.message`, update links from source records to destination records in batch. Always use guarded writes and savepoints.
### 5) Company-Dependent JSONB Data Migration
For company-dependent many2one values stored as JSONB:
- Update per-company values in SQL (`jsonb_each`, `jsonb_object_agg`)
- Merge source JSONB values into destination in deterministic order
- Flush environment after SQL updates
This is safer than partial ORM-only writes when data is stored in JSONB structures.
### 6) Deterministic Destination Selection
The wizard selects destination partner by ordered criteria (`active`, `create_date`) before merge. In custom dedup flows, define and document an explicit winner strategy to keep behavior predictable.
### 7) Defensive Checks Before Merge
Before data merge, validate constraints to avoid corrupt states:
- Do not merge parent with child (`child_of` checks)
- Block conflicting user links
- Enforce consistency checks (for example, same email unless admin)
- Limit merge group size for operational safety
---
## Quick Reference
### record Tag
+453
View File
@@ -0,0 +1,453 @@
---
name: ai-vibe-slides
description: "Create beautiful, professional HTML or React slide decks ready for fullscreen presentation. Use this skill when the user wants to: create a PPT/slide/presentation from an idea or outline; build a visually stunning slide deck from existing content; generate an HTML presentation that can be projected fullscreen; convert a document into a presentation. Trigger when you hear: 'create slides', 'make a PPT', 'presentation', 'slide deck', 'pitch deck', 'vibe ppt', 'make a talk', or any request to create a presentation. This skill produces a single self-contained HTML/React artifact — no backend, no installation, no dependencies."
---
# AI Vibe Slides — Beautiful HTML Slide Decks, Ready to Present
## Goal
Produce **a single HTML or React artifact file** containing a complete slide deck that can:
- Present fullscreen directly in the browser
- Navigate via arrow keys, spacebar, or click
- Look professional, polished, and stylistically consistent
- Print or export to PDF when needed
Inspired by [banana-slides](https://github.com/Anionex/banana-slides): a 3-step pipeline of **Idea → Outline → Finished Slides**, but the output is a self-contained HTML file instead of a fullstack application.
---
## Slide Creation Pipeline
### Step 1: Understand the Request → Build an Outline
When the user provides a request, first **build an outline mentally** (no need to display it unless the user asks):
1. Identify the **main topic** and **target audience** (students, business, tech talk...)
2. Break it into **logical sections**:
- Slide 1: Cover (title + subtitle + author)
- Slides 2-3: Introduction / context
- Middle slides: Core content (one key idea per slide)
- Final slide: Conclusion / Call to action / Thank you
3. Each slide should have: a title, 2-5 bullet points or visual content, and a layout type
If the user only gives a short sentence (e.g., "create slides about AI in healthcare"), automatically expand it into 8-12 slides with a logical structure.
### Step 2: Choose a Design Direction
Based on context, commit to **one clear design direction**:
| Context | Suggested Style |
| ---------------------- | ----------------------------------------------------- |
| Startup pitch deck | Bold, dark theme, gradient accents, strong sans-serif |
| Academic / education | Clean, light, diagram-heavy, readable fonts |
| Tech talk / conference | Modern dark, code-style typography, neon accents |
| Corporate / report | Minimal, professional, navy/white, serif headings |
| Creative / marketing | Colorful, asymmetric layout, bold typography |
| Kids / early education | Pastel, rounded corners, playful icons, large text |
General rules:
- **Pick 2-3 primary colors** and use them consistently across the entire deck
- **1 heading font + 1 body font** (use Google Fonts)
- **Minimal text, generous whitespace** — max 5-6 lines per slide
- **Clear visual hierarchy**: large title → medium content → small notes
### Step 3: Generate the HTML/React Slide Deck
Create **a single file** (`.html` or `.jsx`) containing everything:
---
## HTML Slide Deck Structure
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{Presentation Title}</title>
<link
href="https://fonts.googleapis.com/css2?family={Font1}&family={Font2}&display=swap"
rel="stylesheet"
/>
<style>
/* === RESET + BASE === */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* === SLIDE CONTAINER === */
.slide-deck {
width: 100vw;
height: 100vh;
overflow: hidden;
position: relative;
}
.slide {
width: 100%;
height: 100%;
display: none;
flex-direction: column;
justify-content: center;
padding: 60px 80px;
position: absolute;
top: 0;
left: 0;
}
.slide.active {
display: flex;
}
/* === TYPOGRAPHY === */
h1 {
font-family: "{Font1}", sans-serif;
font-size: 3.2rem;
margin-bottom: 1rem;
}
h2 {
font-family: "{Font1}", sans-serif;
font-size: 2.4rem;
margin-bottom: 1.5rem;
}
p,
li {
font-family: "{Font2}", sans-serif;
font-size: 1.4rem;
line-height: 1.8;
}
/* === THEME COLORS === */
:root {
--bg-primary: #0f172a;
--bg-slide: #1e293b;
--text-primary: #f8fafc;
--text-secondary: #94a3b8;
--accent: #3b82f6;
--accent-2: #8b5cf6;
}
/* === NAVIGATION UI === */
.nav-hint {
position: fixed;
bottom: 20px;
right: 30px;
font-size: 0.8rem;
color: var(--text-secondary);
opacity: 0.5;
}
.slide-counter {
position: fixed;
bottom: 20px;
left: 30px;
font-size: 0.8rem;
color: var(--text-secondary);
}
/* === TRANSITIONS === */
.slide {
animation: fadeIn 0.4s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* === LAYOUT VARIANTS === */
.slide.cover {
justify-content: center;
align-items: center;
text-align: center;
}
.slide.two-column {
flex-direction: row;
gap: 60px;
align-items: center;
}
.slide.two-column .col {
flex: 1;
}
.slide.centered {
align-items: center;
text-align: center;
}
/* === VISUAL ELEMENTS === */
.card {
background: rgba(255, 255, 255, 0.05);
border-radius: 12px;
padding: 24px;
margin: 8px 0;
}
.badge {
display: inline-block;
background: var(--accent);
color: white;
padding: 4px 14px;
border-radius: 20px;
font-size: 0.85rem;
}
.divider {
width: 60px;
height: 4px;
background: var(--accent);
border-radius: 2px;
margin: 16px 0;
}
.icon-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
}
/* === PRINT / PDF EXPORT === */
@media print {
.slide {
page-break-after: always;
display: flex !important;
position: relative;
}
.nav-hint,
.slide-counter {
display: none;
}
}
</style>
</head>
<body>
<div class="slide-deck" id="deck">
<!-- SLIDE 1: COVER -->
<div
class="slide cover active"
style="background: linear-gradient(135deg, var(--bg-primary), #1a1a2e);"
>
<div class="badge">Topic</div>
<h1 style="font-size: 3.8rem; margin-top: 20px;">Main Title</h1>
<p
style="color: var(--text-secondary); font-size: 1.3rem; margin-top: 12px;"
>
Short subtitle description
</p>
<div class="divider" style="margin: 20px auto;"></div>
<p style="color: var(--text-secondary); font-size: 1rem;">
Author — Date
</p>
</div>
<!-- SLIDE 2+: CONTENT -->
<div class="slide">
<h2>Slide Title</h2>
<div class="divider"></div>
<ul>
<li>Key point 1</li>
<li>Key point 2</li>
<li>Key point 3</li>
</ul>
</div>
<!-- ... more slides ... -->
</div>
<div class="slide-counter">
<span id="current">1</span> / <span id="total"></span>
</div>
<div class="nav-hint">← → or click to navigate</div>
<script>
const slides = document.querySelectorAll(".slide");
let currentSlide = 0;
document.getElementById("total").textContent = slides.length;
function showSlide(n) {
slides[currentSlide].classList.remove("active");
currentSlide = (n + slides.length) % slides.length;
slides[currentSlide].classList.add("active");
document.getElementById("current").textContent = currentSlide + 1;
}
document.addEventListener("keydown", (e) => {
if (e.key === "ArrowRight" || e.key === " ")
showSlide(currentSlide + 1);
if (e.key === "ArrowLeft") showSlide(currentSlide - 1);
if (e.key === "f") document.documentElement.requestFullscreen?.();
if (e.key === "Escape") document.exitFullscreen?.();
});
document.querySelector(".slide-deck").addEventListener("click", (e) => {
const x = e.clientX / window.innerWidth;
x > 0.5 ? showSlide(currentSlide + 1) : showSlide(currentSlide - 1);
});
</script>
</body>
</html>
```
---
## Slide Layout Types
Each slide should use the layout that best fits its content:
### 1. Cover Slide
- Centered, extra-large font, gradient background
- Topic badge + main title + subtitle + author
### 2. Section Divider
- Only section title + number, accent color background
- Used to separate major sections of the presentation
### 3. Content + Bullets
- Left-aligned title + list of key points
- Use icons/emoji at the start of each bullet instead of plain dots
### 4. Two-Column
- `.two-column` layout: text on left, visuals/list/cards on right
- Great for comparisons, before-after, text+illustration
### 5. Cards Grid
- 2-3 column grid, each card containing icon + title + short description
- Great for features, benefits, team members
### 6. Big Number / Statistic
- Huge number in the center (font-size: 5rem+) + small label below
- Great for data points, KPIs, impact numbers
### 7. Quote / Highlight
- Large text, centered, with decorative quotation marks
- Different background (light accent color)
### 8. Timeline / Steps
- Horizontal or vertical flexbox, dots connecting each step
- Great for processes, roadmaps, history
### 9. Thank You / CTA
- Centered, simple, contact info or call to action
---
## MANDATORY Design Rules
1. **16:9 aspect ratio**: Always use `width: 100vw; height: 100vh` — each slide fills the entire screen
2. **Minimal text**: Maximum 6 lines per slide. If content is long → split into multiple slides
3. **Large font sizes**: Heading ≥ 2.4rem, body ≥ 1.3rem — must be readable on a projector
4. **High contrast**: Text must be clearly legible against its background. Verify visually
5. **Consistency**: Same fonts, same color palette, same spacing throughout the entire deck
6. **No placeholder images**: Never use `<img src="placeholder">`. Replace with CSS shapes, gradients, icons (emoji or Lucide for React), or inline SVGs
7. **Subtle animation**: Only fadeIn on slide transition. No complex animations that distract
8. **Responsive fullscreen**: Must work well at all screen sizes
9. **Print-ready**: Include `@media print` rules so each slide becomes one printed page
---
## When Using React (.jsx) Instead of HTML
If creating a React artifact, use this pattern:
```jsx
import { useState, useEffect, useCallback } from "react";
const slides = [
{ type: "cover", title: "...", subtitle: "..." },
{ type: "content", title: "...", points: ["...", "..."] },
{ type: "twoColumn", title: "...", left: "...", right: "..." },
// ...
];
export default function SlideDeck() {
const [current, setCurrent] = useState(0);
const next = useCallback(
() => setCurrent((c) => (c + 1) % slides.length),
[],
);
const prev = useCallback(
() => setCurrent((c) => (c - 1 + slides.length) % slides.length),
[],
);
useEffect(() => {
const handleKey = (e) => {
if (e.key === "ArrowRight" || e.key === " ") next();
if (e.key === "ArrowLeft") prev();
if (e.key === "f") document.documentElement.requestFullscreen?.();
};
window.addEventListener("keydown", handleKey);
return () => window.removeEventListener("keydown", handleKey);
}, [next, prev]);
const renderSlide = (slide) => {
switch (slide.type) {
case "cover":
return /* cover layout */;
case "content":
return /* content layout */;
case "twoColumn":
return /* two-column layout */;
// ...
}
};
return (
<div
className="w-screen h-screen overflow-hidden relative"
onClick={(e) => (e.clientX > window.innerWidth / 2 ? next() : prev())}
style={{ fontFamily: "'Outfit', sans-serif" }}
>
{renderSlide(slides[current])}
<div className="fixed bottom-5 left-8 text-sm opacity-40">
{current + 1} / {slides.length}
</div>
</div>
);
}
```
Advantages of React: Tailwind CSS utilities, Lucide icons, more complex logic, recharts for charts.
---
## Pre-Delivery Checklist
- [ ] Correct number of slides (cover + content + closing)
- [ ] Arrow keys ← → work, click navigates
- [ ] Counter displays correct "X / N"
- [ ] Press F for fullscreen
- [ ] All text is readable with sufficient contrast
- [ ] No broken images or placeholders
- [ ] Google Fonts load correctly (or good fallback)
- [ ] Print/PDF exports properly (`@media print`)
- [ ] Consistent style throughout the entire deck
- [ ] Each slide has exactly one key idea, not overloaded with text
---
## Natural Language Editing
After initial creation, the user can request modifications:
- "Switch to a light theme" → update CSS variables
- "Add 2 slides about case studies" → insert slides into the array
- "Slide 3 has too much text, split it" → refactor content across slides
- "Change the font to Playfair Display" → update Google Fonts link + CSS
- "Add a chart to slide 5" → use CSS chart or recharts (React)
On each edit, keep unchanged slides intact and only update what the user requested.