Crispy Print

Print system based on Typst using Vue UI on top of Frappe Frameworks 【矢量打印】

Install Crispy Print

bench get-app https://github.com/agatho-daemon/crispy_print

Tags

  • frappe
  • pdf-generation
  • typst
  • vector-printing

Add the Frappe Gems badge to your README

Maintain Crispy Print? Paste this into your README:

[![Listed on Frappe Gems](https://frappegems.com/api/method/frappe_gems.seo.badge?app=agatho-daemon%2Fcrispy_print)](https://frappegems.com/gems/apps/agatho-daemon/crispy_print)

About Crispy Print

Crispy Print

Modern print format designer for Frappe using the Typst typesetting system. Build PDF‑native print formats with a Vue 3 visual builder and real-time preview.

License: MIT Tests Python Frappe

Project Status

Alpha / Work in progress. Expect frequent changes while features are still settling.

> Why Typst instead of HTML/CSS? Typst provides superior PDF typography, precise layout control, and professional typesetting features that are difficult to achieve with browser-based rendering. Perfect for invoices, reports, certificates, and other print-critical documents.

Table of Contents

Features

  • Visual Print Format Builder - Drag-and-drop interface for designing print layouts
  • Real-time Typst Preview - See PDF output as you design with live SVG preview
  • Native PDF Generation - High-quality PDFs via Typst CLI (no browser printing)
  • DocType Integration - Create custom formats for any Frappe DocType
  • Letterhead Support - Use Letter Head documents with automatic image handling
  • Logo Support - Add company logo to page.
  • Custom Fonts - Support for system fonts, custom fonts, and bundled fonts
  • Print Preview Page - Dedicated preview page for testing formats with actual documents
  • QR Code Integration - Automatic QR code generation for documents
  • Raw Typst Mode - Advanced users can write Typst markup directly
  • Dual-Mode Report Builder - Basic visual controls for report templates with Advanced Raw Typst mode for full customization
  • Report Mode Guardrails - Safe Basic/Advanced switching with signature checks to prevent accidental overwrite of custom Typst

Requirements

Typst CLI (Required)

Typst must be installed on your system before installing the app.

macOS (Homebrew)

brew install typst

Linux (Ubuntu/Debian) & Windows WSL

curl -L -o typst.tar.xz https://github.com/typst/typst/releases/latest/download/typst-x86_64-unknown-linux-musl.tar.xz
tar -xf typst.tar.xz
sudo mv typst-x86_64-unknown-linux-musl/typst /usr/local/bin/

> Windows users: Frappe requires WSL. Install Typst inside your WSL environment using the Linux commands above.

Or download from Typst Releases

Verify Installation

typst --version
# Should output: typst 0.11.0 or higher

Frappe Compatibility

  • Frappe: v15 or later (all Python/Node.js dependencies already satisfied)
  • Python dependency: pyqrcode (installed with the app; required for QR SVG generation)

Installation

1. Install Typst CLI

See Requirements above - Typst must be installed first.

2. Get and Install the App

cd ~/frappe-bench
bench get-app https://github.com/agatho-daemon/crispy_print --branch develop
bench --site your-site install-app crispy_print
bench restart

3. Verify Installation

# Check app is installed
bench --site your-site list-apps | grep crispy_print

# Test Typst integration
bench --site your-site console
>>> from crispy_print.api import get_typst_local_fonts
>>> fonts = get_typst_local_fonts()
>>> print(len(fonts), "fonts available")

4. Build Assets (Development Only)

If you're developing the app:

cd apps/crispy_print/crispy_print/public/js
yarn install
cd ~/frappe-bench
bench build --app crispy_print

Quick Start

Creating Your First Print Format

> ⚠️ CRITICAL: You must set at least one format as Default for a DocType. The Typst print button appears on document forms only when a default format exists for that DocType.

Step-by-step:

  1. Create a new format

    • Navigate to: DeskCrispy PrintCrispy Format
    • Click New
    • Enter Name (e.g., "Sales Invoice Modern")
    • Select DocType (e.g., "Sales Invoice")
    • Select Module (e.g., "Crispy Print")
    • Save
  2. Set as default ⚠️ (Required for button to appear!)

    • Check the "Set as Default" checkbox
    • Save again
  3. Design your layout

    • Click Open Builder button
    • Add sections: Click "+ Add Section"
    • Drag fields: From right pane to layout grid
    • Configure fields: Click field to edit label, style, alignment
    • Add tables: Drag table fields (e.g., "items") for line items
    • Adjust columns: Split sections into 1-4 columns
  4. Configure page settings (left sidebar)

    • Paper Size: A4, Letter, etc.
    • Margins: Adjust spacing
    • Fonts: Select font family
    • Letterhead: Optional background image
    • QR Code: Enable for verification
  5. Save and test

    • Click Save
    • Open any document of that DocType (e.g., Sales Invoice)
    • Look for Typst button in toolbar (top-right)
    • Click to preview and download PDF

Using Your Print Format

Once a default format exists, the Typst button appears automatically on all documents of that DocType.

From Document: 1. Open document (e.g., SI-2024-001) 2. Click Typst button in toolbar 3. Preview opens with your default format 4. Click Download PDF

Direct URL:

/app/crispy-print/{doctype}/{docname}/{format_name}

Font Configuration

Bundled Fonts

The app automatically includes fonts from crispy_print/public/vendor/typst/. These fonts are available to all print formats without additional configuration.

System Fonts

Typst automatically discovers system fonts. On Linux, it searches standard directories like /usr/share/fonts and ~/.local/share/fonts.

Custom Fonts

To add custom fonts outside the Frappe bench:

Add to your shell profile (~/.bashrc, ~/.zshrc, or ~/.profile):

export TYPST_FONT_PATHS="/path/to/custom/fonts:/another/font/path"

Then restart your bench:

bench restart

Option 2: Typst Font Directory

Set the dedicated Typst font directory:

export TYPST_FONT_DIR="$HOME/.fonts/typst"

Create the directory and add fonts:

mkdir -p ~/.fonts/typst
cp /path/to/font.ttf ~/.fonts/typst/

Frappe Site Configuration

You can also configure the Typst binary path in site_config.json:

{
  "TYPST_BIN": "/usr/local/bin/typst"
}

Font Discovery

The app's get_typst_local_fonts() API method returns all available fonts by running:

typst fonts

This includes: - System fonts - Fonts in TYPST_FONT_PATHS - Bundled fonts from crispy_print/public/vendor/typst/

Architecture

Build System

This app uses Frappe v15's native esbuild bundler - no separate Vite or webpack setup required.

  • Bundle Entry: crispy_print/public/js/crispy_print.bundle.js
  • Build Command: bench build --app crispy_print
  • Output: Single JavaScript bundle with inlined CSS (~1.7MB)
  • Plugin: Uses frappe-vue-style to automatically inline Vue SFC styles

Project Structure

crispy_print/
├── crispy_print/
│   ├── api.py                            # Whitelisted API methods
│   ├── hooks.py                          # App hooks
│   ├── public/
│   │   ├── js/
│   │   │   ├── crispy_print.bundle.js    # Main entry (builder)
│   │   │   ├── crispy_preview.bundle.js  # Preview page entry
│   │   │   ├── components/               # Reusable Vue components
│   │   │   ├── composables/              # Vue composables (useStore)
│   │   │   ├── pages/
│   │   │   │   ├── CrispyPFB.vue         # Print Format Builder
│   │   │   │   └── CrispyPP.vue          # Print Preview
│   │   │   ├── typst/
│   │   │   │   ├── createTypstWorker.ts  # Web worker factory
│   │   │   │   ├── setupWorker.ts        # Worker orchestration
│   │   │   │   ├── JSONToTypst.ts        # Layout → Typst translator
│   │   │   │   └── worker.ts             # Typst compilation worker
│   │   │   └── utils/
│   │   │       ├── layout.ts             # Layout type definitions
│   │   │       └── formatLoader.ts       # Format data utilities
│   │   └── vendor/typst/                 # Bundled fonts (optional)
│   ├── doctype/
│   │   └── crispy_format/                # Crispy Format DocType
│   └── page/
│       ├── crispy_print_builder/         # Builder page (Frappe desk)
│       └── typst_print/                  # Preview page (Frappe desk)
├── pyproject.toml                        # Python dependencies & config
└── README.md

Key Components

Pages: - Crispy Format Builder (/app/crispy-format-builder) - 4-pane builder; DocType uses visual layout, Report supports Basic + Advanced Raw Typst modes - Crispy Print Preview (/app/crispy-print/{doctype}/{docname}/{format}) - Document preview page

Core Files: - api.py - Backend API: Typst compilation, font discovery, letterhead handling - CrispyPFB.vue - Main builder component with drag-drop layout editor - CrispyPP.vue - Preview component with format/settings controls - useStore.ts - Centralized state management (layout, page settings, metadata) - setupWorker.ts - Typst worker lifecycle and compilation orchestration - JSONToTypst.ts - Translates JSON layout structure to Typst markup - worker.ts - Web Worker for async Typst compilation via API - formatLoader.ts - Utilities for loading Crispy Format documents

Development

Frontend Dependencies

For TypeScript/Vue IntelliSense in VS Code and the color picker bundle (@simonwep/pickr):

cd apps/crispy_print/crispy_print/public/js
yarn install

This installs local dependencies used by the frontend bundle: - package.json, yarn.lock - Type dependencies - tsconfig.json - TypeScript configuration - node_modules/ - Type definitions

Note: Required for building.

Building

# Build the app
bench build --app crispy_print

# Clear cache after changes
bench clear-cache && bench clear-website-cache

# Development workflow
bench start  # Run with auto-reload enabled

Running Tests

Frontend Tests (TypeScript/Vue):

cd apps/crispy_print/crispy_print/public/js

# Run all tests
yarn test:unit

# Run specific batch
yarn test:unit:batch6

# Watch mode
yarn test:unit -- --watch

Backend Tests (Python):

# Run all tests
bench --site your-site run-tests --app crispy_print

# Run specific module
bench --site your-site run-tests --module crispy_print.tests.test_api

# Run DocType tests
bench --site your-site run-tests --doctype "Crispy Format"

Test Coverage: - Frontend: 67 tests across 27 test files (100% passing) - Backend: 29 tests across 2 test files (100% passing) - Total: 96 tests

See TEST_COVERAGE.md for details.

Vue Component Guidelines

All Vue components use `


For dynamically created DOM (e.g., `.typst-page` elements), apply styles via JavaScript:

```typescript
const page = document.createElement("div")
page.className = "typst-page"
page.style.marginBottom = "1.5rem"
page.style.boxShadow = "0 4px 12px rgba(148, 163, 184, 0.25)"

Usage

Related Developer Tools apps for Frappe & ERPNext

  • Frappe — Low code web framework for real world applications, in Python and Javascript
  • Frappe Docker — Docker environment for developing, deploying, and running Frappe applications (ERPNext and custom apps) in production and development
  • Builder — Craft beautiful websites effortlessly with an intuitive visual builder and publish them instantly
  • Bench — CLI to manage Multi-tenant deployments for Frappe apps
  • Frappe Ui — A set of components and utilities for rapid UI development
  • Press — Full service cloud hosting for the Frappe stack - powers Frappe Cloud
  • Gameplan — Open Source Discussions Platform for Remote Teams
  • Doppio — A Frappe app (CLI) to magically setup single page applications and Vue/React powered desk pages on your custom Frappe apps.