diff --git a/crates/typst-docs/src/html.rs b/crates/typst-docs/src/html.rs
index ea81fa5c9..c79f07cb8 100644
--- a/crates/typst-docs/src/html.rs
+++ b/crates/typst-docs/src/html.rs
@@ -356,7 +356,7 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html {
md::escape::escape_html(&mut buf, &display).unwrap();
buf.push_str("");
return Html::new(buf);
- } else if !matches!(lang, "example" | "typ") {
+ } else if !matches!(lang, "example" | "typ" | "preview") {
let set = &*typst_library::text::SYNTAXES;
let buf = syntect::html::highlighted_html_for_string(
&display,
@@ -369,10 +369,14 @@ fn code_block(resolver: &dyn Resolver, lang: &str, text: &str) -> Html {
return Html::new(buf);
}
- let root = typst::syntax::parse(&display);
- let highlighted = Html::new(typst::syntax::highlight_html(&root));
- if lang == "typ" {
- return Html::new(format!("
{}
", highlighted.as_str()));
+ let mut highlighted = None;
+ if matches!(lang, "example" | "typ") {
+ let root = typst::syntax::parse(&display);
+ let html = Html::new(typst::syntax::highlight_html(&root));
+ if lang == "typ" {
+ return Html::new(format!("{}
", html.as_str()));
+ }
+ highlighted = Some(html);
}
let id = FileId::new(None, VirtualPath::new("main.typ"));
diff --git a/crates/typst-docs/src/lib.rs b/crates/typst-docs/src/lib.rs
index 30ba4ebb9..d32b5d66f 100644
--- a/crates/typst-docs/src/lib.rs
+++ b/crates/typst-docs/src/lib.rs
@@ -77,7 +77,7 @@ pub trait Resolver {
fn image(&self, filename: &str, data: &[u8]) -> String;
/// Produce HTML for an example.
- fn example(&self, hash: u128, source: Html, frames: &[Frame]) -> Html;
+ fn example(&self, hash: u128, source: Option, frames: &[Frame]) -> Html;
/// Determine the commits between two tags.
fn commits(&self, from: &str, to: &str) -> Vec;
@@ -780,7 +780,7 @@ mod tests {
None
}
- fn example(&self, _: u128, _: Html, _: &[Frame]) -> Html {
+ fn example(&self, _: u128, _: Option, _: &[Frame]) -> Html {
Html::new(String::new())
}
diff --git a/crates/typst/src/geom/color.rs b/crates/typst/src/geom/color.rs
index a6d2135f3..260137ea9 100644
--- a/crates/typst/src/geom/color.rs
+++ b/crates/typst/src/geom/color.rs
@@ -32,158 +32,122 @@ const ANGLE_EPSILON: f32 = 1e-5;
/// - HSL through the [`color.hsl` function]($color.hsl)
/// - HSV through the [`color.hsv` function]($color.hsv)
///
-/// Typst provides the following built-in colors:
-///
-/// `black`, `gray`, `silver`, `white`, `navy`, `blue`, `aqua`, `teal`,
-/// `eastern`, `purple`, `fuchsia`, `maroon`, `red`, `orange`, `yellow`,
-/// `olive`, `green`, and `lime`.
///
/// # Example
-/// The predefined colors and the color constructors are available globally and
-/// also in the color type's scope, so you can write either of the following
-/// two:
+///
/// ```example
/// #rect(fill: aqua)
-/// #rect(fill: color.aqua)
/// ```
///
-/// ## Color maps
-/// Typst also includes a number of preset color maps. In the following section,
-/// the list of available color maps is given, along with a sample of each gradient
-/// and relevant comments. Most of these color maps are chosen to be color blind
-/// friendly.
+/// # Predefined colors
+/// Typst defines the following built-in colors:
///
-/// ### Turbo
-/// The [`turbo`]($color.map.turbo) gradient is a rainbow-like gradient that is
-/// perceptually uniform. You can learn more about the turbo color map on
-/// Google's [blog post](https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html).
+/// | Color | Definition |
+/// |-----------|:-------------------|
+/// | `black` | `{luma(0)}` |
+/// | `gray` | `{luma(170)}` |
+/// | `silver` | `{luma(221)}` |
+/// | `white` | `{luma(255)}` |
+/// | `navy` | `{rgb("#001f3f")}` |
+/// | `blue` | `{rgb("#0074d9")}` |
+/// | `aqua` | `{rgb("#7fdbff")}` |
+/// | `teal` | `{rgb("#39cccc")}` |
+/// | `eastern` | `{rgb("#239dad")}` |
+/// | `purple` | `{rgb("#b10dc9")}` |
+/// | `fuchsia` | `{rgb("#f012be")}` |
+/// | `maroon` | `{rgb("#85144b")}` |
+/// | `red` | `{rgb("#ff4136")}` |
+/// | `orange` | `{rgb("#ff851b")}` |
+/// | `yellow` | `{rgb("#ffdc00")}` |
+/// | `olive` | `{rgb("#3d9970")}` |
+/// | `green` | `{rgb("#2ecc40")}` |
+/// | `lime` | `{rgb("#01ff70")}` |
///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.turbo))
-/// ```
+/// The predefined colors and the most important color constructors are
+/// available globally and also in the color type's scope, so you can write
+/// either `color.red` or just `red`.
///
-/// ### Cividis
-/// The [`cividis`]($color.map.cividis) gradient is a blue to gray to yellow
-/// gradient. You can learn more about the Cividis color map on the
-/// Berkley Institute for Data Science's [blog post](https://bids.github.io/colormap/).
+/// ```preview
+/// #let colors = (
+/// "black", "gray", "silver", "white",
+/// "navy", "blue", "aqua", "teal",
+/// "eastern", "purple", "fuchsia",
+/// "maroon", "red", "orange", "yellow",
+/// "olive", "green", "lime",
+/// )
///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.cividis))
-/// ```
-///
-/// ### Rainbow
-/// The [`rainbow`]($color.map.rainbow) gradient cycles through the full color
-/// spectrum. This color map is best used by setting the interpolation color
-/// space to [HSL]($color.hsl).
-///
-/// **Attention:** The rainbow gradient is _not suitable_ for data visualization
-/// because it is not perceptually uniform, so the differences between values
-/// become unclear to your readers. It should only be used for decorative
-/// purposes.
-///
-/// ```example
-/// #rect(
-/// width: 100%,
-/// height: 20pt,
-/// fill: gradient.linear(..color.map.rainbow, space: color.hsl)
+/// #set text(font: "PT Sans")
+/// #set page(width: auto)
+/// #grid(
+/// columns: 9,
+/// gutter: 10pt,
+/// ..colors.map(name => {
+/// let c = eval(name)
+/// let cp = c.components()
+/// let x = cp.sum() / cp.len()
+/// set text(fill: white) if x < 50%
+/// set square(stroke: black) if c == white
+/// set align(center + horizon)
+/// square(size: 50pt, fill: c, name)
+/// })
/// )
/// ```
///
-/// ### Spectral
-/// The [`spectral`]($color.map.spectral) gradient is a red to yellow to blue
-/// gradient. Spectral does not take any parameters.
+/// # Predefined color maps
+/// Typst also includes a number of preset color maps that can be used for
+/// gradients. Most of these color maps are chosen to be color blind friendly.
///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.spectral))
+/// | Map | Details |
+/// |------------|:------------------------------------------------------------|
+/// | `turbo` | A perceptually uniform rainbow-like color map. Read [this blog post](https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html) for more details. |
+/// | `cividis` | A blue to gray to yellow color map. See [this blog post](https://bids.github.io/colormap/) for more details. |
+/// | `rainbow` | Cycles through the full color spectrum. This color map is best used by setting the interpolation color space to [HSL]($color.hsl). The rainbow gradient is **not suitable** for data visualization because it is not perceptually uniform, so the differences between values become unclear to your readers. It should only be used for decorative purposes. |
+/// | `spectral` | Red to yellow to blue color map. |
+/// | `viridis` | A purple to teal to yellow color map. |
+/// | `inferno` | A black to red to yellow color map. |
+/// | `magma` | A black to purple to yellow color map. |
+/// | `plasma` | A purple to pink to yellow color map. |
+/// | `rocket` | A black to red to white color map. |
+/// | `mako` | A black to teal to yellow color map. |
+/// | `vlag` | A light blue to white to red color map. |
+/// | `icefire` | A light teal to black to yellow color map. |
+/// | `flare` | A orange to purple color map that is perceptually uniform. |
+/// | `crest` | A blue to white to red color map. |
+///
+/// Some popular presets are not included because they are not available under a
+/// free licence. Others, like
+/// [Jet](https://jakevdp.github.io/blog/2014/10/16/how-bad-is-your-colormap/),
+/// are not included because they are not not color blind friendly. Feel free to
+/// use or create a package with other presets that are useful to you!
+///
+/// ```preview
+/// #set page(width: auto, height: auto)
+/// #set text(font: "PT Sans", size: 8pt)
+///
+/// #let maps = (
+/// "turbo", "cividis", "rainbow", "spectral",
+/// "viridis", "inferno", "magma", "plasma",
+/// "rocket", "mako", "vlag", "icefire",
+/// "flare", "crest",
+/// )
+///
+/// #stack(dir: ltr, spacing: 3pt, ..maps.map((name) => {
+/// let map = eval("color.map." + name)
+/// stack(
+/// dir: ttb,
+/// block(
+/// width: 15pt,
+/// height: 100pt,
+/// fill: gradient.linear(..map, angle: 90deg),
+/// ),
+/// block(
+/// width: 15pt,
+/// height: 32pt,
+/// move(dy: 8pt, rotate(90deg, name)),
+/// ),
+/// )
+/// }))
/// ```
-///
-/// ### Viridis
-/// The [`viridis`]($color.map.viridis) gradient is a purple to teal to yellow
-/// gradient. Viridis does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.viridis))
-/// ```
-///
-/// ### Inferno
-/// The [`inferno`]($color.map.inferno) gradient is a black to red to yellow
-/// gradient. Inferno does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.inferno))
-/// ```
-///
-/// ### Magma
-/// The [`magma`]($color.map.magma) gradient is a black to purple to yellow
-/// gradient. Magma does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.magma))
-/// ```
-///
-/// ### Plasma
-/// The [`plasma`]($color.map.plasma) gradient is a purple to pink to yellow
-/// gradient. Plasma does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.plasma))
-/// ```
-///
-/// ### Rocket
-/// The [`rocket`]($color.map.rocket) gradient is a black to red to white
-/// gradient. Rocket does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.rocket))
-/// ```
-///
-/// ### Mako
-/// The [`mako`]($color.map.mako) gradient is a black to teal to yellow gradient
-///. Mako does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.mako))
-/// ```
-///
-/// ### Vlag
-/// The [`vlag`]($color.map.vlag) gradient is a light blue to white to red
-/// gradient. Vlag does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.vlag))
-/// ```
-///
-/// ### Icefire
-/// The [`icefire`]($color.map.icefire) gradient is a light teal to black to
-/// yellow gradient. Icefire does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.icefire))
-/// ```
-///
-/// ### Flare
-/// The [`flare`]($color.map.flare) gradient is an orange to purple gradient that
-/// is perceptually uniform. Flare does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.flare))
-/// ```
-///
-/// ### Crest
-/// The [`crest`]($color.map.crest) gradient is a blue to white to red gradient .
-///Crest does not take any parameters.
-///
-/// ```example
-/// #rect(width: 100%, height: 20pt, fill: gradient.linear(..color.map.crest))
-/// ```
-///
-/// ### On other presets
-/// [Jet](https://jakevdp.github.io/blog/2014/10/16/how-bad-is-your-colormap/)
-/// is not color blind friendly and should not be used for data visualization,
-/// which is why it is not included in Typst. Other popular presets are not
-/// neccesarily under a free licence, which is why we could not include them.
-///
-/// Feel free to use or create a package with other presets useful to you!
#[ty(scope)]
#[derive(Debug, Copy, Clone)]
pub enum Color {
@@ -251,7 +215,6 @@ impl Color {
pub const MAP: fn() -> Module = || {
// Lazy to avoid re-allocating.
static MODULE: Lazy = Lazy::new(map);
-
MODULE.clone()
};
@@ -276,10 +239,11 @@ impl Color {
/// Create a grayscale color.
///
- /// A grayscale color is represented internally by a single `lightness` component.
+ /// A grayscale color is represented internally by a single `lightness`
+ /// component.
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
/// #for x in range(250, step: 50) {
@@ -294,7 +258,9 @@ impl Color {
/// The lightness component.
#[external]
lightness: Component,
- /// The color to convert to grayscale.
+ /// Alternatively: The color to convert to grayscale.
+ ///
+ /// If this is given, the `lightness` should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -315,14 +281,15 @@ impl Color {
/// - Creating grayscale images with uniform perceived lightness
/// - Creating smooth and uniform color transition and gradients
///
- /// A linear Oklab color is represented internally by an array of four components:
+ /// A linear Oklab color is represented internally by an array of four
+ /// components:
/// - lightness ([`ratio`]($ratio))
/// - a ([`float`]($float) in the range `[-0.4..0.4]`)
/// - b ([`float`]($float) in the range `[-0.4..0.4]`)
/// - alpha ([`ratio`]($ratio))
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
/// #square(
@@ -346,7 +313,9 @@ impl Color {
/// The key component.
#[external]
alpha: RatioComponent,
- /// The color to convert to Oklab.
+ /// Alternatively: The color to convert to Oklab.
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -375,19 +344,20 @@ impl Color {
/// perform color operations such as blending and interpolation. Although,
/// you should prefer to use the [`oklab` function]($color.oklab) for these.
///
- /// A linear RGB(A) color is represented internally by an array of four components:
+ /// A linear RGB(A) color is represented internally by an array of four
+ /// components:
/// - red ([`ratio`]($ratio))
/// - green ([`ratio`]($ratio))
/// - blue ([`ratio`]($ratio))
/// - alpha ([`ratio`]($ratio))
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
- /// #square(
- /// fill: color.linear-rgb(30%, 50%, 10%)
- /// )
+ /// #square(fill: color.linear-rgb(
+ /// 30%, 50%, 10%,
+ /// ))
/// ```
#[func(title = "Linear RGB")]
pub fn linear_rgb(
@@ -406,7 +376,9 @@ impl Color {
/// The alpha component.
#[external]
alpha: Component,
- /// The color to convert to linear RGB(A).
+ /// Alternatively: The color to convert to linear RGB(A).
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -450,20 +422,6 @@ impl Color {
/// The real arguments (the other arguments are just for the docs, this
/// function is a bit involved, so we parse the arguments manually).
args: Args,
- /// The color in hexadecimal notation.
- ///
- /// Accepts three, four, six or eight hexadecimal digits and optionally
- /// a leading hash.
- ///
- /// If this string is given, the individual components should not be given.
- ///
- /// ```example
- /// #text(16pt, rgb("#239dad"))[
- /// *Typst*
- /// ]
- /// ```
- #[external]
- hex: Str,
/// The red component.
#[external]
red: Component,
@@ -476,7 +434,23 @@ impl Color {
/// The alpha component.
#[external]
alpha: Component,
- /// The color to convert to RGB(A).
+ /// Alternatively: The color in hexadecimal notation.
+ ///
+ /// Accepts three, four, six or eight hexadecimal digits and optionally
+ /// a leading hash.
+ ///
+ /// If this is given, the individual components should not be given.
+ ///
+ /// ```example
+ /// #text(16pt, rgb("#239dad"))[
+ /// *Typst*
+ /// ]
+ /// ```
+ #[external]
+ hex: Str,
+ /// Alternatively: The color to convert to RGB(a).
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -511,8 +485,8 @@ impl Color {
/// - yellow ([`ratio`]($ratio))
/// - key ([`ratio`]($ratio))
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
/// #square(
@@ -536,7 +510,9 @@ impl Color {
/// The key component.
#[external]
key: RatioComponent,
- /// The color to convert to CMYK.
+ /// Alternatively: The color to convert to CMYK.
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -569,8 +545,8 @@ impl Color {
/// - lightness ([`ratio`]($ratio))
/// - alpha ([`ratio`]($ratio))
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
/// #square(
@@ -594,7 +570,9 @@ impl Color {
/// The alpha component.
#[external]
alpha: Component,
- /// The color to convert to HSL.
+ /// Alternatively: The color to convert to HSL.
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -627,8 +605,8 @@ impl Color {
/// - value ([`ratio`]($ratio))
/// - alpha ([`ratio`]($ratio))
///
- /// These components are also available using the [`components`]($color.components)
- /// method.
+ /// These components are also available using the
+ /// [`components`]($color.components) method.
///
/// ```example
/// #square(
@@ -652,7 +630,9 @@ impl Color {
/// The alpha component.
#[external]
alpha: Component,
- /// The color to convert to HSL.
+ /// Alternatively: The color to convert to HSL.
+ ///
+ /// If this is given, the individual components should not be given.
#[external]
color: Color,
) -> SourceResult {
@@ -673,7 +653,7 @@ impl Color {
})
}
- /// Converts this color into its components.
+ /// Extracts the components of this color.
///
/// The size and values of this array depends on the color space. You can
/// obtain the color space using [`space`]($color.space). Below is a table
diff --git a/crates/typst/src/geom/gradient.rs b/crates/typst/src/geom/gradient.rs
index b7944b10c..f2281930c 100644
--- a/crates/typst/src/geom/gradient.rs
+++ b/crates/typst/src/geom/gradient.rs
@@ -19,29 +19,41 @@ use crate::syntax::{Span, Spanned};
/// the [`gradient.radial` function]($gradient.radial), and conic gradients
/// through the [`gradient.conic` function]($gradient.conic).
///
+/// A gradient can be used for the following purposes:
+/// - As a fill to paint the interior of a shape:
+/// `{rect(fill: gradient.linear(..))}`
+/// - As a stroke to paint the outline of a shape:
+/// `{rect(stroke: 1pt + gradient.linear(..))}`
+/// - As the fill of text:
+/// `{set text(fill: gradient.linear(..))}`
+/// - As a color map you can [sample]($gradient.sample) from:
+/// `{gradient.linear(..).sample(0.5)}`
+///
+/// # Examples
/// ```example
+/// >>> #set square(size: 50pt)
/// #stack(
/// dir: ltr,
-/// square(size: 50pt, fill: gradient.linear(..color.map.rainbow)),
-/// square(size: 50pt, fill: gradient.radial(..color.map.rainbow)),
-/// square(size: 50pt, fill: gradient.conic(..color.map.rainbow)),
+/// spacing: 1fr,
+/// square(fill: gradient.linear(..color.map.rainbow)),
+/// square(fill: gradient.radial(..color.map.rainbow)),
+/// square(fill: gradient.conic(..color.map.rainbow)),
/// )
/// ```
///
-/// # Gradients on text
-/// Gradients are supported on text but only when setting the relativeness to
-/// either `{auto}` (the default value) or `{"parent"}`. It was decided that
-/// glyph-by-glyph gradients would not be supported out-of-the-box but can be
-/// emulated using [show rules]($styling/#show-rules).
-///
-/// You can use gradients on text as follows:
+/// Gradients are also supported on text, but only when setting the
+/// [relativeness]($gradient.relative) to either `{auto}` (the default value) or
+/// `{"parent"}`. To create word-by-word or glyph-by-glyph gradients, you can
+/// wrap the words or characters of your text in [boxes]($box) manually or
+/// through a [show rule]($styling/#show-rules).
///
/// ```example
-/// #set page(margin: 1pt)
+/// >>> #set page(width: auto, height: auto, margin: 12pt)
+/// >>> #set text(size: 12pt)
/// #set text(fill: gradient.linear(red, blue))
/// #let rainbow(content) = {
-/// set text(fill: gradient.linear(..color.map.rainbow))
-/// box(content)
+/// set text(fill: gradient.linear(..color.map.rainbow))
+/// box(content)
/// }
///
/// This is a gradient on text, but with a #rainbow[twist]!
@@ -56,24 +68,13 @@ use crate::syntax::{Span, Spanned};
/// the offsets when defining a gradient. In this case, Typst will space all
/// stops evenly.
///
-/// # Usage
-/// Gradients can be used for the following purposes:
-/// - As fills to paint the interior of a shape:
-/// `{rect(fill: gradient.linear(..))}`
-/// - As strokes to paint the outline of a shape:
-/// `{rect(stroke: 1pt + gradient.linear(..))}`
-/// - As color maps you can [sample]($gradient.sample) from:
-/// `{gradient.linear(..).sample(0.5)}`
-///
-/// Gradients are not currently supported on text.
-///
/// # Relativeness
/// The location of the `{0%}` and `{100%}` stops is dependant on the dimensions
/// of a container. This container can either be the shape they are painted on,
-/// or to the closest container ancestor. This is controlled by the `relative`
-/// argument of a gradient constructor. By default, gradients are relative to
-/// the shape they are painted on, unless the gradient is applied on text, in
-/// which case they are relative to the closest ancestor container.
+/// or to the closest surrounding container. This is controlled by the
+/// `relative` argument of a gradient constructor. By default, gradients are
+/// relative to the shape they are painted on, unless the gradient is applied on
+/// text, in which case they are relative to the closest ancestor container.
///
/// Typst determines the ancestor container as follows:
/// - For shapes that are placed at the root/top level of the document, the
@@ -98,16 +99,16 @@ use crate::syntax::{Span, Spanned};
/// choosing an interpolation space.
///
/// | Color space | Perceptually uniform? |
-/// | ------------------------------- |:----------------------|
-/// | [Oklab]($color.oklab) | *Yes* |
-/// | [sRGB]($color.rgb) | *No* |
+/// | ------------------------------- |-----------------------|
+/// | [Oklab]($color.oklab) | *Yes* |
+/// | [sRGB]($color.rgb) | *No* |
/// | [linear-RGB]($color.linear-rgb) | *Yes* |
-/// | [CMYK]($color.cmyk) | *No* |
-/// | [Grayscale]($color.luma) | *Yes* |
-/// | [HSL]($color.hsl) | *No* |
-/// | [HSV]($color.hsv) | *No* |
+/// | [CMYK]($color.cmyk) | *No* |
+/// | [Grayscale]($color.luma) | *Yes* |
+/// | [HSL]($color.hsl) | *No* |
+/// | [HSV]($color.hsv) | *No* |
///
-/// ```example
+/// ```preview
/// >>> #set text(fill: white, font: "IBM Plex Sans", 8pt)
/// >>> #set block(spacing: 0pt)
/// #let spaces = (
@@ -141,52 +142,20 @@ use crate::syntax::{Span, Spanned};
/// right-to-left, and 270° from bottom-to-top.
///
/// ```example
-/// #set block(spacing: 0pt)
+/// >>> #set square(size: 50pt)
/// #stack(
/// dir: ltr,
-/// square(size: 50pt, fill: gradient.linear(red, blue, angle: 0deg)),
-/// square(size: 50pt, fill: gradient.linear(red, blue, angle: 90deg)),
-/// square(size: 50pt, fill: gradient.linear(red, blue, angle: 180deg)),
-/// square(size: 50pt, fill: gradient.linear(red, blue, angle: 270deg)),
+/// spacing: 1fr,
+/// square(fill: gradient.linear(red, blue, angle: 0deg)),
+/// square(fill: gradient.linear(red, blue, angle: 90deg)),
+/// square(fill: gradient.linear(red, blue, angle: 180deg)),
+/// square(fill: gradient.linear(red, blue, angle: 270deg)),
/// )
/// ```
///
/// # Presets
-/// You can find the full list of presets in the documentation of [`color`]($color),
-/// below is an overview of them. Note that not all presets are suitable for data
-/// visualization and full details and relevant sources can be found in the
-/// documentation of [`color`]($color).
-///
-/// ```example
-/// #set text(fill: white, size: 18pt)
-/// #set text(top-edge: "bounds", bottom-edge: "bounds")
-/// #let presets = (
-/// ("turbo", color.map.turbo),
-/// ("cividis", color.map.cividis),
-/// ("rainbow", color.map.rainbow),
-/// ("spectral", color.map.spectral),
-/// ("viridis", color.map.viridis),
-/// ("inferno", color.map.inferno),
-/// ("magma", color.map.magma),
-/// ("plasma", color.map.plasma),
-/// ("rocket", color.map.rocket),
-/// ("mako", color.map.mako),
-/// ("vlag", color.map.vlag),
-/// ("icefire", color.map.icefire),
-/// ("flare", color.map.flare),
-/// ("crest", color.map.crest),
-/// )
-///
-/// #stack(
-/// spacing: 3pt,
-/// ..presets.map(((name, preset)) => block(
-/// width: 100%,
-/// height: 20pt,
-/// fill: gradient.linear(..preset),
-/// align(center + horizon, smallcaps(name)),
-/// ))
-/// )
-/// ```
+/// Typst predefines color maps that you can use with your gradients. See the
+/// [`color`]($color/#predefined-color-maps) documentation for more details.
#[ty(scope)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Gradient {
@@ -198,13 +167,16 @@ pub enum Gradient {
#[scope]
#[allow(clippy::too_many_arguments)]
impl Gradient {
- /// Creates a new linear gradient.
+ /// Creates a new linear gradient, in which colors transition along a
+ /// straight line.
///
/// ```example
/// #rect(
/// width: 100%,
/// height: 20pt,
- /// fill: gradient.linear(..color.map.viridis)
+ /// fill: gradient.linear(
+ /// ..color.map.viridis,
+ /// ),
/// )
/// ```
#[func(title = "Linear Gradient")]
@@ -225,9 +197,10 @@ impl Gradient {
space: ColorSpace,
/// The [relative placement](#relativeness) of the gradient.
///
- /// For an element placed at the root/top level of the document, the parent
- /// is the page itself. For other elements, the parent is the innermost block,
- /// box, column, grid, or stack that contains the element.
+ /// For an element placed at the root/top level of the document, the
+ /// parent is the page itself. For other elements, the parent is the
+ /// innermost block, box, column, grid, or stack that contains the
+ /// element.
#[named]
#[default(Smart::Auto)]
relative: Smart,
@@ -267,31 +240,34 @@ impl Gradient {
})))
}
- /// Creates a new radial gradient.
+ /// Creates a new radial gradient, in which colors radiate away from an
+ /// origin.
+ ///
+ /// The gradient is defined by two circles: the focal circle and the end
+ /// circle. The focal circle is a circle with center `focal-center` and
+ /// radius `focal-radius`, that defines the points at which the gradient
+ /// starts and has the color of the first stop. The end circle is a circle
+ /// with center `center` and radius `radius`, that defines the points at
+ /// which the gradient ends and has the color of the last stop. The gradient
+ /// is then interpolated between these two circles.
+ ///
+ /// Using these four values, also called the focal point for the starting
+ /// circle and the center and radius for the end circle, we can define a
+ /// gradient with more interesting properties than a basic radial gradient:
///
/// ```example
- /// #circle(
- /// radius: 20pt,
- /// fill: gradient.radial(..color.map.viridis)
- /// )
- /// ```
- ///
- /// _Focal Point_
- /// The gradient is defined by two circles: the focal circle and the end circle.
- /// The focal circle is a circle with center `focal-center` and radius `focal-radius`,
- /// that defines the points at which the gradient starts and has the color of the
- /// first stop. The end circle is a circle with center `center` and radius `radius`,
- /// that defines the points at which the gradient ends and has the color of the last
- /// stop. The gradient is then interpolated between these two circles.
- ///
- /// Using these four values, also called the focal point for the starting circle and
- /// the center and radius for the end circle, we can define a gradient with more
- /// interesting properties than a basic radial gradient:
- ///
- /// ```example
- /// #circle(
- /// radius: 20pt,
- /// fill: gradient.radial(..color.map.viridis, focal-center: (10%, 40%), focal-radius: 5%)
+ /// >>> #set circle(radius: 30pt)
+ /// #stack(
+ /// dir: ltr,
+ /// spacing: 1fr,
+ /// circle(fill: gradient.radial(
+ /// ..color.map.viridis,
+ /// )),
+ /// circle(fill: gradient.radial(
+ /// ..color.map.viridis,
+ /// focal-center: (10%, 40%),
+ /// focal-radius: 5%,
+ /// )),
/// )
/// ```
#[func]
@@ -316,14 +292,14 @@ impl Gradient {
#[named]
#[default(Smart::Auto)]
relative: Smart,
- /// The center of the last circle of the gradient.
+ /// The center of the end circle of the gradient.
///
/// A value of `{(50%, 50%)}` means that the end circle is
/// centered inside of its container.
#[named]
#[default(Axes::splat(Ratio::new(0.5)))]
center: Axes,
- /// The radius of the last circle of the gradient.
+ /// The radius of the end circle of the gradient.
///
/// By default, it is set to `{50%}`. The ending radius must be bigger
/// than the focal radius.
@@ -384,24 +360,24 @@ impl Gradient {
})))
}
- /// Creates a new conic gradient (i.e a gradient whose color changes
- /// radially around a center point).
+ /// Creates a new conic gradient, in which colors change radially around a
+ /// center point.
///
- /// ```example
- /// #circle(
- /// radius: 20pt,
- /// fill: gradient.conic(..color.map.viridis)
- /// )
- /// ```
- ///
- /// _Center Point_
/// You can control the center point of the gradient by using the `center`
/// argument. By default, the center point is the center of the shape.
///
/// ```example
- /// #circle(
- /// radius: 20pt,
- /// fill: gradient.conic(..color.map.viridis, center: (10%, 40%))
+ /// >>> #set circle(radius: 30pt)
+ /// #stack(
+ /// dir: ltr,
+ /// spacing: 1fr,
+ /// circle(fill: gradient.conic(
+ /// ..color.map.viridis,
+ /// )),
+ /// circle(fill: gradient.conic(
+ /// ..color.map.viridis,
+ /// center: (20%, 30%),
+ /// )),
/// )
/// ```
#[func]
@@ -453,117 +429,18 @@ impl Gradient {
})))
}
- /// Returns the stops of this gradient.
- #[func]
- pub fn stops(&self) -> Vec {
- match self {
- Self::Linear(linear) => linear
- .stops
- .iter()
- .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
- .collect(),
- Self::Radial(radial) => radial
- .stops
- .iter()
- .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
- .collect(),
- Self::Conic(conic) => conic
- .stops
- .iter()
- .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
- .collect(),
- }
- }
-
- /// Returns the mixing space of this gradient.
- #[func]
- pub fn space(&self) -> ColorSpace {
- match self {
- Self::Linear(linear) => linear.space,
- Self::Radial(radial) => radial.space,
- Self::Conic(conic) => conic.space,
- }
- }
-
- /// Returns the relative placement of this gradient.
- #[func]
- pub fn relative(&self) -> Smart {
- match self {
- Self::Linear(linear) => linear.relative,
- Self::Radial(radial) => radial.relative,
- Self::Conic(conic) => conic.relative,
- }
- }
-
- /// Returns the angle of this gradient.
- #[func]
- pub fn angle(&self) -> Option {
- match self {
- Self::Linear(linear) => Some(linear.angle),
- Self::Radial(_) => None,
- Self::Conic(conic) => Some(conic.angle),
- }
- }
-
- /// Returns the kind of this gradient.
- #[func]
- pub fn kind(&self) -> Func {
- match self {
- Self::Linear(_) => Self::linear_data().into(),
- Self::Radial(_) => Self::radial_data().into(),
- Self::Conic(_) => Self::conic_data().into(),
- }
- }
-
- /// Sample the gradient at a given position.
- ///
- /// The position is either a position along the gradient (a [ratio]($ratio)
- /// between `{0%}` and `{100%}`) or an [angle]($angle). Any value outside
- /// of this range will be clamped.
- ///
- /// _The angle will be used for conic gradients once they are available._
- #[func]
- pub fn sample(
- &self,
- /// The position at which to sample the gradient.
- t: RatioOrAngle,
- ) -> Color {
- let value: f64 = t.to_ratio().get();
-
- match self {
- Self::Linear(linear) => sample_stops(&linear.stops, linear.space, value),
- Self::Radial(radial) => sample_stops(&radial.stops, radial.space, value),
- Self::Conic(conic) => sample_stops(&conic.stops, conic.space, value),
- }
- }
-
- /// Samples the gradient at the given positions.
- ///
- /// The position is either a position along the gradient (a [ratio]($ratio)
- /// between `{0%}` and `{100%}`) or an [angle]($angle). Any value outside
- /// of this range will be clamped.
- ///
- /// _The angle will be used for conic gradients once they are available._
- #[func]
- pub fn samples(
- &self,
- /// The positions at which to sample the gradient.
- #[variadic]
- ts: Vec,
- ) -> Array {
- ts.into_iter().map(|t| self.sample(t).into_value()).collect()
- }
-
/// Creates a sharp version of this gradient.
///
- /// _Sharp gradients_ have discreet jumps between colors, instead of a
+ /// Sharp gradients have discreet jumps between colors, instead of a
/// smooth transition. They are particularly useful for creating color
/// lists for a preset gradient.
///
/// ```example
+ /// #set rect(width: 100%, height: 20pt)
/// #let grad = gradient.linear(..color.map.rainbow)
- /// #rect(width: 100%, height: 20pt, fill: grad)
- /// #rect(width: 100%, height: 20pt, fill: grad.sharp(5))
+ /// #rect(fill: grad)
+ /// #rect(fill: grad.sharp(5))
+ /// #rect(fill: grad.sharp(5, smoothness: 20%))
/// ```
#[func]
pub fn sharp(
@@ -651,6 +528,15 @@ impl Gradient {
/// Repeats this gradient a given number of times, optionally mirroring it
/// at each repetition.
+ ///
+ /// ```example
+ /// #circle(
+ /// radius: 40pt,
+ /// fill: gradient
+ /// .radial(aqua, white)
+ /// .repeat(4),
+ /// )
+ /// ```
#[func]
pub fn repeat(
&self,
@@ -721,6 +607,100 @@ impl Gradient {
})),
})
}
+
+ /// Returns the kind of this gradient.
+ #[func]
+ pub fn kind(&self) -> Func {
+ match self {
+ Self::Linear(_) => Self::linear_data().into(),
+ Self::Radial(_) => Self::radial_data().into(),
+ Self::Conic(_) => Self::conic_data().into(),
+ }
+ }
+
+ /// Returns the stops of this gradient.
+ #[func]
+ pub fn stops(&self) -> Vec {
+ match self {
+ Self::Linear(linear) => linear
+ .stops
+ .iter()
+ .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
+ .collect(),
+ Self::Radial(radial) => radial
+ .stops
+ .iter()
+ .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
+ .collect(),
+ Self::Conic(conic) => conic
+ .stops
+ .iter()
+ .map(|(color, offset)| Stop { color: *color, offset: Some(*offset) })
+ .collect(),
+ }
+ }
+
+ /// Returns the mixing space of this gradient.
+ #[func]
+ pub fn space(&self) -> ColorSpace {
+ match self {
+ Self::Linear(linear) => linear.space,
+ Self::Radial(radial) => radial.space,
+ Self::Conic(conic) => conic.space,
+ }
+ }
+
+ /// Returns the relative placement of this gradient.
+ #[func]
+ pub fn relative(&self) -> Smart {
+ match self {
+ Self::Linear(linear) => linear.relative,
+ Self::Radial(radial) => radial.relative,
+ Self::Conic(conic) => conic.relative,
+ }
+ }
+
+ /// Returns the angle of this gradient.
+ #[func]
+ pub fn angle(&self) -> Option {
+ match self {
+ Self::Linear(linear) => Some(linear.angle),
+ Self::Radial(_) => None,
+ Self::Conic(conic) => Some(conic.angle),
+ }
+ }
+
+ /// Sample the gradient at a given position.
+ ///
+ /// The position is either a position along the gradient (a [ratio]($ratio)
+ /// between `{0%}` and `{100%}`) or an [angle]($angle). Any value outside
+ /// of this range will be clamped.
+ #[func]
+ pub fn sample(
+ &self,
+ /// The position at which to sample the gradient.
+ t: RatioOrAngle,
+ ) -> Color {
+ let value: f64 = t.to_ratio().get();
+
+ match self {
+ Self::Linear(linear) => sample_stops(&linear.stops, linear.space, value),
+ Self::Radial(radial) => sample_stops(&radial.stops, radial.space, value),
+ Self::Conic(conic) => sample_stops(&conic.stops, conic.space, value),
+ }
+ }
+
+ /// Samples the gradient at multiple positions at once and returns the
+ /// results as an array.
+ #[func]
+ pub fn samples(
+ &self,
+ /// The positions at which to sample the gradient.
+ #[variadic]
+ ts: Vec,
+ ) -> Array {
+ ts.into_iter().map(|t| self.sample(t).into_value()).collect()
+ }
}
impl Gradient {