diff --git a/README.md b/README.md index a06ea30..8f80156 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ **Python bindings for [Silicon](https://github.com/Aloxaf/silicon)'s renderer — create beautiful images of your source code, powered by Rust.** +

+ Silicate example - Python code rendered with Dracula theme +

+ Unlike wrapper approaches that shell out to a CLI, Silicate uses [PyO3](https://pyo3.rs) to call Silicon's Rust library directly, giving you native performance with a clean Python API. ## Installation @@ -44,6 +48,25 @@ print(silicate.list_themes()) print(silicate.list_languages()) ``` +## Theme gallery + +Silicate ships with 24+ built-in themes. Here are a few: + + + + + + + + + + + + + + +
Dracula
Nord
Monokai Extended
GitHub
Solarized Dark
Your code here
+ ### Options All parameters after `code` (and `output` for `to_file`) are keyword-only: @@ -62,6 +85,9 @@ All parameters after `code` (and `output` for `to_file`) are keyword-only: | `shadow_blur_radius` | `50.0` | Shadow blur radius | | `pad_horiz` | `80` | Horizontal padding (px) | | `pad_vert` | `100` | Vertical padding (px) | +| `shadow_offset_x` | `0` | Shadow offset in X axis | +| `shadow_offset_y` | `0` | Shadow offset in Y axis | +| `code_pad_right` | `25` | Right padding inside code window (px) | | `highlight_lines` | `None` | 1-based line numbers to highlight | | `tab_width` | `4` | Spaces per tab | | `line_offset` | `1` | Starting line number | @@ -85,3 +111,7 @@ uv run python -c "import silicate; print(silicate.list_themes())" ## License MIT + +--- + +Built by [All Tuner Labs](https://alltuner.com) diff --git a/docs/api.md b/docs/api.md index 4b8b5d2..df67413 100644 --- a/docs/api.md +++ b/docs/api.md @@ -18,6 +18,9 @@ def generate( shadow_blur_radius: float = 50.0, pad_horiz: int = 80, pad_vert: int = 100, + shadow_offset_x: int = 0, + shadow_offset_y: int = 0, + code_pad_right: int = 25, highlight_lines: list[int] | None = None, tab_width: int = 4, line_offset: int = 1, @@ -44,6 +47,9 @@ Generate a code image and return raw PNG bytes. | `shadow_blur_radius` | `float` | `50.0` | Gaussian blur radius for shadow | | `pad_horiz` | `int` | `80` | Horizontal padding in pixels | | `pad_vert` | `int` | `100` | Vertical padding in pixels | +| `shadow_offset_x` | `int` | `0` | Shadow offset in X axis | +| `shadow_offset_y` | `int` | `0` | Shadow offset in Y axis | +| `code_pad_right` | `int` | `25` | Padding to the right of the code in pixels | | `highlight_lines` | `list[int] \| None` | `None` | 1-based line numbers to highlight | | `tab_width` | `int` | `4` | Spaces per tab character | | `line_offset` | `int` | `1` | Starting line number | diff --git a/docs/assets/example-github.png b/docs/assets/example-github.png new file mode 100644 index 0000000..ff28ecc Binary files /dev/null and b/docs/assets/example-github.png differ diff --git a/docs/assets/example-monokai.png b/docs/assets/example-monokai.png new file mode 100644 index 0000000..3e72908 Binary files /dev/null and b/docs/assets/example-monokai.png differ diff --git a/docs/assets/example-nord.png b/docs/assets/example-nord.png new file mode 100644 index 0000000..bddb5c8 Binary files /dev/null and b/docs/assets/example-nord.png differ diff --git a/docs/assets/example-solarized.png b/docs/assets/example-solarized.png new file mode 100644 index 0000000..01437f5 Binary files /dev/null and b/docs/assets/example-solarized.png differ diff --git a/docs/assets/example-usage.png b/docs/assets/example-usage.png new file mode 100644 index 0000000..3a44c02 Binary files /dev/null and b/docs/assets/example-usage.png differ diff --git a/docs/assets/hero-example.png b/docs/assets/hero-example.png new file mode 100644 index 0000000..550cd63 Binary files /dev/null and b/docs/assets/hero-example.png differ diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 0000000..599cfa3 Binary files /dev/null and b/docs/assets/logo.png differ diff --git a/docs/index.md b/docs/index.md index 23c59cb..70394a6 100644 --- a/docs/index.md +++ b/docs/index.md @@ -2,6 +2,10 @@ **Python bindings for [Silicon](https://github.com/Aloxaf/silicon)'s renderer — create beautiful images of your source code, powered by Rust.** +

+ Silicate example - Python code rendered with Dracula theme +

+ Unlike wrapper approaches that shell out to a CLI, Silicate uses [PyO3](https://pyo3.rs) to call Silicon's Rust library directly, giving you native performance with a clean Python API. ## Features @@ -35,6 +39,32 @@ silicate.to_file( ) ``` +## Theme gallery + +Silicate ships with 24+ built-in themes. Here are a few examples across different languages: + +
+ +### Dracula — Python +![Dracula theme example](assets/hero-example.png) + +### Nord — Rust +![Nord theme example](assets/example-nord.png) + +### Monokai Extended — TypeScript +![Monokai theme example](assets/example-monokai.png) + +### GitHub — SQL +![GitHub theme example](assets/example-github.png) + +### Solarized Dark — Go +![Solarized theme example](assets/example-solarized.png) + +### Silicate itself — Python +![Usage example](assets/example-usage.png) + +
+ ## How it works ```mermaid @@ -47,3 +77,7 @@ graph LR ``` Silicate embeds the Silicon Rust library via [PyO3](https://pyo3.rs), compiled with [maturin](https://github.com/PyO3/maturin). The syntax highlighting engine, font rendering, and image composition all run in native Rust — Python only handles the API surface. + +--- + +Built by [All Tuner Labs](https://alltuner.com) diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css index 187a2ce..8130df3 100644 --- a/docs/stylesheets/extra.css +++ b/docs/stylesheets/extra.css @@ -1,33 +1,85 @@ -/* Silicate brand colors — indigo/violet code-editor theme */ +/* All Tuner Labs brand colors and MkDocs Material theme overrides. */ +/* Provides wine/burgundy color scheme with light/dark mode support. */ +/* All Tuner Labs Brand Colors */ :root { - /* Primary palette */ - --silicon-indigo: #6366f1; - --silicon-violet: #8b5cf6; - --silicon-slate: #1e293b; - --silicon-light: #f1f5f9; + --wine: #5B2333; + --white-smoke: #F7F4F3; + --taupe-gray: #928E8D; + --raisin-black: #2C2826; +} + +/* Light mode custom colors */ +[data-md-color-scheme="default"] { + --md-primary-fg-color: var(--wine); + --md-primary-fg-color--light: #7a2f45; + --md-primary-fg-color--dark: #4a1b28; + --md-primary-bg-color: var(--white-smoke); + + --md-accent-fg-color: var(--wine); + --md-accent-fg-color--transparent: rgba(91, 35, 51, 0.1); - /* Material overrides — light mode */ - --md-primary-fg-color: var(--silicon-indigo); - --md-primary-fg-color--light: #818cf8; - --md-primary-fg-color--dark: #4f46e5; - --md-accent-fg-color: var(--silicon-violet); + --md-default-bg-color: var(--white-smoke); + --md-default-fg-color: var(--raisin-black); + --md-default-fg-color--light: var(--taupe-gray); + --md-default-fg-color--lighter: #b5b2b1; + --md-default-fg-color--lightest: #d4d3d2; + + --md-code-bg-color: #ffffff; + --md-code-fg-color: var(--raisin-black); } +/* Dark mode custom colors */ [data-md-color-scheme="slate"] { - /* Material overrides — dark mode */ - --md-primary-fg-color: #818cf8; - --md-primary-fg-color--light: #a5b4fc; - --md-primary-fg-color--dark: #6366f1; - --md-accent-fg-color: #a78bfa; + --md-primary-fg-color: var(--wine); + --md-primary-fg-color--light: #7a2f45; + --md-primary-fg-color--dark: #4a1b28; + + --md-accent-fg-color: #8a3d51; + --md-accent-fg-color--transparent: rgba(138, 61, 81, 0.1); + + --md-default-bg-color: var(--raisin-black); + --md-default-fg-color: var(--white-smoke); + --md-default-fg-color--light: var(--taupe-gray); + + --md-code-bg-color: #1a1816; + --md-code-fg-color: var(--white-smoke); +} + +/* Custom link colors for light mode */ +[data-md-color-scheme="default"] .md-content a { + color: var(--wine); +} + +[data-md-color-scheme="default"] .md-content a:hover { + color: #7a2f45; +} + +/* Custom link colors for dark mode - use white-smoke for readability */ +[data-md-color-scheme="slate"] .md-content a { + color: var(--white-smoke); +} + +[data-md-color-scheme="slate"] .md-content a:hover { + color: var(--taupe-gray); +} + +/* Sidebar navigation links in dark mode */ +[data-md-color-scheme="slate"] .md-nav__link { + color: var(--white-smoke); +} + +[data-md-color-scheme="slate"] .md-nav__link:hover { + color: var(--taupe-gray); } -/* Code block styling */ -.md-typeset code { - border-radius: 4px; +[data-md-color-scheme="slate"] .md-nav__link--active { + color: var(--white-smoke); } -/* Navigation tab highlight */ -.md-tabs__link--active { - border-bottom: 2px solid var(--md-accent-fg-color); +/* Custom header logo sizing */ +.md-header__button.md-logo img, +.md-header__button.md-logo svg { + height: 2rem; + width: auto; } diff --git a/docs/usage.md b/docs/usage.md index be8ef30..2376626 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -48,6 +48,19 @@ for theme in silicate.list_themes(): Available themes include: `1337`, `Coldark-Cold`, `Coldark-Dark`, `DarkNeon`, `Dracula`, `GitHub`, `Monokai Extended`, `Nord`, `OneHalfDark`, `OneHalfLight`, `Solarized (dark)`, `Solarized (light)`, `Sublime Snazzy`, `TwoDark`, `Visual Studio Dark+`, `gruvbox-dark`, `gruvbox-light`, `zenburn`, and more. +Here's the same code rendered with different themes: + + + + + + + + + + +
Dracula
Nord
Monokai Extended
GitHub
+ ### Languages ```python @@ -162,3 +175,7 @@ silicate.to_file( pad_vert=80, ) ``` + +The code above produces: + +![Full example output](assets/example-nord.png) diff --git a/mkdocs.yml b/mkdocs.yml index 0277b85..b20bfc4 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,7 +1,7 @@ site_name: Silicate -site_description: Python bindings for Silicon's renderer -site_url: https://silicate.alltuner.com -site_author: David Poblador i Garcia +site_url: https://silicate.alltuner.com/ +site_description: Python bindings for Silicon's renderer — create beautiful images of your source code, powered by Rust +site_author: All Tuner Labs, S.L. repo_url: https://github.com/alltuner/silicate repo_name: alltuner/silicate @@ -9,6 +9,8 @@ edit_uri: edit/main/docs/ theme: name: material + logo: assets/logo.png + favicon: assets/logo.png palette: # Light mode - media: "(prefers-color-scheme: light)" @@ -29,8 +31,10 @@ theme: features: - navigation.instant - navigation.tracking + - navigation.tabs + - navigation.sections + - navigation.expand - navigation.top - - toc.integrate - search.suggest - search.highlight - content.code.copy diff --git a/pyproject.toml b/pyproject.toml index be4c422..97f58a8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,16 +12,42 @@ authors = [ { name = "David Poblador i Garcia", email = "david@poblador.com" } ] requires-python = ">=3.9" -keywords = ["code", "image", "screenshot", "syntax-highlighting", "silicon", "rust"] +keywords = [ + "code", + "image", + "screenshot", + "syntax-highlighting", + "silicon", + "rust", + "code-to-image", + "carbon", + "code-screenshot", + "png", + "developer-tools", + "pyo3", + "rendering", +] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", + "Intended Audience :: Information Technology", "License :: OSI Approved :: MIT License", "Programming Language :: Rust", "Programming Language :: Python :: Implementation :: CPython", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Multimedia :: Graphics", + "Topic :: Multimedia :: Graphics :: Graphics Conversion", "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Software Development :: Documentation", + "Topic :: Text Processing :: Markup", + "Topic :: Utilities", + "Typing :: Typed", ] [project.urls] diff --git a/python/silicate/__init__.pyi b/python/silicate/__init__.pyi index baf83ef..5d95afe 100644 --- a/python/silicate/__init__.pyi +++ b/python/silicate/__init__.pyi @@ -13,6 +13,9 @@ def generate( shadow_blur_radius: float = 50.0, pad_horiz: int = 80, pad_vert: int = 100, + shadow_offset_x: int = 0, + shadow_offset_y: int = 0, + code_pad_right: int = 25, highlight_lines: list[int] | None = None, tab_width: int = 4, line_offset: int = 1, @@ -34,6 +37,9 @@ def generate( shadow_blur_radius: Gaussian blur radius for the shadow. pad_horiz: Horizontal padding in pixels. pad_vert: Vertical padding in pixels. + shadow_offset_x: Shadow offset in X axis. + shadow_offset_y: Shadow offset in Y axis. + code_pad_right: Padding to the right of the code in pixels. highlight_lines: List of 1-based line numbers to highlight. tab_width: Number of spaces per tab character. line_offset: Starting line number. @@ -57,6 +63,9 @@ def to_file( shadow_blur_radius: float = 50.0, pad_horiz: int = 80, pad_vert: int = 100, + shadow_offset_x: int = 0, + shadow_offset_y: int = 0, + code_pad_right: int = 25, highlight_lines: list[int] | None = None, tab_width: int = 4, line_offset: int = 1, @@ -81,6 +90,9 @@ def to_file( shadow_blur_radius: Gaussian blur radius for the shadow. pad_horiz: Horizontal padding in pixels. pad_vert: Vertical padding in pixels. + shadow_offset_x: Shadow offset in X axis. + shadow_offset_y: Shadow offset in Y axis. + code_pad_right: Padding to the right of the code in pixels. highlight_lines: List of 1-based line numbers to highlight. tab_width: Number of spaces per tab character. line_offset: Starting line number. diff --git a/src/lib.rs b/src/lib.rs index 9f9d64b..a3d3685 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,9 @@ fn render( shadow_blur_radius: f32, pad_horiz: u32, pad_vert: u32, + shadow_offset_x: i32, + shadow_offset_y: i32, + code_pad_right: u32, highlight_lines: Option>, tab_width: u8, line_offset: u32, @@ -72,7 +75,9 @@ fn render( .shadow_color(shadow) .blur_radius(shadow_blur_radius) .pad_horiz(pad_horiz) - .pad_vert(pad_vert); + .pad_vert(pad_vert) + .offset_x(shadow_offset_x) + .offset_y(shadow_offset_y); let font_spec = font.unwrap_or_else(|| vec![("Hack".to_string(), 26.0)]); let font_refs: Vec<(&str, f32)> = font_spec.iter().map(|(n, s)| (n.as_str(), *s)).collect(); @@ -88,6 +93,7 @@ fn render( .shadow_adder(shadow_adder) .highlight_lines(highlight_lines.unwrap_or_default()) .tab_width(tab_width) + .code_pad_right(code_pad_right) .build() .map_err(|e| PyValueError::new_err(format!("Font error: {}", e)))?; @@ -126,6 +132,9 @@ fn encode_png(image: &image::RgbaImage) -> PyResult> { shadow_blur_radius = 50.0, pad_horiz = 80, pad_vert = 100, + shadow_offset_x = 0, + shadow_offset_y = 0, + code_pad_right = 25, highlight_lines = None, tab_width = 4, line_offset = 1, @@ -146,6 +155,9 @@ fn generate<'py>( shadow_blur_radius: f32, pad_horiz: u32, pad_vert: u32, + shadow_offset_x: i32, + shadow_offset_y: i32, + code_pad_right: u32, highlight_lines: Option>, tab_width: u8, line_offset: u32, @@ -165,6 +177,9 @@ fn generate<'py>( shadow_blur_radius, pad_horiz, pad_vert, + shadow_offset_x, + shadow_offset_y, + code_pad_right, highlight_lines, tab_width, line_offset, @@ -194,6 +209,9 @@ fn generate<'py>( shadow_blur_radius = 50.0, pad_horiz = 80, pad_vert = 100, + shadow_offset_x = 0, + shadow_offset_y = 0, + code_pad_right = 25, highlight_lines = None, tab_width = 4, line_offset = 1, @@ -214,6 +232,9 @@ fn to_file( shadow_blur_radius: f32, pad_horiz: u32, pad_vert: u32, + shadow_offset_x: i32, + shadow_offset_y: i32, + code_pad_right: u32, highlight_lines: Option>, tab_width: u8, line_offset: u32, @@ -233,6 +254,9 @@ fn to_file( shadow_blur_radius, pad_horiz, pad_vert, + shadow_offset_x, + shadow_offset_y, + code_pad_right, highlight_lines, tab_width, line_offset, diff --git a/uv.lock b/uv.lock index 8974082..a41b119 100644 --- a/uv.lock +++ b/uv.lock @@ -671,7 +671,7 @@ wheels = [ [[package]] name = "silicate" -version = "0.1.0" +version = "0.1.2" source = { editable = "." } [package.dev-dependencies]