Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]

### Added
- **Notebook-style templates** - `notebook-cover` and `notebook-page`
(1080x1350) replicate the viral handwritten study-notes carousel format:
ruled paper, spiral binding, dashed callout boxes, and a cloud punchline.
Includes bundled handwritten fonts Kalam (Light/Regular/Bold) and Caveat
(Medium/Bold), drawn inline SVG pipeline icons (no emoji), shrink-to-fit
hero/chapter titles, and dynamic-height dashed boxes and punchline bubble.

- **Multi-slide HTTP API** — `POST /api/render` now accepts
`response_format: "json"` to render every slide of a carousel and return them
Expand Down
2 changes: 1 addition & 1 deletion docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default defineConfig({
text: 'Social Media',
collapsed: true,
items: [
{ text: 'Social Quote', link: '/templates/social-quote' }, { text: 'Dev Quote', link: '/templates/dev-quote' }, { text: 'Twitter/X Quote', link: '/templates/twitter-quote' }, { text: 'TikTok Quote', link: '/templates/tiktok-quote' }, { text: 'WhatsApp Chat', link: '/templates/whatsapp-chat' }, { text: 'Notes App', link: '/templates/notes-app' }, { text: 'Instagram Story', link: '/templates/instagram-story' }, { text: 'LinkedIn Card', link: '/templates/linkedin-card' }, { text: 'Pinterest Pin', link: '/templates/pinterest-pin' }, { text: 'Social Poll', link: '/templates/social-poll' }, { text: 'Tweet Embed', link: '/templates/tweet-embed' }
{ text: 'Social Quote', link: '/templates/social-quote' }, { text: 'Dev Quote', link: '/templates/dev-quote' }, { text: 'Twitter/X Quote', link: '/templates/twitter-quote' }, { text: 'TikTok Quote', link: '/templates/tiktok-quote' }, { text: 'WhatsApp Chat', link: '/templates/whatsapp-chat' }, { text: 'Notes App', link: '/templates/notes-app' }, { text: 'Notebook Cover', link: '/templates/notebook-cover' }, { text: 'Notebook Page', link: '/templates/notebook-page' }, { text: 'Instagram Story', link: '/templates/instagram-story' }, { text: 'LinkedIn Card', link: '/templates/linkedin-card' }, { text: 'Pinterest Pin', link: '/templates/pinterest-pin' }, { text: 'Social Poll', link: '/templates/social-poll' }, { text: 'Tweet Embed', link: '/templates/tweet-embed' }
],
},
{
Expand Down
16 changes: 16 additions & 0 deletions docs/templates/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,22 @@ Cosy ships with **148 templates** out of the box. Browse the gallery below, or u
<span class="dims">1080×1350</span>
</div>
</a>

<a href="./notebook-cover" class="template-card">
<img src="https://s3.ajianaz.dev/hermes/codecoradev/cosy/preview/notebook-cover.png" alt="Notebook Cover" loading="lazy" />
<div class="template-info">
<h3>Notebook Cover</h3>
<span class="dims">1080&times;1350</span>
</div>
</a>

<a href="./notebook-page" class="template-card">
<img src="https://s3.ajianaz.dev/hermes/codecoradev/cosy/preview/notebook-page.png" alt="Notebook Page" loading="lazy" />
<div class="template-info">
<h3>Notebook Page</h3>
<span class="dims">1080&times;1350</span>
</div>
</a>
<a href="./rate-limit" class="template-card">
<img src="https://s3.ajianaz.dev/hermes/codecoradev/cosy/preview/rate-limit.png" alt="Rate Limit" loading="lazy" />
<div class="template-info">
Expand Down
84 changes: 84 additions & 0 deletions docs/templates/notebook-cover.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Notebook Cover

Notebook/study-notes carousel cover: handwritten hero, tagline banner, 6-step pipeline with inline SVG icons, dashed intro box, and a 9-row table of contents with dot leaders. Pairs with `notebook-page` for the inner slides.

## Preview

![Notebook Cover](https://s3.ajianaz.dev/hermes/codecoradev/cosy/preview/notebook-cover.png)

## Dimensions

- **Width:** 1080px
- **Height:** 1350px
- **Aspect Ratio:** 1080:1350

## Fonts

- Kalam
- Caveat
- Inter

## Brand Fields

| Field | Type | Required | Max / Default |
|---|---|---|---|
| `accent_color` | text | - | #1e3a8a |
| `accent_color_end` | text | - | #6d28d9 |
| `bg_color` | text | - | #fdfcf5 |
| `bg_color_end` | text | - | #fdfcf5 |
| `bg_image` | image | - | - |
| `bg_image_opacity` | number | - | 0.15 |
| `logo` | image | - | - |
| `show_brand` | boolean | - | false |
| `brand_handle` | text | - | @ajianaz |
| `brand_name` | text | yes | ajianaz |

## Slide Fields

| Field | Type | Required | Max / Default |
|---|---|---|---|
| `header_handle` | text | yes | max 30 - Left header text (e.g. IG handle). |
| `page_label` | text | yes | max 12 - Right header label (e.g. 'cover'). |
| `hero_title` | text | yes | max 18 - Big display title (Caveat). |
| `hero_font_size` | number | - | Hero font size (140-170). |
| `hero_subtitle` | text | yes | max 46 - Uppercase subtitle under hero. |
| `tagline` | text | yes | max 60 - Italic banner line. |
| `icon1` | text | - | Pipeline icon 1: note/phone/brain/search/spark/rocket. |
| `icon2` | text | - | Pipeline icon 2. |
| `icon3` | text | - | Pipeline icon 3. |
| `icon4` | text | - | Pipeline icon 4. |
| `icon5` | text | - | Pipeline icon 5. |
| `icon6` | text | - | Pipeline icon 6. |
| `label1` | text | yes | max 14 - Pipeline label 1. |
| `label2` | text | yes | max 14 - Pipeline label 2. |
| `label3` | text | yes | max 14 - Pipeline label 3. |
| `label4` | text | yes | max 14 - Pipeline label 4. |
| `label5` | text | yes | max 14 - Pipeline label 5. |
| `label6` | text | yes | max 14 - Pipeline label 6. |
| `intro_lead` | text | yes | max 20 - Bold lead inside dashed intro box (purple). |
| `intro_text` | text | yes | max 150 - Intro sentence (wrapped). |
| `toc_title` | text | yes | max 24 - Table-of-contents heading. |
| `toc1` | text | yes | max 22 |
| `pg1` | text | yes | max 8 |
| `toc2` | text | yes | max 22 |
| `pg2` | text | yes | max 8 |
| `toc3` | text | yes | max 22 |
| `pg3` | text | yes | max 8 |
| `toc4` | text | yes | max 22 |
| `pg4` | text | yes | max 8 |
| `toc5` | text | yes | max 22 |
| `pg5` | text | yes | max 8 |
| `toc6` | text | yes | max 22 |
| `pg6` | text | yes | max 8 |
| `toc7` | text | yes | max 22 |
| `pg7` | text | yes | max 8 |
| `toc8` | text | yes | max 22 |
| `pg8` | text | yes | max 8 |
| `toc9` | text | yes | max 22 |
| `pg9` | text | yes | max 8 |

## Usage

```bash
cosy render --template notebook-cover --data input.json --output output.png
```
59 changes: 59 additions & 0 deletions docs/templates/notebook-page.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Notebook Page

Notebook/study-notes content page: chapter title box, star bullets, dashed example box (optional), cloud punchline callout, optional second dashed box, and a bottom brand line. Pairs with `notebook-cover`.

## Preview

![Notebook Page](https://s3.ajianaz.dev/hermes/codecoradev/cosy/preview/notebook-page.png)

## Dimensions

- **Width:** 1080px
- **Height:** 1350px
- **Aspect Ratio:** 1080:1350

## Fonts

- Kalam
- Caveat
- Inter

## Brand Fields

| Field | Type | Required | Max / Default |
|---|---|---|---|
| `accent_color` | text | - | #1e3a8a |
| `accent_color_end` | text | - | #6d28d9 |
| `bg_color` | text | - | #fdfcf5 |
| `bg_color_end` | text | - | #fdfcf5 |
| `bg_image` | image | - | - |
| `bg_image_opacity` | number | - | 0.15 |
| `logo` | image | - | - |
| `show_brand` | boolean | - | false |
| `brand_handle` | text | - | @ajianaz |
| `brand_name` | text | yes | ajianaz |

## Slide Fields

| Field | Type | Required | Max / Default |
|---|---|---|---|
| `header_handle` | text | yes | max 30 - Left header text (e.g. IG handle). |
| `page_label` | text | yes | max 12 - Right header label (e.g. 'Page 1'). |
| `chapter_title` | text | yes | max 30 - Chapter title inside the box. |
| `lead_text` | text | yes | max 140 - Lead sentence (wrapped). |
| `bullet1` | text | - | max 120 - Bullet point 1. |
| `bullet2` | text | - | max 120 - Bullet point 2. |
| `bullet3` | text | - | max 120 - Bullet point 3. |
| `box_title` | text | - | max 30 - Dashed box title (omit to hide box). |
| `box_text` | text | - | max 200 - Dashed box body (wrapped). |
| `box_color` | color | - | Dashed box border/title color (default accent). |
| `punchline` | text | yes | max 90 - Cloud callout punchline (wrapped). |
| `extra_title` | text | - | max 30 - Second dashed box title (omit to hide). |
| `extra_text` | text | - | max 180 - Second dashed box body (wrapped). |
| `footer_line` | text | - | max 60 - Bottom center line (brand/CTA). |

## Usage

```bash
cosy render --template notebook-page --data input.json --output output.png
```
Binary file added src/assets/fonts/Caveat-Bold.ttf
Binary file not shown.
Binary file added src/assets/fonts/Caveat-Medium.ttf
Binary file not shown.
Binary file added src/assets/fonts/Kalam-Bold.ttf
Binary file not shown.
Binary file added src/assets/fonts/Kalam-Light.ttf
Binary file not shown.
Binary file added src/assets/fonts/Kalam-Regular.ttf
Binary file not shown.
33 changes: 32 additions & 1 deletion src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,8 +264,39 @@ pub fn build_font_db(custom_dir: Option<&Path>) -> anyhow::Result<usvg::fontdb::
"Bold",
include_bytes!("assets/fonts/SpaceGrotesk-Bold.ttf"),
);
// Handwritten fonts: Kalam (body) + Caveat (display) for notebook-style templates
load_bundled_font(
&mut db,
"Kalam",
"Light",
include_bytes!("assets/fonts/Kalam-Light.ttf"),
);
load_bundled_font(
&mut db,
"Kalam",
"Regular",
include_bytes!("assets/fonts/Kalam-Regular.ttf"),
);
load_bundled_font(
&mut db,
"Kalam",
"Bold",
include_bytes!("assets/fonts/Kalam-Bold.ttf"),
);
load_bundled_font(
&mut db,
"Caveat",
"Medium",
include_bytes!("assets/fonts/Caveat-Medium.ttf"),
);
load_bundled_font(
&mut db,
"Caveat",
"Bold",
include_bytes!("assets/fonts/Caveat-Bold.ttf"),
);
log::debug!(
"Loaded 10 bundled fonts (Inter R/B/SB/Black/I/BI, JetBrains Mono R, SpaceGrotesk M/SB/B)"
"Loaded 15 bundled fonts (Inter R/B/SB/Black/I/BI, JetBrains Mono R, SpaceGrotesk M/SB/B, Kalam L/R/B, Caveat M/B)"
);

// 2. Load system fonts (may fail in containers — that's OK)
Expand Down
54 changes: 54 additions & 0 deletions templates/notebook-cover/defaults.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"brand": {
"brand_name": "ajianaz",
"brand_handle": "@ajianaz",
"bg_color": "#fdfcf5",
"bg_color_end": "#fdfcf5",
"accent_color": "#1e3a8a",
"accent_color_end": "#6d28d9",
"show_brand": false
},
"slides": [
{
"header_handle": "IG: ajianaz",
"page_label": "cover",
"hero_title": "Catatan",
"hero_font_size": 150,
"hero_subtitle": "CARI BERDASARKAN ARTI, BUKAN KATA KUNCI",
"tagline": "Ide yang kamu tulis tidak boleh hilang begitu saja.",
"icon1": "note",
"icon2": "phone",
"icon3": "brain",
"icon4": "search",
"icon5": "spark",
"icon6": "rocket",
"label1": "Tulis Ide",
"label2": "Di HP",
"label3": "Makna",
"label4": "Cari Arti",
"label5": "Ketemu",
"label6": "Lanjut",
"intro_lead": "Pencarian makna",
"intro_text": "menemukan catatanmu walau kamu tidak ingat kata-kata persis yang dulu kamu ketik.",
"toc_title": "Apa Saja Isinya?",
"toc1": "Masalah: ide hilang",
"pg1": "Hal. 1",
"toc2": "Kata kunci kerap gagal",
"pg2": "Hal. 2",
"toc3": "Solusi: cari makna",
"pg3": "Hal. 3",
"toc4": "Cara mesin paham arti",
"pg4": "Hal. 4",
"toc5": "Semua di HP-mu sendiri",
"pg5": "Hal. 5",
"toc6": "Arti 100% offline",
"pg6": "Hal. 6",
"toc7": "Checklist aplikasi",
"pg7": "Hal. 7",
"toc8": "Mitos vs fakta",
"pg8": "Hal. 8",
"toc9": "Kesimpulan dan langkah",
"pg9": "Hal. 9"
}
]
}
Loading
Loading