diff --git a/README.md b/README.md index 8618b30..a061bc6 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ links below to their main page. - [**codly-languages**](https://typst.app/universe/package/codly-languages): A set of language configurations for use with [codly](https://typst.app/universe/package/codly). +- [easy-typography](https://typst.app/universe/package/easy-typography): Sets up + sensible typography defaults. - [**glossy**](https://typst.app/universe/package/glossy): A very simple glossary system with easily customizable output. - [**rfc-vibe**](https://typst.app/universe/package/rfc-vibe): Bring RFC language @@ -19,6 +21,9 @@ links below to their main page. create various run-in lists. - [**swank-tex**](https://typst.app/universe/package/swank-tex): Render those funky logos for TeX, LaTeX, and friends. +- [**tasteful-pairings**](https://typst.app/universe/package/tasteful-pairings): + A carefully curated collection of font pairings focusing on readability and + typographic harmony. ## Templates diff --git a/easy-typography/.gitignore b/easy-typography/.gitignore new file mode 100644 index 0000000..f1ca904 --- /dev/null +++ b/easy-typography/.gitignore @@ -0,0 +1,2 @@ +tests/**/out/ +tests/**/diff/ diff --git a/easy-typography/LICENSE b/easy-typography/LICENSE new file mode 100644 index 0000000..a4ad6f1 --- /dev/null +++ b/easy-typography/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Stephen Waits + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/easy-typography/README.md b/easy-typography/README.md new file mode 100644 index 0000000..3485c1c --- /dev/null +++ b/easy-typography/README.md @@ -0,0 +1,65 @@ +# Easy Typography for Typst + +A Typst package that simplifies professional typography by providing sensible +defaults and easy customization options. Focus on your content while ensuring +beautiful, readable documents. + +## Features + +- 🎨 Precise heading scale with clear hierarchy +- 📏 Optimal line height and paragraph spacing +- 📖 Professional text justification and hyphenation +- ⚖️ Balanced vertical rhythm throughout +- ⚡ Simple configuration with reasonable defaults + +## Usage + +Basic usage with default settings: + +```typst +#import "@preview/easy-typography:0.1.0": * +#show: easy-typography + += Your Document Title +Your content here... +``` + +Customized usage with specific fonts: + +```typst +#show: easy-typography.with( + fonts: ( + heading: "Source Sans Pro", + body: "Source Serif Pro" + ), + body-size: 11pt, + paper: "a4", + margin: 2cm +) +``` + +## Configuration Options + +- `body-size`: Base size for body text (default: 10pt) +- `fonts`: Dictionary specifying heading and body fonts + - `heading`: Font for headings (default: "Libertinus Sans") + - `body`: Font for body text (default: "Libertinus Serif") +- `paper`: Paper size setting (optional) +- `margin`: Page margin setting (optional) + +## Example Output + +The package automatically handles: + +- Heading sizes with natural visual hierarchy (H1-H5) +- Optimal spacing between elements +- Professional text justification +- Smart hyphenation +- Consistent vertical rhythm + +See the [example output](thumbnail.png) for more information and a complete +example. + +## License + +MIT License - See [LICENSE](LICENSE) for details. diff --git a/easy-typography/lib.typ b/easy-typography/lib.typ new file mode 100644 index 0000000..5a139b5 --- /dev/null +++ b/easy-typography/lib.typ @@ -0,0 +1 @@ +#import "src/main.typ": easy-typography diff --git a/easy-typography/src/constants.typ b/easy-typography/src/constants.typ new file mode 100644 index 0000000..e7c4624 --- /dev/null +++ b/easy-typography/src/constants.typ @@ -0,0 +1,29 @@ +// Constants + +// space above H1 +#let heading-above-max = 1.25em + +// space above H5 +#let heading-above-min = 0.80em + +// space below H1 +#let heading-below-max = 0.65em + +// space below H5 +#let heading-below-min = 0.55em + +// font size for H1 +#let heading-size-max = 1.10em + +// font size for H5 +#let heading-size-min = 1.00em + +// default text weight -- light is best for reading, and printers are fine with +// it these days +#let body-weight = "light" + +// line spacing -- tight; efficient but still readable with good fonts +#let line-spacing = 1.30 + +// paragraph spacing -- defaults to a double-space +#let paragraph-spacing = 1.70 diff --git a/easy-typography/src/main.typ b/easy-typography/src/main.typ new file mode 100644 index 0000000..c2d57c3 --- /dev/null +++ b/easy-typography/src/main.typ @@ -0,0 +1,102 @@ +#import "constants.typ": * + +/// The main function for easy typography setup. +/// +/// - body-size (): The size of body text (default 10pt). +/// - fonts (): A dictionary specifying heading/body fonts. +/// - paper (str): The paper size to use (none to skip). +/// - margin (): Margin for the page (none to skip). +/// -> content +#let easy-typography( + body-size: 10pt, + fonts: (heading: "Libertinus Sans", body: "Libertinus Serif"), + paper: none, + margin: none, + body +) = { + // Optional page setup + if paper != none { + set page(paper: paper) + } + if margin != none { + set page(margin: margin) + } + + // Paragraphs + set par( + leading: line-spacing * 0.5em, + spacing: paragraph-spacing * 0.5em, + justify: true, + linebreaks: "optimized", + ) + + // Body text + set text( + font: fonts.body, + fallback: false, + style: "normal", + weight: body-weight, + stretch: 100%, + size: body-size, + tracking: 0pt, + spacing: 100% + 0pt, + baseline: 0pt, + overhang: true, + hyphenate: true, + kerning: true, + ligatures: true, + number-width: "proportional", + // number-type: "lining", // commented: intentionally left up to the font to choose + ) + + show table: set text(number-width: "tabular") + + /// Top-heavy easing function for heading sizes/spacing. + /// + /// `sqrt(t)` gives biggest decrease at top, gentlest at bottom. + /// + /// - max (length): Biggest size (H1) + /// - min (length): Smallest size (H5) + /// - level (length): From 1 to 5 + /// -> length + let compute-size(max, min, level) = { + if level <= 1 { + max + } else if level >= 5 { + min + } else { + let t = (level - 1) / 4 + max - (max - min) * calc.sqrt(t) + } + } + + // Heading weight logic + let compute-weight(level) = { + if level <= 1 { + "bold" + } else if level == 2 { + "semibold" + } else if level == 3 { + "medium" + } else { + "regular" + } + } + + // Show headings using computed size/spacing values + show heading: it => block( + breakable: false, + sticky: true, + above: compute-size(heading-above-max, heading-above-min, it.level), + below: compute-size(heading-below-max, heading-below-min, it.level), + text( + font: fonts.heading, + size: compute-size(heading-size-max, heading-size-min, it.level), + weight: compute-weight(it.level), + it + ) + ) + + // Finally, render the body + body +} diff --git a/easy-typography/tests/basic/ref/1.png b/easy-typography/tests/basic/ref/1.png new file mode 100644 index 0000000..267c085 Binary files /dev/null and b/easy-typography/tests/basic/ref/1.png differ diff --git a/easy-typography/tests/basic/test.typ b/easy-typography/tests/basic/test.typ new file mode 100644 index 0000000..2dff79b --- /dev/null +++ b/easy-typography/tests/basic/test.typ @@ -0,0 +1,125 @@ +#import "/lib.typ": * + +#import "@preview/codly:1.2.0": * +#import "@preview/codly-languages:0.1.1": * +#show: codly-init.with() +#codly(languages: codly-languages) + +#show: easy-typography.with( + fonts: (heading: "Source Sans 3", body: "Source Serif 4"), +) + += Introducing Easy Typography + +#set heading(numbering: (..nums) => { + numbering("1.1.", ..nums.pos().slice(1)) +}) + +The `easy-typography` package transforms complex typographic decisions into +simple choices, letting you focus on your content while ensuring professional +results. By adjusting the settings to match your specific needs, you can refine +the aesthetic or adapt your layout for everything from casual reading to formal +publication. + +== Core Typography Features + +The package manages: + +#columns(2)[ +- Precise heading scale with a clear hierarchy +- Optimal line height and paragraph spacing +#colbreak() +- Professional text justification and hyphenation +- Balanced vertical rhythm throughout +] + +These features ensure that your document is both visually appealing and easy to +read. + +=== Type Formatting + +This package automatically adjusts line spacing, paragraph spacing, and +justification to maintain a clean layout. Headings are also carefully weighted +to balance them against the body text, so you can focus on content rather than +tweaking spacing and sizing. Standard formatting like *bold* and _italic_ +integrates seamlessly with `easy-typography`'s approach. + +=== Heading Levels + +The heading scale gracefully steps down, ensuring that each level remains +distinct yet consistent. Behind the scenes, `easy-typography` calculates the +ideal size for each heading, preserving a cohesive visual hierarchy as your +document gets deeper. This approach supports manuals, academic papers, and any +long-form text where structure matters. It also helps in shorter documents, +guaranteeing a crisp layout with minimal effort. + +== Why Typography Matters + +Good typography isn't just about aesthetics. It's about effective communication. +Well-designed text: + +#columns(2)[ +- Improves reading comprehension +- Reduces eye strain +- Maintains reader engagement +#colbreak() +- Establishes visual hierarchy +- Conveys professionalism +] + +Notice how this document's typography enhances readability. The justified text, +proper hyphenation, and optimized line breaks create a clean, professional +appearance. With each heading level, the user can quickly scan and digest +important information. + +== Example Usage and Output + +#set heading(numbering: none) +#show raw.where(block: true): set text(size: 7pt) + +#grid( + columns: (55%, auto), + gutter: 1.0em, +[ + // code + ```typst + #import "@preview/easy-typography:0.1.0": * + #show: easy-typography.with( + fonts: ( + heading: "Source Sans Pro", + body: "Source Serif Pro" + ), + ) + + #lorem(6) + = Level One + #lorem(6) + == Level Two + #lorem(6) + === Level Three + #lorem(6) + ==== Level Four + #lorem(6) + ===== Level Five + #lorem(6) + ``` +], +box( + stroke: 0.5pt + silver, + inset: 0.5em, + radius: 0.2em, + [ + #lorem(6) + = Level One + #lorem(6) + == Level Two + #lorem(6) + === Level Three + #lorem(6) + ==== Level Four + #lorem(6) + ===== Level Five + #lorem(6) + ] + ) // box +) diff --git a/easy-typography/thumbnail.png b/easy-typography/thumbnail.png new file mode 100644 index 0000000..93c4e95 Binary files /dev/null and b/easy-typography/thumbnail.png differ diff --git a/easy-typography/typst.toml b/easy-typography/typst.toml new file mode 100644 index 0000000..616e8c9 --- /dev/null +++ b/easy-typography/typst.toml @@ -0,0 +1,10 @@ +[package] +name = "easy-typography" +version = "0.1.0" +entrypoint = "lib.typ" +authors = ["Stephen Waits "] +license = "MIT" +description = "Sets up sensible typography defaults." +keywords = ["easy", "typography", "defaults"] +repository = "https://github.com/swaits/typst-collection" +exclude = ["thumbnail.png", "tests"] diff --git a/tasteful-pairings/.gitignore b/tasteful-pairings/.gitignore new file mode 100644 index 0000000..f1ca904 --- /dev/null +++ b/tasteful-pairings/.gitignore @@ -0,0 +1,2 @@ +tests/**/out/ +tests/**/diff/ diff --git a/tasteful-pairings/LICENSE b/tasteful-pairings/LICENSE new file mode 100644 index 0000000..a4ad6f1 --- /dev/null +++ b/tasteful-pairings/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Stephen Waits + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tasteful-pairings/README.md b/tasteful-pairings/README.md new file mode 100644 index 0000000..8d4dfba --- /dev/null +++ b/tasteful-pairings/README.md @@ -0,0 +1,57 @@ +# Tasteful Pairings + +A carefully curated collection of font pairings for [Typst](https://typst.app/), +focusing on readability and typographic harmony. Each pairing combines a +sans-serif heading font with a serif body font, following established +typographic principles for clear visual hierarchy and optimal reading +experience. + +## Installation + +```typ +#import "@preview/tasteful-pairings:0.1.0": * +``` + +## Usage + +```typ +#let pairing = font-pairings.at("modern-heritage") + +#show heading: set text(font: pairing.heading) +#set text(font: pairing.body) + += Your Document Title +Your content here... +``` + +## Available Pairings + +- **`ibm-plex`** - Modern corporate-friendly superfamily +- **`noto`** - Extensive language support, highly legible +- **`source`** - Adobe's refined open-source pair +- **`friendly-weather`** - Open Fira Sans with space-efficient Merriweather +- **`android`** - Complete Roboto family look +- **`kindle`** - Amazon's reading-optimized fonts +- **`office`** - Classic Microsoft Office combination +- **`modern-heritage`** - Contemporary Montserrat with timeless Georgia Pro +- **`legible`** - Reading-focused Lexend and Literata + +## Gallery + +![Font pairing examples gallery](thumbnail.png) + +## Philosophy + +The pairings in this collection follow these principles: + +1. **Sans for Headlines, Serif for Body** - Following traditional typographic + wisdom for clear hierarchy +2. **Readability First** - Each pairing is tested for optimal reading experience +3. **Complementary Characteristics** - Fonts are matched based on x-height, + weight balance, and character width +4. **Practical Applications** - Selected for real-world use cases from corporate + documents to digital reading + +## License + +[MIT License](LICENSE). diff --git a/tasteful-pairings/lib.typ b/tasteful-pairings/lib.typ new file mode 100644 index 0000000..dd41dd0 --- /dev/null +++ b/tasteful-pairings/lib.typ @@ -0,0 +1 @@ +#import "src/main.typ": font-pairings diff --git a/tasteful-pairings/src/main.typ b/tasteful-pairings/src/main.typ new file mode 100644 index 0000000..a16b104 --- /dev/null +++ b/tasteful-pairings/src/main.typ @@ -0,0 +1,55 @@ +#let font-pairings = ( + "ibm-plex": ( + heading: "IBM Plex Sans", + body: "IBM Plex Serif", + description: "A modern corporate-friendly superfamily with a wide weight range. Clean, neutral, and highly legible." + ), + + "noto": ( + heading: "Noto Sans", + body: "Noto Serif", + description: "Huge language coverage, highly legible, and neutral. Great for multilingual documents." + ), + + "source": ( + heading: "Source Sans 3", + body: "Source Serif 4", + description: "Adobe's open-source pair. Clean, highly readable, and well-hinted for both screen and print." + ), + + "friendly-weather": ( + heading: "Fira Sans", + body: "Merriweather", + description: "Open, friendly sans plus a space-efficient modern serif. Good for text-heavy documents." + ), + + "android": ( + heading: "Roboto", + body: "Roboto Serif", + description: "A complete Android-friendly look. Roboto is extremely common; Roboto Serif is its matching new serif companion." + ), + + "kindle": ( + heading: "Amazon Ember", + body: "Bookerly", + description: "The Kindle pairing. Bookerly is a warm, book-like serif; Amazon Ember is a clean, readable sans." + ), + + "office": ( + heading: "Calibri", + body: "Cambria", + description: "A classic Microsoft Office pairing. Calibri (sans) for headings, Cambria (serif) for body text." + ), + + "modern-heritage": ( + heading: "Montserrat", + body: "Georgia Pro", + description: "Merges the warm, traditional forms of Georgia Pro with Montserrat’s clean, geometric lines. A modern-yet-classic pairing, equally suited to formal reports or stylish web layouts." + ), + + "legible": ( + heading: "Lexend", + body: "Literata", + description: "An ultra-legible pairing designed for reading fluency. Lexend’s tall x-height and open shapes reduce visual stress, while Literata brings a warm, bookish feel to body text." + ), +) diff --git a/tasteful-pairings/tests/gallery/ref/1.png b/tasteful-pairings/tests/gallery/ref/1.png new file mode 100644 index 0000000..620b174 Binary files /dev/null and b/tasteful-pairings/tests/gallery/ref/1.png differ diff --git a/tasteful-pairings/tests/gallery/test.typ b/tasteful-pairings/tests/gallery/test.typ new file mode 100644 index 0000000..ea8d9b7 --- /dev/null +++ b/tasteful-pairings/tests/gallery/test.typ @@ -0,0 +1,23 @@ +#import "/lib.typ": * + +#set page(margin: 1em, height: auto, width: 5.5in) +#set par(justify: true, linebreaks: "optimized") + +#let keys = font-pairings.keys().sorted() + +#for key in keys { + block( + stroke: 1pt + navy, + inset: 1em, + radius: 1em, + [ + #let pairing = font-pairings.at(key) + #show heading: set text(font: pairing.heading, weight: "bold") + = #pairing.heading & #pairing.body #h(1fr) #text(fill: eastern, weight: "light", size: 0.8em, baseline: -3pt, ["#key"]) + #set text(font: pairing.body, weight: "light") + #pairing.description + + #lorem(20) + ] + ) +} diff --git a/tasteful-pairings/thumbnail.png b/tasteful-pairings/thumbnail.png new file mode 100644 index 0000000..0f69a0c Binary files /dev/null and b/tasteful-pairings/thumbnail.png differ diff --git a/tasteful-pairings/typst.toml b/tasteful-pairings/typst.toml new file mode 100644 index 0000000..7615847 --- /dev/null +++ b/tasteful-pairings/typst.toml @@ -0,0 +1,10 @@ +[package] +name = "tasteful-pairings" +version = "0.1.0" +entrypoint = "lib.typ" +authors = ["Stephen Waits "] +license = "MIT" +description = "A carefully curated collection of font pairings." +keywords = ["font", "pairing", "typography"] +repository = "https://github.com/swaits/typst-collection" +exclude = ["thumbnail.png", "tests"]