## Using Roq (copy this section to your project's CLAUDE.md / AGENTS.md) Roq is a static site generator built on Quarkus. It uses the Qute template engine with FrontMatter headers (YAML between `---` delimiters). ### Quick Start 1. Install via JBang: `curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force roq@quarkiverse/quarkus-roq` 2. Create a site: `roq create my-site` (adds the default theme with example content) 3. Start dev mode: `cd my-site && roq start` (live-reload on http://localhost:8080, most changes are picked up automatically, use `-p 9090` for a custom port, press `s` to force a soft restart if needed) 4. Build static site: `roq generate` (output in `target/roq/`), preview with `roq serve` 5. Add a plugin or theme: `roq add plugin:tagging`, `roq add theme:default` 6. Update to latest versions: `roq update` For a minimal HTML structure without the default theme: `roq create my-site -x theme:base`. Use `--no-code` to skip example content, `--gradle` for Gradle. Available commands: `roq create`, `roq start`, `roq generate`, `roq serve`, `roq add`, `roq update`, `roq blog`. There is NO `roq dev` command, use `roq start` for dev mode. ### AI Agent Integration (Quarkus Agent MCP) AI coding agents (Claude Code, VS Code Copilot, Cursor, etc.) can manage Roq dev servers using [Quarkus Agent MCP](https://github.com/quarkusio/quarkus-agent-mcp). It handles lifecycle (start, stop, soft restart via `s`), log capture, and proxies to Dev MCP tools in the running app. **Install via JBang:** ``` jbang app install --fresh --force quarkus-agent-mcp@quarkusio ``` **Configure in Claude Code:** ``` claude mcp add quarkus-agent -- jbang quarkus-agent-mcp@quarkusio ``` **Configure in VS Code / Cursor (`.vscode/mcp.json`):** ```json { "servers": { "quarkus-agent": { "type": "stdio", "command": "jbang", "args": ["quarkus-agent-mcp@quarkusio"] } } } ``` Once configured, the agent uses `quarkus_start` to launch the Roq dev server, `quarkus_restart` for soft restart, `quarkus_logs` to read output, and `quarkus_searchTools` / `quarkus_callTool` to interact with the running app. ### Directory Structure ``` my-site/ ├── content/ # Pages, collections (posts/, etc.), index.html (required) ├── templates/ │ ├── layouts/ # Page layouts (page.html, post.html) │ └── partials/ # Reusable template fragments ├── data/ # Structured data files (YAML/JSON), accessible via {cdi:filename.property} ├── public/ # Static assets served as-is (images, PDFs) ├── web/ # JS/CSS sources (bundled by Quarkus Web Bundler) └── config/ └── application.properties # Site config with site.* prefix ``` ## Installing Roq Skill Files for AI Coding Assistants Roq extensions ship detailed reference docs as skill files inside their deployment JARs at `META-INF/quarkus-skill.md`. Follow these steps to install them in your project. ### 1. Find your Roq extensions and version ``` mvn dependency:list -DincludeGroupIds=io.quarkiverse.roq -DoutputAbsoluteArtifactFilename=true ``` ### 2. Extract the relevant skills Extract from the matching JAR in your local Maven repository: ``` unzip -p ~/.m2/repository/io/quarkiverse/roq/ARTIFACT_ID/VERSION/ARTIFACT_ID-VERSION.jar META-INF/quarkus-skill.md > .claude/skills/SHORT_NAME.md ``` Install to the appropriate skills directory (`.claude/skills/` for Claude Code), or append to your CLAUDE.md/AGENTS.md. Install a skill for each `*-deployment` JAR listed in the dependency output. ### 3. Keep skills in sync After running `roq update`, re-extract the skill files to match the new version. Compare the Roq version in your dependencies with the version of the installed skill to detect staleness. **Migrating to Roq:** - [Migrating to Roq](https://iamroq.dev/docs/migrating/): phased workflow, syntax mappings, configuration reference, and LLM prompts for migrating a Jekyll/Hugo site to Roq **Skill files (latest version for reference):** - [quarkus-roq-frontmatter-deployment](https://raw.githubusercontent.com/quarkiverse/quarkus-roq/main/roq-frontmatter/deployment/src/main/resources/META-INF/quarkus-skill.md): base reference (FrontMatter pages, layouts, collections, pagination, template variables, Qute syntax, built-in tags, data files, template extensions, configuration, common pitfalls) - [quarkus-roq-deployment](https://raw.githubusercontent.com/quarkiverse/quarkus-roq/main/roq/deployment/src/main/resources/META-INF/quarkus-skill.md): full Roq extras (directory structure, themes, RSS, LLMs.txt, static generation, testing, CLI commands) - [quarkus-roq-data-deployment](https://raw.githubusercontent.com/quarkiverse/quarkus-roq/main/roq-data/deployment/src/main/resources/META-INF/quarkus-skill.md): data file mapping with @DataMapping and CDI --- The following is the content of this blog site: # Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. > An Open Source static site generator (SSG) that makes it fun and easy to build websites and blogs. It's built with Java and Quarkus under the hood. ## Marketplace ### [Tailwind CSS](/web/tailwind-css/) Add Tailwind CSS support to your Roq project. Write utility-first CSS classes directly in your templates, with automatic purging of unused styles for optimized production builds. Configuration Tailwind configuration is automatic (detecting site content and templates) via the Quarkus Web Bundler. Getting started After installing, create a CSS file that imports Tailwind: @import "tailwindcss"; @plugin "@tailwindcss/typography"; The @tailwindcss/typography plugin provides the prose class for beautifully styled content rendering (used by Roq for markdown and AsciiDoc output). Then use Tailwind classes in your templates: <div class="flex items-center gap-4 p-6 bg-white dark:bg-gray-800 rounded-lg shadow"> <h2 class="text-xl font-bold text-gray-900 dark:text-white">Hello Tailwind</h2> </div> ### [Svelte](/web/svelte/) Add Svelte component support to your Roq project. Build interactive UI components with Svelte's reactive framework and embed them in your static pages. Getting started Create .svelte files in your web/ directory: <!-- web/components/Counter.svelte --> <script> let count = 0; </script> <button on:click={() => count++}> Clicks: {count} </button> Then mount the component in your templates using Web Bundler's script injection. ### [Sass](/web/sass/) Add Sass/SCSS support to your Roq project. Use variables, nesting, mixins, and all Sass features to write maintainable stylesheets. Sass is the default Web Bundler preprocessor. It is included automatically when using the Web Bundler without Tailwind. Getting started Create .scss files in your web/ directory: // web/style.scss $primary: #3b82f6; $radius: 0.5rem; .card { border-radius: $radius; background: white; &-title { color: $primary; font-weight: 600; } } ### [mvnpm](/web/mvnpm/) Add mvnpm support to your Roq project. Import npm packages directly through Maven coordinates, with no Node.js or npm installation required. mvnpm bridges Maven and npm, converting npm packages into Maven artifacts that the Web Bundler can resolve and bundle. Getting started Add npm packages as Maven dependencies in your pom.xml: <dependency> <groupId>org.mvnpm</groupId> <artifactId>htmx.org</artifactId> <version>2.0.4</version> <scope>provided</scope> </dependency> Then import them in your JavaScript: import 'htmx.org'; Browse available packages at mvnpm.org. ### [Tagging](/plugin/tagging/) Generate a dynamic (derived) collection based on a given collection's tags. For example, if multiple posts have tags: guide, a /posts/tag/guide page is generated listing all matching posts. This works for any collection. If you are using a theme that supports it (includes a tagging layout), you should now have tags pages available for all the tags in your posts! You can use theme override to customize the theme tagging layout. To enable tagging without a theme, create a layout template and add tagging: [collection id] in FM. As a result you will have access to a new derived collection named tagCollection: <!-- templates/layouts/tag.html --> --- layout: main tagging: posts --- {#for post in site.collections.get(page.data.tagCollection)} <div>{post.title}</div> {/for} This also supports pagination. Since tagging already specifies the target collection, pagination can be enabled with paginate: true in FM: --- layout: main tagging: posts paginate: true --- {#for post in site.collections.get(page.data.tagCollection).paginated(page.paginator)} <div>{post.title}</div> {/for} Template Extensions Usage Description collection.allTags Returns a list of all tags from the collection, each tag slugified collection.tagsCount Returns a list of all tags slugified (name) with their count (count) in the collection ### [Sitemap](/plugin/sitemap/) Easily create a sitemap.xml for your site. Create a new sitemap file: <!-- content/sitemap.xml --> {#include fm/sitemap.xml} To remove pages from the sitemap, use sitemap: false in the FM data. Browse http://localhost:8080/sitemap.xml to verify. ### [Series](/plugin/series/) Join multiple posts into a series with automatic series headers. Edit the layout for your posts, for example when using the roq-default theme: <!-- templates/layouts/post-series.html --> --- theme-layout: post --- {#include partials/roq-series /} {#insert /} Then use this layout and add the series attribute in the Front Matter of the posts you want to join: --- layout: post-series title: Assemble your blog post in a series description: Automatically series header for your posts tags: plugin, frontmatter, guide, series author: John Doe series: My series Title --- Use the exact same series title for all documents in the series. ### [QR Code](/plugin/qr-code/) Add QR codes to your website. Create a template and add the #qrcode tag to it, then style and size it as you want. By default, the plugin produces HTML output compatible with both HTML and Markdown templates. To use the plugin with AsciiDoc, set the asciidoc attribute to true. {#qrcode value="https://luigis.com/menu/" alt="Luigi's Menu" foreground="#000066" background="#FFFFFF" width=300 height=300 /} {#qrcode value="https://luigis.com/menu/" alt="Luigi's Menu" foreground="#000066" background="#FFFFFF" width=300 height=300 asciidoc=true /} ### [Markdown](/plugin/markdown/) Process .md and .markdown files using CommonMark Java. Markdown plugin is already included in Quarkus Roq extension. No separate installation needed unless you removed it. Every file with .md or .markdown extension will be processed. ### [Lunr Search](/plugin/lunr-search/) Enable search for your site without the need for external, server-side, search services. Setup Add the search index JSON: <!-- content/search-index.json --> {#include fm/search-index.json} Inject the search script in the <head> of your layout. For example with the default theme: <!-- templates/layouts/default.html --> --- theme-layout: default --- {#insert /} {#head} {#search-script /} {/} Inject the search overlay in the <body> and search button in the navigation: <!-- templates/layouts/main.html --> --- theme-layout: main --- {#search-overlay /} {#insert /} {#menu} {#search-button /} {#include partials/roq-default/sidebar-menu menu=cdi:menu.items /} {/} Controlling indexing You can prevent content from being indexed: --- title: I don't want to be indexed search: false --- You can also boost specific pages or layouts in the results: --- title: I want to be first in the result search-boost: 30 --- ### [Diagram](/plugin/diagram/) Diagram-as-code support by leveraging Kroki.io. It delegates image rendering to Kroki either by using a provided server or by popping a dev service. Please take a look at the full Kroki reference documentation. Use it in your content: {#diagram asciidoc=true language="pikchr" alt="Impossible trident" width=500 height=500 diagramOutputFormat="svg"} scale = 1.0 eh = 0.5cm ew = 0.2cm ... {/} You can either use a deployed server or let the dev services provide one for you, but in this case you won't have all languages available. ### [AsciiDoc](/plugin/asciidoc/) Fast Java-based AsciiDoc processor (based on Yupiik asciidoc-java). Provides fast startup but does not support all AsciiDoc options yet. For the full feature set, see AsciiDoc JRuby. Add the .adoc or .asciidoc file extension to pages and they will be processed. Use Qute in AsciiDoc files Qute parsing is disabled by default on AsciiDoc files, to enable it: quarkus.asciidoc.qute=true You can also use the :qute: AsciiDoc header attribute to enable Qute parsing (or not :qute: false) per page. AsciiDoc includes You may use includes from anywhere in the site directory. Make sure the included file is ignored by Roq by prefixing the file or directory with _. include::_includes/attributes.adoc[] Headers AsciiDoc headers are parsed by Roq and used as page data: = Title is used as page title author is available through page.data.author and page.data.author-email revision is available through page.data.revision.number, page.data.revision.date and page.data.revision.remark attribute :description: is used as page description attributes starting with page- will be used as page data (:page-image: becomes image in the data) all other header attributes are also available in page.data.attributes You can also use FrontMatter headers to set the page data like any other page. Roq attributes Name Description | {site-url} | The full site url (e.g. https://my-site.com/blog/) | | {site-path} | The site path (e.g. /blog/) | | {page-url} | The full page url (e.g. https://my-site.com/blog/about/) | | {page-path} | The page path (e.g. /blog/about) | AsciiDoc attributes configuration Attributes can be configured globally: quarkus.asciidoc.attributes.source-highlighter=highlight.js quarkus.asciidoc.attributes.icons=font Or as an include file in the AsciiDoc headers, or as part of the Frontmatter data asciidoc-attributes in a page or layout: --- asciidoc-attributes: notitle: true --- Table of Contents (TOC) To add a Table of Contents, use the page-content-toc attribute in your AsciiDoc header: :page-content-toc: true :page-content-toc-title: Contents :page-content-toc-levels: 2 This works with the default Roq theme and creates a dynamic sidebar TOC that highlights the current section as you scroll. AsciiDoc Data Conversion Convert data containing AsciiDoc into HTML using the asciidocToHtml template extension: --- bar: | == Hello * that's nice * I can use asciidoc in the data --- {page.data.bar.asciidocToHtml} ### [AsciiDoc JRuby](/plugin/asciidoc-jruby/) Full-featured Asciidoctor implementation based on AsciidoctorJ. Offers the complete AsciiDoc feature set including all extensions. Slower startup than the Java variant but covers all advanced AsciiDoc options. Add the .adoc or .asciidoc file extension to pages and they will be processed using Asciidoctor. Use Qute in AsciiDoc files Qute parsing is disabled by default on AsciiDoc files, to enable it: quarkus.asciidoc.qute=true You can also use the :qute: AsciiDoc header attribute to enable Qute parsing (or not :qute: false) per page. AsciiDoc includes You may use includes from anywhere in the site directory. Make sure the included file is ignored by Roq by prefixing the file or directory with _. include::_includes/attributes.adoc[] Headers AsciiDoc headers are parsed by Roq and used as page data: = Title is used as page title author is available through page.data.author and page.data.author-email revision is available through page.data.revision.number, page.data.revision.date and page.data.revision.remark attribute :description: is used as page description attributes starting with page- will be used as page data (:page-image: becomes image in the data) all other header attributes are also available in page.data.attributes You can also use FrontMatter headers to set the page data like any other page. Roq attributes Name Description | {site-url} | The full site url (e.g. https://my-site.com/blog/) | | {site-path} | The site path (e.g. /blog/) | | {page-url} | The full page url (e.g. https://my-site.com/blog/about/) | | {page-path} | The page path (e.g. /blog/about) | AsciiDoc attributes configuration Attributes can be configured globally: quarkus.asciidoc.attributes.source-highlighter=highlight.js quarkus.asciidoc.attributes.icons=font Or as an include file in the AsciiDoc headers, or as part of the Frontmatter data asciidoc-attributes in a page or layout: --- asciidoc-attributes: notitle: true --- Table of Contents (TOC) To add a Table of Contents, use the page-content-toc attribute in your AsciiDoc header: :page-content-toc: true :page-content-toc-title: Contents :page-content-toc-levels: 2 This works with the default Roq theme and creates a dynamic sidebar TOC that highlights the current section as you scroll. AsciiDoc Data Conversion Convert data containing AsciiDoc into HTML using the asciidocToHtml template extension: --- bar: | == Hello * that's nice * I can use asciidoc in the data --- {page.data.foo.asciidocToHtml} ### [Aliases](/plugin/aliases/) Create one or many aliases (redirections) for a page. Add aliases: [your-alias-here, another-alias-here] in the Front Matter to access the page using a customized URL. # content/posts/2024-08-29-welcome-to-roq.md --- layout: post title: "Welcome to Roq!" date: 2024-08-29 13:32:20 +0200 description: This is the first article ever made with Quarkus Roq tags: blogging aliases: [first-roq-article-ever] --- Now, when you access http://localhost:8080/first-roq-article-ever, you will be redirected to the 2024-08-29-welcome-to-roq blog post. You can use link templating in aliases. ### [Resume Theme](/theme/resume-theme/) Build a personal resume or CV with a data-driven YAML configuration. Data Files Add your resume info in the data/ directory: profile.yml firstName: Ada lastName: Lovelace jobTitle: Computational Pioneer city: London country: United Kingdom bio: | Ada Lovelace was a 19th-century mathematician known for her visionary work on Charles Babbage's Analytical Engine. bio.yml - title: Experience items: - header: "1842 - 1843" title: "Mathematician · Self-initiated · London" content: | Translated and annotated Luigi Menabrea's paper on Charles Babbage's Analytical Engine. Added extensive original notes, including the first published algorithm designed for a machine. - title: Education items: - header: "1830 - 1835" title: "Private Tutoring" content: | Studied mathematics and science under Augustus De Morgan and Mary Somerville. The bio data supports hierarchical items with subItems, collapsible/collapsed flags, ruler separators, and logo objects with label, imageUrl, and link. social.yml - name: LinkedIn url: https://www.linkedin.com/in/ada-lovelace/ - name: X url: https://x.com/ada-lovelace Color Themes The theme comes with 6 pre-configured color schemes (Purple, Blue, Emerald, Amber, Rose, Cyan). To use an alternate theme, import it in your web/style.css: /* Available: _theme-blue.css, _theme-emerald.css, _theme-amber.css, _theme-rose.css, _theme-cyan.css */ @import "./_theme-blue.css"; You can also create a custom color scheme by overriding the theme variables. The theme uses Tailwind CSS v4 color palettes. ### [Default Theme](/theme/default-theme/) The default Roq theme for blogs and sites (used on this site). Built with Tailwind CSS, featuring dark mode, responsive design, sidebar navigation, and social media links. The accent color palette can easily be customized with your own colors or any existing Tailwind color palette. Site Data Configure your site through the index page frontmatter (e.g. content/index.html): Key Description name Site name displayed in the sidebar simple-name Short name used in the copyright notice logo Logo image path displayed in the sidebar (falls back to image) description Site tagline shown below the logo theme-color Color used for the browser address bar on mobile (default: #263959) Analytics analytics: ga4: G-XXXXXXXXXX Social Brands Add social media links to your site through the index page frontmatter: social-github: quarkiverse social-twitter: quarkusio social-linkedin: john-doe social-mastodon: https://mastodon.social/@username Available keys: social-twitter, social-github, social-linkedin, social-linkedin-company, social-facebook, social-youtube, social-discord, social-email, social-bluesky, social-mastodon, social-slack, social-whatsapp, social-instagram, social-telegram. For Mastodon and Slack, you must provide the complete URL as these platforms don't have a standard prefix. Menu Define navigation menus in data/menu.yml. Each key becomes a menu section in the sidebar: nav: - title: "Home" path: "/" icon: "fa-solid fa-house" - title: "Blog" path: "/blog" icon: "fa-regular fa-newspaper" doc: - title: "Getting Started" path: "/docs/getting-started/" icon: "fa fa-bolt" Each item supports title, path, icon (Font Awesome class), and optionally target (e.g. _blank for external links). Authors Define authors in data/authors.yml to display author info on blog posts: ada: name: "Ada Lovelace" avatar: "https://example.com/ada.png" job: Software Pioneer profile: "https://x.com/ada" nickname: "ada" bio: "Passionate about algorithms and analytical engines." Then reference an author in a post's frontmatter with author: ada. Layouts Theme layouts are automatically available: use layout: foo and it resolves local first, then falls back to the theme. To override a theme layout, create your own layout file and use theme-layout: foo to extend from the original. default // Base HTML structure ├── main // Shared site layout (sidebar, nav, footer) │ ├── home // Home page │ ├── blog // Blog listing with pagination │ ├── page // Generic page │ ├── post // Blog post with author and tags │ └── tag // Tag archive page └── 404 // Error page Page Data Frontmatter keys available to control page behavior per layout. All layouts Key Description Default body-class Custom CSS class on the body element page-class CSS class for page-specific styling robots Robots meta tag value Page / Post Key Description Default show-header Show the page header true show-header-date Show the date in the header true show-header-intro Show the description in the header true content-toc Enable table of contents false content-toc-title TOC section title Contents content-toc-levels Heading levels to include in TOC 2 Post Key Description Default author Author key from data/authors.yml tags List of tags for the post fig-caption Caption for the post cover image Blog Key Description Default featured Number of featured posts Partials Override any theme partial by creating a file with the same name in templates/partials/roq-default/: partials/roq-default/ ├── 404.html ├── head.html ├── head-scripts.html ├── page-header.html ├── page-toc.html ├── pagination.html ├── sidebar-about.html ├── sidebar-contact.html ├── sidebar-copyright.html ├── sidebar-darkmode.html └── sidebar-menu.html Qute User-Tags The theme provides reusable Qute user-tags for building pages: roq/hero Hero section for the home page. {#roq/hero logo="roq-logo.svg"} {#title}My Site{/title} {#tagline}A tagline for my site{/tagline} {#subtitle}Some extra info{/subtitle} {/roq/hero} roq/featureCard Feature card, typically used on the home page. {#roq/featureCard icon="fa-solid fa-bolt" title="Fast" link="/docs/" link-text="Learn more" highlighted=true} Feature description here. {/roq/featureCard} roq/postCard Blog post preview card. Used in blog and tag layouts, can also be used in custom pages. {#roq/postCard post=myPost /} roq/authorCard Author profile card. {#roq/authorCard name="Ada Lovelace" avatar="ada.png" profile="https://example.com" nickname="ada"} Author bio here. {/roq/authorCard} roq/terminal Terminal emulator component for displaying commands. {#roq/terminal title="Getting Started"} {#commands} {#command} {#prompt}${/prompt} {#cmd}quarkus{/cmd} {#args}create app my-site -x roq{/args} {/command} {/commands} {/roq/terminal} CSS Customization Create a web/_custom.css file in your site to override theme styles. This file is processed by Tailwind, so you can use Tailwind utilities, @apply, @theme, and other Tailwind features. Other CSS files added to web/ are bundled as plain CSS without Tailwind processing. Color Palettes The theme is built on three color palettes. Override any combination to completely transform the look and feel of your site: Palette Role Default accent Structure: headings, links, page headers, sidebar slate pop Energy: buttons, hover effects, gradients, icons sky neutral Text and backgrounds: body text, cards, sidebar background gray To swap a palette, map all 11 shades (50 through 950) in a @theme block in your web/_custom.css. You can use any Tailwind color or custom hex values: @theme { /* Accent: indigo instead of slate */ --color-accent-50: var(--color-indigo-50); --color-accent-100: var(--color-indigo-100); --color-accent-200: var(--color-indigo-200); --color-accent-300: var(--color-indigo-300); --color-accent-400: var(--color-indigo-400); --color-accent-500: var(--color-indigo-500); --color-accent-600: var(--color-indigo-600); --color-accent-700: var(--color-indigo-700); --color-accent-800: var(--color-indigo-800); --color-accent-900: var(--color-indigo-900); --color-accent-950: var(--color-indigo-950); /* Pop: rose instead of sky */ --color-pop-50: var(--color-rose-50); --color-pop-100: var(--color-rose-100); --color-pop-200: var(--color-rose-200); --color-pop-300: var(--color-rose-300); --color-pop-400: var(--color-rose-400); --color-pop-500: var(--color-rose-500); --color-pop-600: var(--color-rose-600); --color-pop-700: var(--color-rose-700); --color-pop-800: var(--color-rose-800); --color-pop-900: var(--color-rose-900); --color-pop-950: var(--color-rose-950); /* Neutral: stone instead of gray */ --color-neutral-50: var(--color-stone-50); --color-neutral-100: var(--color-stone-100); --color-neutral-200: var(--color-stone-200); --color-neutral-300: var(--color-stone-300); --color-neutral-400: var(--color-stone-400); --color-neutral-500: var(--color-stone-500); --color-neutral-600: var(--color-stone-600); --color-neutral-700: var(--color-stone-700); --color-neutral-800: var(--color-stone-800); --color-neutral-900: var(--color-stone-900); --color-neutral-950: var(--color-stone-950); } Changing all three palettes gives your site a completely different identity while keeping the same layout and structure. You can also override just one or two palettes. The Roq blog itself uses a custom cyan for accent and orange for pop. Sidebar The sidebar is fully customizable through theme variables in web/_custom.css. Color variables are defined in @theme and can be used as Tailwind utilities (e.g. text-sidebar, bg-sidebar-subtle): Variable Role Default Utility --color-sidebar Main text color neutral-300 text-sidebar --color-sidebar-heading Site name, headings white text-sidebar-heading --color-sidebar-muted Secondary text, separators neutral-500 text-sidebar-muted --color-sidebar-subtle Subtle borders, hover backgrounds rgba(255,255,255,0.06) border-sidebar-subtle --color-sidebar-border Sidebar right border neutral-700 border-sidebar-border --sidebar-bg Background (supports gradients) neutral 800→900 gradient By default the sidebar is dark in both modes. To create a light sidebar in light mode with a dark sidebar in dark mode: @theme { --color-sidebar: var(--color-indigo-800); --color-sidebar-heading: var(--color-indigo-950); --color-sidebar-muted: var(--color-indigo-500); --color-sidebar-subtle: rgba(0, 0, 0, 0.08); --color-sidebar-border: var(--color-indigo-200); --sidebar-bg: linear-gradient(180deg, var(--color-indigo-50) 0%, var(--color-indigo-100) 100%); } .dark { --color-sidebar: var(--color-indigo-200); --color-sidebar-heading: white; --color-sidebar-muted: var(--color-indigo-400); --color-sidebar-subtle: rgba(255, 255, 255, 0.06); --color-sidebar-border: var(--color-indigo-800); --sidebar-bg: linear-gradient(180deg, var(--color-indigo-950) 0%, var(--color-indigo-900) 100%); } For best dark mode legibility with colored sidebars, test your chosen palette carefully. Alternatively, omit the .dark block to fall back to the default dark sidebar. Dark Mode Dark mode is built-in with automatic system preference detection and a toggle in the sidebar. No configuration needed. SEO The theme includes built-in SEO support with meta tags, Open Graph, Twitter cards, favicon auto-discovery, and RSS. For more details, see the SEO, Favicon, Analytics, and RSS documentation. ### [Base Theme](/theme/base-theme/) The base theme is a minimal starting point included with Roq. It provides the essential HTML structure with SEO, favicon, and Web Bundler support, giving you full control over your site's design. This is the ideal choice when you want to build a fully custom site from scratch. Layouts default // Base HTML structure (SEO, favicon, bundle) ├── page // Simple page with title └── post // Post with title and date The default layout provides the HTML skeleton with: {#seo /} for meta tags, Open Graph, and Twitter cards {#favicon /} for automatic favicon discovery {#bundle /} for CSS and JS bundling via Web Bundler The page and post layouts extend default with minimal markup (title, content, and date for posts). Customization Since the base theme provides only the HTML structure, you style everything through your own CSS in web/app.css. The starter CSS includes basic variables for colors, typography, and a simple card layout that you can replace entirely. See the Favicon, SEO, and Analytics documentation for configuring the built-in tags. ## Posts ### [GFM Alert Blocks: Styled Callouts in Your Markdown](/posts/gfm-alert-blocks-styled-callouts-in-your-markdown/) Roq now supports GitHub Flavored Markdown (GFM) alert blocks (also known as admonition blocks) — the styled callouts you see on GitHub READMEs and issues, complete with icons and color themes: Note Useful information that users should know, even when skimming content. Tip Helpful advice for doing things better or more easily. Important Key information users need to achieve their goal. Warning Urgent info that needs immediate user attention to avoid problems. Caution Advises about risks or negative outcomes of certain actions. How It Works Alert blocks use a special blockquote syntax with a type identifier: > [!NOTE] > Your note content here. The five standard types are: Type Icon Color Use Case NOTE Info circle Blue General information TIP Light bulb Green Helpful suggestions IMPORTANT Verified badge Purple Critical information WARNING Alert triangle Orange Potential issues CAUTION Stop octagon Red Dangerous actions Icons are from GitHub Octicons (MIT license). Custom Alert Types You can configure custom alert types beyond the standard five. Add this to your application.properties: quarkus.qute.web.markdown.plugin.alerts.custom-types.INFO=Information quarkus.qute.web.markdown.plugin.alerts.custom-types.BUG=Known Bug quarkus.qute.web.markdown.plugin.alerts.custom-types.SECURITY=Security Notice Then use them in your markdown: > [!INFO] > This is a custom info alert. > [!BUG] > This is a known issue. > [!SECURITY] > This is a security notice. Custom alert types get basic styling (border, padding, rounded corners) but no icon or color by default. To add them, see the Styling section below. Custom alerts without custom CSS: Information This alert has basic styling but no icon or color. Known Bug Same here — add custom CSS to style it. Security Notice And this one too. Styling The roq-default theme includes full styling for the 5 standard GFM alert types: icons, colored borders, pastel backgrounds, and dark mode support. How SVG Icons Work Icons use the mask-image + background-color technique. The SVG defines only the shape (mask), and background-color: var(--alert-color) fills that shape with a color. This means one SVG works in any color — including dark mode. The SVGs are inlined as data URIs in the CSS using URL-encoded format: --alert-icon: url("data:image/svg+xml,%3Csvg%20xmlns%3D...%3E%3Cpath%20d%3D%22...%22/%3E%3C/svg%3E"); Icons are from GitHub Octicons (MIT license). For Custom Themes If you're using a custom theme, add alert styling to your CSS: .markdown-alert { padding: 1rem; margin: 1rem 0; border-radius: 0.5rem; border-left: 4px solid; } .markdown-alert-title { display: flex; align-items: center; gap: 0.5rem; font-weight: 600; margin-bottom: 0.25rem; } .markdown-alert-title::before { content: ""; display: inline-block; width: 1rem; height: 1rem; flex-shrink: 0; background-color: var(--alert-color); mask-image: var(--alert-icon, none); mask-size: 100%; mask-repeat: no-repeat; mask-position: center; } /* Standard types */ .markdown-alert-note { --alert-color: #0969da; --alert-icon: url("data:image/svg+xml,..."); /* info-16 SVG as data URI */ border-color: #0969da; background: #0969da08; } .markdown-alert-note .markdown-alert-title { color: #0969da; } Adding Icons & Colors for Custom Types To style a custom alert type (e.g., INFO), add CSS with the --alert-icon and --alert-color variables: .markdown-alert-info { --alert-color: #0550ae; --alert-icon: url("data:image/svg+xml,..."); /* your SVG as data URI */ border-color: #0550ae; background: #0550ae08; } .markdown-alert-info .markdown-alert-title { color: #0550ae; } .markdown-alert-bug { --alert-color: #cf222e; --alert-icon: url("data:image/svg+xml,..."); /* bug SVG as data URI */ border-color: #cf222e; background: #cf222e08; } .markdown-alert-bug .markdown-alert-title { color: #cf222e; } .markdown-alert-security { --alert-color: #da3633; --alert-icon: url("data:image/svg+xml,..."); /* shield-16 SVG */ border-color: #da3633; background: #da363308; } .markdown-alert-security .markdown-alert-title { color: #da3633; } Which of these alert blocks will you use first? ### [Set It in Roq: The Editor that change the game!](/posts/set-it-in-roq-the-editor-that-change-the-game/) Roq started as a solid foundation for building modern apps and static sites. But now, it’s leveling up in a big way. With the introduction of a TipTap-powered Editor with Markdown support, Roq is no longer just an SSG tool, it’s stepping into CMS territory. Why This Is a Big Deal Until now, writers had to: Use an IDE or a text editor. Manually create new article files. Manually open the article preview. Use Markdown as code Now, with Roq’s built-in editor: Native integration: all integrated in Quarkus dev experience. Rich Text Editor with Markdown support: write your content in a notion like editor, render beautifully. Preview article: directly from the editor or using a new tab. This makes Roq feel less like a static site generator and more like a developer-friendly CMS, closer to the flexibility of WordPress — but without the heavyness. Key Features Rich formatting: Bold, italic, headings, lists. Markdown support: Switch between rich text and Markdown seamlessly. Code editor with syntax highlighting: For HTML and AsciiDoc content. Media embedding: Images, links, and more. How to Try It (BETA) We’ve tested the editor in many different scenarios to ensure it’s safe to use. That said, it’s still in Beta, and it will need a few more weeks before it’s fully ready. In the meantime, make sure you always review the diffs before merging any content. The editor is natively integrated into Roq 2.1.0.BETA2. Until the final release is available, you’ll need to set this version manually in your pom.xml. Start Dev-Mode roq 🚀 Hit b (like CMS) to Open The Roq Editor. ### [Roq 2.0 and Java Advent Calendar article](/posts/roq-2-0-and-java-advent-calendar-article/) Hello fellow Roqers, I’m thrilled to announce that Roq 2.0 is here 🚀—and it’s a big one! 🔥 Think of it like a new iPhone launch: most of the magic happens under the hood. Many changes aren’t immediately visible, but they’re packed with powerful developer features that make a huge difference. 🕵️ Added lightning filesystem watcher for live reload 📂 Allow web directory at the root of the Roq site 🧩 Simplified default app structure: supports web/app.js and web/app.scss (or web/app/app.js like before …​) ⚡️ TailwindCSS support without any config 💫 Directory support for data and allow iterating on nested data files using the directory name It might not look like much at first glance, but this release represents a long journey to build a solid foundation. That foundation now makes it possible to support plugins like TailwindCSS, Svelte, and Vue — true to the Quarkus spirit, with zero configuration required. I might write a blog post about Web Bundler 2.0, which makes all this possible. The native binding with architecture driven Maven/Gradle dependencies is pretty cool.. let me know in the comments if that would interest you. I’ve also spent time writing a tutorial to showcase all these new features. It’s published in the Java Advent Calendar alongside other cool Java content to explore this Christmas. Take care and happy coding! 🎄 ### [Major site migrations to Roq](/posts/major-site-migrations-to-roq/) Two prominent websites have recently completed their migration to Roq: wildfly.org and jbang.dev. These migrations mark a significant milestone in the adoption of Roq as a modern static site generator. WildFly.org on the roq The official WildFly project site, wildfly.org, has transitioned from its legacy setup on Jekyll. This move brings faster build times, simplified deployment, and better integration with modern Java tooling. WildFly is a powerful, modular, and lightweight Java application server that provides all the tools you need to build robust enterprise applications. https://github.com/wildfly/wildfly.org/ JBang.dev is awesome right? Similarly, jbang.dev, the home of the JBang scripting tool, has now adopted Roq for its site generation instead of Jekyll. JBang let Students, Educators and Professional Developers create, edit and run self-contained source-only Java programs with unprecedented ease. https://github.com/jbangdev/jbang.dev Roq’s Enhanced AsciiDoc Support Roq now offers robust support for AsciiDoc content. This includes: Header parsing: Roq can extract metadata from AsciiDoc headers, enabling dynamic routing and layout selection without FrontMatter header. Includes support: Authors can modularize content using AsciiDoc includes, making documentation more maintainable and reusable. These features make Roq an excellent choice for documentation-heavy sites and technical blogs. Read more about Roq with Asciidoc…​ More Sites Coming Soon! The momentum doesn’t stop here. Several other sites are currently in the pipeline to migrate to Roq, signaling growing confidence in its capabilities and developer experience. With its blazing-fast builds and flexible content handling, Roq is quickly becoming the go-to solution for modern static site generation in the Java ecosystem. Stay tuned for more announcements! ### [More diagram than you could have dreamed of.](/posts/more-diagram-than-you-could-have-dreamed-of/) As much as you love writing content in a textual format, you like to produce your diagram as code. But there are so many: PlantUML, Ditaa, Mermaid, BPMN and so on and so forth. Integrating all those formats would be a real pain. Hopefully you don’t have to, Kroki.io has already done it for you. A new plugin has been added to integrate its capability seamlessly to ROQ You can use it through an already deployed server or let the plugin make use of Quarkus dev services to do the job for you. 👉 Full documentation is available here, let’s diagram all the things! ### [🔎 Your users deserve searching capabilities!](/posts/your-users-deserve-searching-capabilities/) So your site is growing larger and larger and so it becomes harder and harder to find anything you wrote more than a few weeks ago. And that is frustrating. Words vanish, writing remains Yes…​ But if it remains buried deep in a pile of posts, it won’t be of any use to any one. It seems you need to add a search engine to your site. But…​ you choose static generation for a reason, right ? Economy of resources, matters to you. And so you don’t want to add a full-blown search engine like ElasticSearch or Solr. And guess what ? We couldn’t agree more with you 🤩. We think you are perfectly right, and that people should listen to you more. At least that’s what we do. 👂 So we did a bit of research and found out exactly what you need : Lunr.js, it’s a small, full-text search engine written in JavaScript. It runs in the browser based on a static generated json index and don’t need any other third party services ✨. Tadddaaah! We wrote a Lunr.js plugin for Roq.   👉 Full documentation is available here, don’t wait any longer, go check it out. ### [No pain updates with Roq](/posts/no-pain-updates-with-roq/) One of the most overlooked aspects when choosing a Static Site Generator (SSG) is how easy it is to keep your project up to date. Many developers have struggled with complex upgrade processes, dependency conflicts, and breaking changes when using traditional SSGs like Jekyll or Hugo. With Roq, upgrading is refreshingly simple. Updating Roq: A One-Command Upgrade Roq is built on Quarkus, which provides a streamlined upgrade process via the Quarkus CLI. To update Roq to the latest version, all you need to do is run: quarkus update ### [Comparing Roq with Hugo, Jekyll, and JBake: A Feature Breakdown](/posts/comparing-roq-with-hugo-jekyll-and-jbake-a-feature-breakdown/) Here’s a feature comparison with some popular SSGs to highlight how Roq stacks up. Feature Roq Hugo Jekyll JBake Performance Fast, and leveraging Quarkus dev-mode Extremely fast (written in Go) Slower due to Ruby and plugins Slower, runs on Java with Freemarker/Groovy templates Templating Qute (simple & readable) Go templates (powerful but complex) Liquid (easy but limited) Freemarker, Groovy, or Thymeleaf Extensibility Leverages Quarkus extensions Limited plugin system Large plugin ecosystem Limited, Java-based plugins Setup Requires JDK (for now) Single binary install Requires Ruby & Bundler Requires Java & Gradle/Maven Dynamic Features Can integrate with Quarkus for hybrid use Mostly static, some JS workarounds Plugins enable some dynamic behavior Fully static Community Growing, part of Quarkus ecosystem Large, well-established Large, long history Niche, less active Learning Curve Beginner friendly, easier for Java developers Can be difficult due to Go templates Complex to setup and update Moderate, depends on template engine A Quick Note About Roq Roq is highly extensible through plugins, which are built as Quarkus extensions (dependencies). Key features like SEO, Search and Sitemap are already available, with more features in the works, including: Image processing (Issue #42) Theme catalog to help get started (Issue #270). While it’s not difficult to convert themes from other SSGs to Roq, I’m working on an AI-based theme converter (Issue #365) to make this process even easier 😁. Considering its young age, Roq is still very complete! Conclusion Jekyll is widely used but comes with the complexity of setting up Ruby environments, which often causes headaches. It has a strong plugin system and is easy to get started with, but performance can be an issue for large sites. JBake was the only Java-based SSG before Roq, but it feels outdated compared to modern alternatives. It lacks the flexibility and performance optimizations of newer SSGs like Hugo and Roq. Roq aims to offer a modern, Java-friendly alternative that brings the ease of Jekyll, the speed of Hugo (to some extent), and the flexibility of Quarkus. ### [Roq n Roll Your Tests 🎶](/posts/roq-n-roll-your-tests/) Hello folks, I'm excited to share something very cool! I've developed a way to: Test the full generation of your website. Use RestAssured to test the generated site (thanks to an already started static server). Step 1: Add the Dependency First, include the quarkus-roq-testing test dependency in your pom.xml. Step 2: Basic Test Example Once you've added the dependency, you can easily ensure all pages are generated without errors: @QuarkusTest @RoqAndRoll public class RoqSiteTest { @Test public void testGen() { // All pages will be generated/validated during test setup } } That's it! This basic test already verifies that your site generation is error-free. Step 3: Test the Generated Content To go even further, you can test the actual content of your generated site. The RestAssured port will automatically use the Roq static server. Here's how: @QuarkusTest @RoqAndRoll public class RoqSiteTest { @Test public void testIndex() { RestAssured.when().get("/") .then() .statusCode(200) .body(containsString( "Roq is a static site generator that makes it easy to build websites and blogs" )); } } Why I Love It ❤️ With just a few annotations and a bit of setup, you can effortlessly test both the generation process and the content of your site. It's powerful, elegant, and super simple to use. Give it a try and let me know how it works for you. Happy testing! 🚀 ### [Easily Generate a `sitemap.xml` for Your Site with Roq](/posts/easily-generate-a-sitemap-xml-for-your-site-with-roq/) Creating a sitemap.xml for your site has never been easier! With the Sitemap plugin, you can automatically generate a well-structured sitemap for search engines to crawl your pages efficiently. Installation To get started, install the plugin by running the following command: roq add plugin:sitemap Setting Up the Sitemap Next, create a new sitemap file in the content/sitemap.xml: <!-- Include your sitemap template --> {#include fm/sitemap.xml} And that's it! Your sitemap is now ready. Excluding Pages from the Sitemap If there are pages you don't want included in the sitemap, simply set the sitemap property to false in the FM of those pages. For example: --- title: "Hidden Page" sitemap: false --- Accessing Your Sitemap Once your site is up and running, you can view your sitemap by navigating to: http://localhost:8080/sitemap.xml Congratulations! You’ve successfully set up a sitemap.xml for your site. ### [Static attached files for posts and pages](/posts/static-attached-files-for-posts-and-pages/) This Christmas, I’m Roq-ing a cool new feature (inspired by Hugo 😅): it is possible to attach static files to posts and pages. They will be served relative to the page. 🎁🤩 I love it because it allows to put all the content related to one page or post in the same place. Bonus, images are displayed on previews since they are relative to the template. For example here is a sample pdf: link. Fun fact: @parisjug is already using this feature on their site (which is on Hugo 🤪)! The doc for this feature is here. ### [Already some happy users 🧑‍💻](/posts/already-some-happy-users/) Roq is a rookie and still needs to prove itself, but already, there are good signs ☀️ The very first to give Roq a shot was David—a talented developer from the Quarkus Team! No images on your blog, David? Maybe it’s because you don’t want them stealing the spotlight from your content, right? Don’t worry, I’ll create an Unsplash plugin just for you. It will automatically pick images based on your content, so you don’t have to lift a finger! David's was nice enough to share about switching from Jekyll to Roq (in his first Roq post:): https://word-bits.flurg.com/posts/it-s-alive/ (repo) I live near Marseille and know the owners of MarsJug. I decided to try switching their website to Roq. Their original site consisted of plain HTML pages with raw event details hardcoded, making updates and maintenance a nightmare. It took just a minute to convince them of the benefits of using Roq. https://marsjug.org/ (repo) Jotak, a Red Hat developer working on the NetObserv project, used to lean more towards Vert.x than Quarkus—something we debated quite a bit back in the day. It’s a shame he had to step away from Java development due to project constraints a few years ago. Still, he managed to convince his team (working with Go and React) to switch to Roq 🚀. https://netobserv.io (repo) Will you be the next to share your Roq's journey? Come on 😎 !!! ### [Do you want to publish a blog post series ?](/posts/do-you-want-to-publish-a-blog-post-series/) So you plan to do a series of blog posts about a given subject. This is as simple as adding a series attribute to the front matter of your posts. Step 1: Add the Series plugin in your dependencies file: <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-plugin-series</artifactId> <version>${quarkus-roq.version}</version> </dependency> Step 2: Edit the layout for your posts, for example when using roq-default theme: templates/layouts/post-series.html --- theme-layout: post --- {#include partials/roq-series /} (1) {#insert /} (2) 1 This will add the series partial before the post content, if it’s declared. 2 This is the post content. And finally, use this layout and add the series attribute in the Front Matter of the posts you want to join. --- layout: series-post title: Assemble you blog post in a series description: Automatically series header for your posts tags: plugin, frontmatter, guide, series author: John Doe series: My series Title (1) --- 1 You should use the exact same title for all documents in the series. It will add the following at the head of your post: A bit like what you see at the very begining of this post. ### [Need a QR Code?](/posts/need-a-qr-code/) Need to add a scannable QR Code to your website? Whether it's for a restaurant menu, event ticket, or any other use case where you want to make your content easily accessible via mobile devices, the Roq QR Code plugin has you covered. Step 1: Add the QRCode plugin in your dependencies file: <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-plugin-qrcode</artifactId> <version>...</version> </dependency> Step 2: Add the QRCode tag to your template with all the parameters you need: {#qrcode value="https://luigis.com/menu/" alt="Luigi's Menu" foreground="#000066" background="#FFFFFF" width=300 height=300 /} It will render a QR Code like this: ### [Roq with Blogs](/posts/roq-with-blogs/) Hello folks, First let me thanks the Roq contributors, they have been awesome and this has been so fun to create Roq! If you want to get started quickly: Click here to generate your Roq Starter App. or use the Roq CLI: roq create Then cd blog-with-roq roq If you have a bit of time, with this release, I think it's time for me to give you the full story 📖: It all started a while back when I helped my wife create her blog. After reviewing a few options, I decided to use Jekyll, as it was the easiest solution with GitHub Pages. Over time, I grew quite frustrated with the process: It was hard for my wife to install and start using. It was challenging to maintain and keep updated. Using Ruby didn’t feel great. Plugins were often outdated or unmaintained. Then my wife said: My wife: “But why don’t you use your famous Quarkus?” Me: “This is not the right tool to create a blog 😭” I think this was around the time Quarkus 1.0 was being released... ... 😴 Time passes ... 🗓️ Mar 23, 2022: quarkus-quinoa 🗓️ Feb 3, 2023: quarkus-web-bundler 🗓️ Early 2024: Quarkus web guide At this point, I thought back on what my wife had said... maybe it was time to reconsider? But Qute processes things at runtime, so it didn’t seem possible 😤 ... 😴 Time passes ... 🗓️ May 7, 2024: My idea was to generate static pages at runtime… because then all of Quarkus could become static without any changes 😍. 🗓️ May 17, 2024: quarkus-roq (generator part) At this point, I thought we (mostly) had everything in Quarkus to change my answer to my wife 🤓 For those who wonder, "Roq" was chosen because: static = rock, rock + quarkus = roq 🗓️ June 19, 2024: Roq Focus Group And now, thanks to the awesome team 🧑‍💻👩🏻‍💻! 🗓️ October 31, 2024: Roq 1.0 🎉🍾🥂 If you like the idea, support us, give us a star ⭐ or start contributing... ### [Write your blog posts in AsciiDoc](/posts/write-your-blog-posts-in-asciidoc/) Writing content is AsciiDoc format is an absolut no brainer. Roq provides a plugin to handle it transparently for you. To use it, you need to add the `quarkus-roq-plugin-asciidoc' to your project. Details You can do that using several ways : Manually pom.xml <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-plugin-asciidoc</artifactId> <version>${quarkus-roq.version}</version> </dependency> Using the Roq CLI roq add plugin:asciidoc Using Maven ./mvnw quarkus:add-extension -Dextensions="io.quarkiverse.roq:quarkus-roq-plugin-asciidoc" Using the Gradle ./gradlew addExtension --extensions="io.quarkiverse.roq:quarkus-roq-plugin-asciidoc" Once done, you can start writing your blog posts in AsciiDoc format. ### [RSS Feed of your blog posts](/posts/rss-feed-of-your-blog-posts/) Adding RSS is as easy as adding this tag to your <head> section: {#rss site /} Like this: <link rel="alternate" type="application/rss+xml" title="Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free." href="https://iamroq.dev/rss.xml"/> It will automatically utilize the Frontmatter data from all your blog posts to generate a valid Atom RSS feed link at rss.xml. Ensure you create an rss.xml file at the root of your site and include this single line of code: {#include fm/rss.html /} The Atom Syndication Format is an XML language used for web feeds. A web feed (also called ‘news feed’ or ‘RSS feed’) is a data format used for providing users with frequently updated content. Content distributors syndicate a web feed, thereby allowing users to subscribe a channel to it. A typical scenario of web-feed use might involve the following: a content provider publishes a feed link on its site which end users can register with an aggregator program (also called a feed reader or a newsreader) running on their own machines. <rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"> <channel> <title><![CDATA[ Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. ]]></title> <description><![CDATA[ An Open Source static site generator (SSG) that makes it fun and easy to build websites and blogs. It's built with Java and Quarkus under the hood. ]]></description> <link>https://iamroq.dev/</link> <atom:link href="https://iamroq.dev/rss.xml" rel="self" type="application/rss+xml"/> <generator>Quarkus Roq</generator> <lastBuildDate>Wed, 08 Apr 2026 23:00:00 +0000</lastBuildDate> <item> <title><![CDATA[GFM Alert Blocks: Styled Callouts in Your Markdown]]></title> <link>https://iamroq.dev/posts/gfm-alert-blocks-styled-callouts-in-your-markdown/</link> <guid isPermaLink="false">https://iamroq.dev/posts/gfm-alert-blocks-styled-callouts-in-your-markdown/</guid> <pubDate>Wed, 08 Apr 2026 23:00:00 +0000</pubDate> <description><![CDATA[Roq supports GitHub Flavored Markdown alert blocks with icons and themed colors. Learn how to use NOTE, TIP, IMPORTANT, WARNING, and CAUTION blocks, and how to add custom alert types.]]></description> <content:encoded><![CDATA[<p>Roq supports GitHub Flavored Markdown alert blocks with icons and themed colors. Learn how to use NOTE, TIP, IMPORTANT, WARNING, and CAUTION blocks, and how to add custom alert types.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/gfm-alert-blocks-styled-callouts-in-your-markdown/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Set It in Roq: The Editor that change the game!]]></title> <link>https://iamroq.dev/posts/set-it-in-roq-the-editor-that-change-the-game/</link> <guid isPermaLink="false">https://iamroq.dev/posts/set-it-in-roq-the-editor-that-change-the-game/</guid> <pubDate>Sun, 01 Feb 2026 23:00:00 +0000</pubDate> <description><![CDATA[Roq introduces a TipTap-powered editor with Markdown support, transforming it from a static site generator into a lightweight, developer-friendly CMS. Create, edit, and preview content seamlessly within the Quarkus dev experience.]]></description> <content:encoded><![CDATA[<p>Roq introduces a TipTap-powered editor with Markdown support, transforming it from a static site generator into a lightweight, developer-friendly CMS. Create, edit, and preview content seamlessly within the Quarkus dev experience.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/set-it-in-roq-the-editor-that-change-the-game/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Roq 2.0 and Java Advent Calendar article]]></title> <link>https://iamroq.dev/posts/roq-2-0-and-java-advent-calendar-article/</link> <guid isPermaLink="false">https://iamroq.dev/posts/roq-2-0-and-java-advent-calendar-article/</guid> <pubDate>Tue, 09 Dec 2025 00:00:00 +0000</pubDate> <description><![CDATA[An introduction to Roq 2.0, a Quarkus-inspired approach to static site generation in Java. Learn about its new foundation, plugin support, and live-reload feature through a practical tutorial.]]></description> <content:encoded><![CDATA[<p>An introduction to Roq 2.0, a Quarkus-inspired approach to static site generation in Java. Learn about its new foundation, plugin support, and live-reload feature through a practical tutorial.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/roq-2-0-and-java-advent-calendar-article/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Major site migrations to Roq]]></title> <link>https://iamroq.dev/posts/major-site-migrations-to-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/major-site-migrations-to-roq/</guid> <pubDate>Tue, 26 Aug 2025 00:00:00 +0000</pubDate> <description><![CDATA[✨ Two prominent websites have just migrated to Roq—any guesses who they might be?]]></description> <content:encoded><![CDATA[<p>✨ Two prominent websites have just migrated to Roq—any guesses who they might be?</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/major-site-migrations-to-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[More diagram than you could have dreamed of.]]></title> <link>https://iamroq.dev/posts/more-diagram-than-you-could-have-dreamed-of/</link> <guid isPermaLink="false">https://iamroq.dev/posts/more-diagram-than-you-could-have-dreamed-of/</guid> <pubDate>Wed, 11 Jun 2025 00:00:00 +0000</pubDate> <description><![CDATA[Leveraging Kroki.io to generate diagram from text]]></description> <content:encoded><![CDATA[<p>Leveraging Kroki.io to generate diagram from text</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/more-diagram-than-you-could-have-dreamed-of/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[🔎 Your users deserve searching capabilities!]]></title> <link>https://iamroq.dev/posts/your-users-deserve-searching-capabilities/</link> <guid isPermaLink="false">https://iamroq.dev/posts/your-users-deserve-searching-capabilities/</guid> <pubDate>Fri, 04 Apr 2025 00:00:00 +0000</pubDate> <description><![CDATA[No third party service needed 🚀]]></description> <content:encoded><![CDATA[<p>No third party service needed 🚀</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/your-users-deserve-searching-capabilities/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[No pain updates with Roq]]></title> <link>https://iamroq.dev/posts/no-pain-updates-with-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/no-pain-updates-with-roq/</guid> <pubDate>Mon, 24 Mar 2025 00:00:00 +0000</pubDate> <description><![CDATA[One of the most overlooked aspects when choosing a Static Site Generator (SSG) is how easy it is to keep your project up to date. Many developers have struggled with complex upgrade processes, dependency conflicts, and breaking changes when using traditional SSGs like Jekyll or Hugo.]]></description> <content:encoded><![CDATA[<p>One of the most overlooked aspects when choosing a Static Site Generator (SSG) is how easy it is to keep your project up to date. Many developers have struggled with complex upgrade processes, dependency conflicts, and breaking changes when using traditional SSGs like Jekyll or Hugo.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/no-pain-updates-with-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Comparing Roq with Hugo, Jekyll, and JBake: A Feature Breakdown]]></title> <link>https://iamroq.dev/posts/comparing-roq-with-hugo-jekyll-and-jbake-a-feature-breakdown/</link> <guid isPermaLink="false">https://iamroq.dev/posts/comparing-roq-with-hugo-jekyll-and-jbake-a-feature-breakdown/</guid> <pubDate>Thu, 27 Feb 2025 00:00:00 +0000</pubDate> <description><![CDATA[]]></description> <content:encoded><![CDATA[<p></p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/comparing-roq-with-hugo-jekyll-and-jbake-a-feature-breakdown/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Roq n Roll Your Tests 🎶]]></title> <link>https://iamroq.dev/posts/roq-n-roll-your-tests/</link> <guid isPermaLink="false">https://iamroq.dev/posts/roq-n-roll-your-tests/</guid> <pubDate>Tue, 28 Jan 2025 00:00:00 +0000</pubDate> <description><![CDATA[Testing the actual Roq generation has never been this cool! 🎸]]></description> <content:encoded><![CDATA[<p>Testing the actual Roq generation has never been this cool! 🎸</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/roq-n-roll-your-tests/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Easily Generate a `sitemap.xml` for Your Site with Roq]]></title> <link>https://iamroq.dev/posts/easily-generate-a-sitemap-xml-for-your-site-with-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/easily-generate-a-sitemap-xml-for-your-site-with-roq/</guid> <pubDate>Wed, 08 Jan 2025 00:00:00 +0000</pubDate> <description><![CDATA[Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin.]]></description> <content:encoded><![CDATA[<p>Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/easily-generate-a-sitemap-xml-for-your-site-with-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Static attached files for posts and pages]]></title> <link>https://iamroq.dev/posts/static-attached-files-for-posts-and-pages/</link> <guid isPermaLink="false">https://iamroq.dev/posts/static-attached-files-for-posts-and-pages/</guid> <pubDate>Thu, 26 Dec 2024 00:00:00 +0000</pubDate> <description><![CDATA[This Christmas, I’m Roq-ing a cool new feature (inspired by Hugo 😅): it is possible to attach static files to posts and pages. They will be served relative to the page. 🎁🤩 ]]></description> <content:encoded><![CDATA[<p>This Christmas, I’m Roq-ing a cool new feature (inspired by Hugo 😅): it is possible to attach static files to posts and pages. They will be served relative to the page. 🎁🤩 </p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/static-attached-files-for-posts-and-pages/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Already some happy users 🧑‍💻]]></title> <link>https://iamroq.dev/posts/already-some-happy-users/</link> <guid isPermaLink="false">https://iamroq.dev/posts/already-some-happy-users/</guid> <pubDate>Tue, 10 Dec 2024 00:00:00 +0000</pubDate> <description><![CDATA[This is a good start, we already have a few happy users!]]></description> <content:encoded><![CDATA[<p>This is a good start, we already have a few happy users!</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/already-some-happy-users/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Do you want to publish a blog post series ?]]></title> <link>https://iamroq.dev/posts/do-you-want-to-publish-a-blog-post-series/</link> <guid isPermaLink="false">https://iamroq.dev/posts/do-you-want-to-publish-a-blog-post-series/</guid> <pubDate>Fri, 06 Dec 2024 07:00:00 +0000</pubDate> <description><![CDATA[Make your blog posts part of a series.]]></description> <content:encoded><![CDATA[<p>Make your blog posts part of a series.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/do-you-want-to-publish-a-blog-post-series/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Need a QR Code?]]></title> <link>https://iamroq.dev/posts/need-a-qr-code/</link> <guid isPermaLink="false">https://iamroq.dev/posts/need-a-qr-code/</guid> <pubDate>Thu, 14 Nov 2024 12:00:00 +0000</pubDate> <description><![CDATA[Add a QR Code to your Roq website.]]></description> <content:encoded><![CDATA[<p>Add a QR Code to your Roq website.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/need-a-qr-code/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Roq with Blogs]]></title> <link>https://iamroq.dev/posts/roq-with-blogs/</link> <guid isPermaLink="false">https://iamroq.dev/posts/roq-with-blogs/</guid> <pubDate>Thu, 31 Oct 2024 00:00:00 +0000</pubDate> <description><![CDATA[🚀 Roq 1.0 is ON! It is time to give it a shot and give us feedback 🚀]]></description> <content:encoded><![CDATA[<p>🚀 Roq 1.0 is ON! It is time to give it a shot and give us feedback 🚀</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/roq-with-blogs/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Write your blog posts in AsciiDoc]]></title> <link>https://iamroq.dev/posts/write-your-blog-posts-in-asciidoc/</link> <guid isPermaLink="false">https://iamroq.dev/posts/write-your-blog-posts-in-asciidoc/</guid> <pubDate>Tue, 22 Oct 2024 00:00:00 +0000</pubDate> <description><![CDATA[Automatically generate html from AsciiDoc content]]></description> <content:encoded><![CDATA[<p>Automatically generate html from AsciiDoc content</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/write-your-blog-posts-in-asciidoc/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[RSS Feed of your blog posts]]></title> <link>https://iamroq.dev/posts/rss-feed-of-your-blog-posts/</link> <guid isPermaLink="false">https://iamroq.dev/posts/rss-feed-of-your-blog-posts/</guid> <pubDate>Thu, 10 Oct 2024 00:00:00 +0000</pubDate> <description><![CDATA[Automatically generate an RSS feed of your blog links.]]></description> <content:encoded><![CDATA[<p>Automatically generate an RSS feed of your blog links.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/rss-feed-of-your-blog-posts/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[The second Roq plugin is for redirecting your page to a better place!]]></title> <link>https://iamroq.dev/posts/the-second-roq-plugin-is-for-redirecting-your-page-to-a-better-place/</link> <guid isPermaLink="false">https://iamroq.dev/posts/the-second-roq-plugin-is-for-redirecting-your-page-to-a-better-place/</guid> <pubDate>Wed, 09 Oct 2024 00:00:00 +0000</pubDate> <description><![CDATA[We introduced a way to declare aliases in FrontMatter. It is now easy create redirections to your blog posts!]]></description> <content:encoded><![CDATA[<p>We introduced a way to declare aliases in FrontMatter. It is now easy create redirections to your blog posts!</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/the-second-roq-plugin-is-for-redirecting-your-page-to-a-better-place/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[The first Roq plugin is for tagging (with pagination)]]></title> <link>https://iamroq.dev/posts/the-first-roq-plugin-is-for-tagging-with-pagination/</link> <guid isPermaLink="false">https://iamroq.dev/posts/the-first-roq-plugin-is-for-tagging-with-pagination/</guid> <pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate> <description><![CDATA[We introduced the first Roq plugin, it is for collection tagging & with pagination support!]]></description> <content:encoded><![CDATA[<p>We introduced the first Roq plugin, it is for collection tagging & with pagination support!</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/the-first-roq-plugin-is-for-tagging-with-pagination/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Out of the box awesome SEO]]></title> <link>https://iamroq.dev/posts/out-of-the-box-awesome-seo/</link> <guid isPermaLink="false">https://iamroq.dev/posts/out-of-the-box-awesome-seo/</guid> <pubDate>Mon, 23 Sep 2024 12:00:00 +0000</pubDate> <description><![CDATA[Learn how to implement SEO in Roq in a blink of an eye.]]></description> <content:encoded><![CDATA[<p>Learn how to implement SEO in Roq in a blink of an eye.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/out-of-the-box-awesome-seo/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Mastering Pagination in Roq]]></title> <link>https://iamroq.dev/posts/mastering-pagination-in-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/mastering-pagination-in-roq/</guid> <pubDate>Fri, 20 Sep 2024 12:00:00 +0000</pubDate> <description><![CDATA[Learn how to implement pagination in Roq to enhance your content navigation. This article walks through the process of adding pagination, configuring page size, and customizing links.]]></description> <content:encoded><![CDATA[<p>Learn how to implement pagination in Roq to enhance your content navigation. This article walks through the process of adding pagination, configuring page size, and customizing links.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/mastering-pagination-in-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[How to add syntax highlighting to your Roq site]]></title> <link>https://iamroq.dev/posts/how-to-add-syntax-highlighting-to-your-roq-site/</link> <guid isPermaLink="false">https://iamroq.dev/posts/how-to-add-syntax-highlighting-to-your-roq-site/</guid> <pubDate>Fri, 20 Sep 2024 09:00:00 +0000</pubDate> <description><![CDATA[Learn how to integrate syntax highlighting into your Roq site using Highlight.js and the Quarkus web-bundler extension. This guide walks you through the simple steps to add it via the pom.xml, JavaScript, and SCSS files.]]></description> <content:encoded><![CDATA[<p>Learn how to integrate syntax highlighting into your Roq site using Highlight.js and the Quarkus web-bundler extension. This guide walks you through the simple steps to add it via the pom.xml, JavaScript, and SCSS files.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/how-to-add-syntax-highlighting-to-your-roq-site/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Easily manage Drafts and Future articles in Roq]]></title> <link>https://iamroq.dev/posts/easily-manage-drafts-and-future-articles-in-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/easily-manage-drafts-and-future-articles-in-roq/</guid> <pubDate>Thu, 19 Sep 2024 08:45:00 +0000</pubDate> <description><![CDATA[Roq SSG introduces a new feature that allows you to hide or show draft and future articles using simple Quarkus configurations. This update gives developers greater control over which content is visible, improving content management and workflow.]]></description> <content:encoded><![CDATA[<p>Roq SSG introduces a new feature that allows you to hide or show draft and future articles using simple Quarkus configurations. This update gives developers greater control over which content is visible, improving content management and workflow.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/easily-manage-drafts-and-future-articles-in-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Effortless URL Handling in Roq with Qute super-power]]></title> <link>https://iamroq.dev/posts/effortless-url-handling-in-roq-with-qute-super-power/</link> <guid isPermaLink="false">https://iamroq.dev/posts/effortless-url-handling-in-roq-with-qute-super-power/</guid> <pubDate>Mon, 16 Sep 2024 11:32:20 +0000</pubDate> <description><![CDATA[Effortlessly manage both relative and absolute URLs with our enhanced Qute-powered feature. Utilizing the RoqUrl class, you can easily join and resolve paths, ensuring clean and predictable URLs. This update simplifies URL handling, making your code more efficient and your content easier to navigate and share.]]></description> <content:encoded><![CDATA[<p>Effortlessly manage both relative and absolute URLs with our enhanced Qute-powered feature. Utilizing the RoqUrl class, you can easily join and resolve paths, ensuring clean and predictable URLs. This update simplifies URL handling, making your code more efficient and your content easier to navigate and share.</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/effortless-url-handling-in-roq-with-qute-super-power/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> <item> <title><![CDATA[Welcome to Roq!]]></title> <link>https://iamroq.dev/posts/welcome-to-roq/</link> <guid isPermaLink="false">https://iamroq.dev/posts/welcome-to-roq/</guid> <pubDate>Thu, 29 Aug 2024 11:32:20 +0000</pubDate> <description><![CDATA[This is the first article ever made with Quarkus Roq]]></description> <content:encoded><![CDATA[<p>This is the first article ever made with Quarkus Roq</p><div style="margin-top: 50px; font-style: italic;"><strong><a href="https://iamroq.dev/posts/welcome-to-roq/">Keep reading</a>.</strong></div><br /> <br />]]></content:encoded> </item> </channel> </rss> ### [The second Roq plugin is for redirecting your page to a better place!](/posts/the-second-roq-plugin-is-for-redirecting-your-page-to-a-better-place/) In the last post, we saw how easy it is to use Quarkus for static site generator (@ia3andy's was right!). I am excited to share that we now have a new plugin that allows you to set up redirects for your blog posts! For this post, I've created three aliases. aliases-very-cool aliases-4-ever aliases-again If you click on at least one alias, you will be redirected here again! And how did I work my magic to set this up? Step 1: Add the aliases plugin in your dependencies file: <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-plugin-aliases</artifactId> <version>...</version> </dependency> Step 2: Add a new entry aliases: [name-of-aliases-here] in your FM data. In this blog post I used the following FM: ... aliases: [aliases-very-cool, aliases-4-ever, aliases-again] ... For more info check out the doc. ### [The first Roq plugin is for tagging (with pagination)](/posts/the-first-roq-plugin-is-for-tagging-with-pagination/) My mind is getting blown by how much Quarkus was made for Static Site Generation. I just implemented a new plugin to generate tag pages and that was soooo easy. To use it: <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-plugin-tagging</artifactId> <version>...</version> </dependency> and adding a new layouts/tag.html page or any layout with tagging: [name of collection] as FM data. For more info check out the doc. ### [Out of the box awesome SEO](/posts/out-of-the-box-awesome-seo/) Adding SEO is as easy as adding this tag to your <head> section: {#seo page site /} It will automatically use the Frontmatter data to fill the tags. Read the Roq documentation for more... Like this: <!-- SEO TITLE --> <title>Out of the box awesome SEO - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free.</title> <meta property="og:title" content="Out of the box awesome SEO" /> <meta name="twitter:title" content="Out of the box awesome SEO"> <meta property="og:site_name" content="Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free."> <!-- SEO DESCRIPTION --> <meta name="description" content="Learn how to implement SEO in Roq in a blink of an eye."> <meta property="og:description" content="Learn how to implement SEO in Roq in a blink of an eye." /> <meta name="twitter:description" content="Learn how to implement SEO in Roq in a blink of an eye."> <!-- SEO AUTHOR --> <meta property="article:author" content="ia3andy" /> <meta name="author" content="ia3andy" /> <!-- SEO URL --> <link rel="canonical" href="https://iamroq.dev/posts/out-of-the-box-awesome-seo/" /> <meta property="og:url" content="https://iamroq.dev/posts/out-of-the-box-awesome-seo/" /> <meta name="twitter:url" content="https://iamroq.dev/posts/out-of-the-box-awesome-seo/"> <!-- SEO TYPE --> <meta property="og:type" content="article" /> <meta property="article:published_time" content="2024-09-23T12:00Z[Etc/UTC]" /> <!-- SEO IMAGE --> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:image:src" content="https://images.unsplash.com/photo-1562577309-2592ab84b1bc?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" /> <meta property="og:image" content="https://images.unsplash.com/photo-1562577309-2592ab84b1bc?q=80&w=3474&auto=format&fit=crop&ixlib=rb-4.0.3&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D" /> <!-- SEO COLLECTION PAGES --> <link rel="prev" href="https://iamroq.dev/posts/the-first-roq-plugin-is-for-tagging-with-pagination/" /> <link rel="next" href="https://iamroq.dev/posts/mastering-pagination-in-roq/" /> <!-- SEO LOCALE --> <meta property="og:locale" content="en" /> <!-- SEO GENERATOR --> <meta name="generator" content="Quarkus Roq v999-SNAPSHOT" /> ### [Mastering Pagination in Roq](/posts/mastering-pagination-in-roq/) Adding pagination to your Roq site is an easy way to improve content navigation. Let’s walk through how to implement pagination and customize its behavior in your site. Step 1: Basic Pagination Setup First, include the following in your frontmatter on the page which will iterate on the paginated collection: layout: main paginate: posts Next, in your template, loop through the paginated posts using: {#for post in site.collections.posts.paginated(page.paginator)} <article class="post">...</article> {/for} Step 2: Adding Pagination Controls To add pagination controls, add something like this to partials/pagination.html and include it in your page {#include partials/pagination.html/}: {#include fm/pagination.html} {#newer}<i class="fa fa-long-arrow-left" aria-hidden="true"></i>{/newer} {#older}<i class="fa fa-long-arrow-right" aria-hidden="true"></i>{/older} {/include} You can further customize your pagination by setting the page size and link format: paginate: size: 4 collection: posts link: posts/page-:page With these steps, you can create a flexible pagination system to improve your site’s navigation. ### [How to add syntax highlighting to your Roq site](/posts/how-to-add-syntax-highlighting-to-your-roq-site/) Adding syntax highlighting to your Roq project has never been easier. Here’s a quick guide to help you integrate Highlight.js in your project with the help of the Quarkus web-bundler extension. Step 1: Add Highlight.js Dependency Next, add Highlight.js to your pom.xml like this: <dependency> <groupId>org.mvnpm</groupId> <artifactId>highlight.js</artifactId> <version>11.10.0</version> <scope>provided</scope> </dependency> This will make the Highlight.js library available to your project. Step 2: Initialize Highlight.js Roq is pre-configured with the Quarkus Web-Bundler to automatically bundle you Javascripts and Styles located in src/main/resource/web/app. The Roq default theme includes the {#bundle /} tag, if you are using your own templates, make sure it is present. Now, let’s configure Highlight.js. In your src/main/resources/web/app/main.js, import the library and activate it: import hljs from 'highlight.js'; import 'highlight.js/scss/default.scss'; hljs.highlightAll(); And that's it! Now your code blocks will be beautifully highlighted, adding a more polished and professional look to your content. This process is quick and effective, making it easy to provide clear, readable syntax highlighting for your users. Happy coding! ### [Easily manage Drafts and Future articles in Roq](/posts/easily-manage-drafts-and-future-articles-in-roq/) Roq just made content management easier with a cool new feature that lets you control drafts and future articles directly in your configuration. No more messing around with hard-to-track content—now you can manage everything through the Quarkus config: roq -Dsite.draft -Dsite.future This is using frontmatter data in articles and pages draft: true and date: 2024-09-19 10:45:00 +0200 to take the decision. By default, both options are set to false, meaning that drafts and future pages will stay hidden until you’re ready to reveal them. All you need to do is update these configs when you're ready to publish. This simple feature adds flexibility and control, making your publishing process more streamlined. Happy content managing! ### [Effortless URL Handling in Roq with Qute super-power](/posts/effortless-url-handling-in-roq-with-qute-super-power/) Managing URLs is now very easy! With our updated Qute-powered feature, you can now manage relative and absolute URLs with more flexibility, thanks to new methods for joining paths and handling absolute URLs. Let’s explore some examples. How to Use It: Relative URL Example (toString prints the relative url): <a class="post-thumbnail" href="{post.url}"> </a> Absolute URL Example: <a class="post-thumbnail" href="{post.url.absolute}"> </a> ** Smart URL:** <meta name="twitter:image:src" content="{page.image.absolute}" > There is a method in Page to retrieve the image url as a RoqUrl from the configured site images path. It is smart so that if the page image is external, it won't be affected. Under the Hood: The Power of RoqUrl At the core of this feature is the RoqUrl class that you can leverage from Qute, which makes joining and resolving URLs super easy. With this structure, joining paths is as simple as calling resolve(). This ensures your URLs are clean, predictable, and easy to manage—whether they’re relative or absolute. Wrapping Up: With Qute’s URL handling, you can now dynamically create and manage both relative and absolute URLs without any hassle. This new implementation will help keep your code clean while making it easier to navigate, link, and share content across your site. ### [Welcome to Roq!](/posts/welcome-to-roq/) Hello folks, A bunch of Quarkus contributors started this new initiative to allow Static Site Generation with Quarkus (similar to Hugo, Jekyll, Lume, ...). Quarkus already provides most of the pieces to create great web applications (https://quarkus.io/guides/web). And Roq adds the missing pieces: Roq Generator: allows to generate a static website out of any Quarkus application (it starts the app, fetch all the configured pages and assets, generate a static website and stop). Roq Data: allows to create json or yaml data file and consume them from your templates. It is also possible to map them to beans to get type-safe validation in bonus! Roq FrontMatter: allow to create pages and collections (posts, ...) using Markdown or Asciidoc with layouting. In fact, your static website content. What's missing? we now need to incrementally add the toolkit to ease the process of creating static content through Quarkus: SEO Image processing (quarkus-web-bundler/issues/42) Pagination (quarkus-roq/issues/65) Advanced routing (redirect, ...) To go further: Compat with tools like https://frontmatter.codes/ Compat with IDEs plugins Roq GitHub action Dev-UI integrated headless CMS (to edit md/asciidoc on the fs) With Roq you can develop the content using Quarkus dev-mode, and then generate (on CI) for Github Pages or similar when it's ready. Bonus, everything added will benefit any "non-static" Quarkus app and any static Quarkus app could also go back to being non static. This effort is now tracked using a "Focus Group" (temporary wording) project: https://github.com/orgs/quarkiverse/projects/6 This is a great opportunity to participate in a fun focus group and be involved with the Quarkus community, if anyone is interested in being a part of this, please reach out to me 🚀 There will be small, medium, bigger features to develop with any level of involvement. Participating could just be giving thoughts and discussing things.. Check out the Roq docs for more info on how to get the most out of Roq. File all bugs/feature requests at Roq’s GitHub repo. ## Pages ### [Markup Examples](/markups/) Markup Examples This section contains pages demonstrating the rendering of different markup languages in Roq. Available Examples AsciiDoc Example - AsciiDoc content types including headings, lists, tables, code blocks, admonitions, and more Markdown Example - Markdown content types including headings, lists, tables, code blocks, and more These pages are used for seeing theme styling and are excluded from search engines and sitemaps. ### [Oops! Roq is saying 404](/404.html) ### [About Roq](/about/) This tool is a testament to how extensible and powerful Quarkus is, offering a low-risk yet highly capable platform that will evolve as demand grows. Origins I wrote a blog post explaining how it all started. Credits Those are generated as a JSON by all-contributors, then we leverage roq-data to print them... slick 🏄! Thanks goes to these wonderful people: Andy Damevin author @ia3andy Matheus Cruz author @mcruzdev Melloware @melloware Max Rydahl Andersen @maxandersen Holly Cummins @holly-cummins Erik Jan de Wit @edewit Jérôme Tama author @jtama Rayza Luana @RayzaAnchayhua Martin Kouba @mkouba Foivos @zakkak Joel Takvorian @jotak Pablo Gutierrez @pablomxnl Pedro Hos @pedro-hos OKC JUG @okcjug Jason Lee @jasondlee João Nascimento @jotaNas janwesterkamp @janwesterkamp Clément de Tastes @CodeSimcoe Stéphane Philippart @philippart-s Patrik Duditš @pdudits Rolfe Dlugy-Hegwer @rolfedh Matheus André @matheusandre1 Sun S. D. Tan @sunix Matheus Oliveira @omatheusmesmo Dimitri Hautot @DimitriHautot ### [Roq Advanced Stuff](/docs/advanced/) If you find any issue or missing info, be awesome and edit this document to help others Roqers. Built-in features Roq and its themes include several built-in features for SEO, feeds, and discoverability. The base theme provides the essential tags (SEO, favicon, Web Bundler), while the default theme builds on top of it with a full layout, dark mode, sidebar, and more. If you are using either theme, most of these features are already enabled. Configure them through your site index frontmatter or by adding content files. For details on each feature, see the Base Theme, Favicon, SEO, Analytics, RSS, and LLMs.txt sections in the basics guide. Pagination Adding pagination to your Roq site is an easy way to improve content navigation. Let’s walk through how to implement pagination and customize its behavior in your site. Step 1: Iterate on the paginated collection First, include the following in your FrontMatter header on the page which will iterate on the paginated collection: paginate: posts Next, in your template, loop through the paginated posts using: {#for post in site.collections.posts.paginated(page.paginator)} (1) <article class="post"> ... </article> {/for} {#include partials/pagination.html/} 1 Calling .paginated(page.paginator) will resolve to the posts for the computed page. Step 2: Including Pagination Controls To add pagination controls, use the provided fm/pagination.html in your own partials/pagination.html: {#include fm/pagination.html} {#newer}<i class="fa fa-long-arrow-left" aria-hidden="true"></i>{/newer} {#older}<i class="fa fa-long-arrow-right" aria-hidden="true"></i>{/older} {/include} If you want to write your own controls, find inspiration in the FM sources fm/pagination.html. Just by doing so, Roq will generate a bunch of pages based on the pagination setting. For example with a pagination size of 4 and with 9 posts, you would get: index.html (posts 1 to 4) posts/page-2 (posts 5 to 8) posts/page-3 (post 9) the first page uses the declaring page link. You can further customize your pagination by setting the page size and link format: paginate: size: 4 collection: posts link: posts/page-:page With these steps, you can create a flexible pagination system to improve your site’s navigation. Themes Browse all available themes in the Plugins & Themes directory. Overriding theme In Roq, you can override theme partials or layouts. To override a theme partial, it is very simple, you just need to add the same template in your site. For example, adding your own templates/partials/roq-default/pagination.html will override the one from the default Roq theme To override a theme layout, you need to insert an extra layout layer. This allows you to override only specific sections of the theme layout, without duplicating the entire layout structure. Roq layouts leverage Qute include under the hood. It is possible to define insert sections that provide overridable default content. Example Let’s override the roq-default theme’s main layout so that our customizations apply everywhere it is used. templates/layouts/main.html --- theme-layout: main (1) --- {#insert /} (2) {#description} (3) Here I can override the description section {/} {#footer} <footer> And here the footer </footer> {/} 1 Inherits from the theme layout: theme-layout: main explicitly targets the theme’s main layout as a base. 2 Inheritance mechanism: {#insert /} ensures that this layout will inherit sections defined in the theme layout. 3 Override specific sections: You can override individual sections such as description and footer without affecting other parts of the layout. Now, everywhere layout: main is used (even in the theme), your override will be used. How it Works Internally Roq handles theme layouts in two layers: The original theme layouts are always kept under theme-layouts/…​. These are the base templates that overrides can extend for partial customization. Roq also produces corresponding site layouts for each theme layout. Site layouts are the versions that your pages actually reference. When Roq builds your site, it checks for overrides: If you provide an override: Roq uses your override as the site layout, while still keeping the theme’s original layout under theme-layouts/…​ for inheritance. If you don’t provide an override: Roq copies the theme layout as the site layout, so it can be used directly. This mechanism ensures you only need to override the parts you want to customize, everything else automatically falls back to the theme. Developing a theme To develop a theme, create a Maven module which will contain the theme layouts, partials, scripts and styles. . └── main ├── resources │ ├── application.properties │ └── templates │ ├── partials │ │ └── roq-default (1) │ │ ├── head.html │ │ ├── pagination.html │ │ ├── sidebar-about.html │ │ ├── sidebar-contact.html │ │ ├── sidebar-copyright.html │ │ └── sidebar-menu.html │ └── theme-layouts (2) │ └── roq-default │ ├── default.html │ ├── index.html │ ├── main.html │ ├── page.html │ ├── post.html │ └── tag.html └── web ├── roq.js ├── roq.scss 1 You can add partials for your theme, they need to be located in a directory with the theme name templates/partials/{theme-name}/. 2 Layouts need to be declared in theme-layouts/ using a directory with the theme name templates/theme-layouts/{theme-name}/. Same as for a site, scripts and styles can either be added to src/main/resources/META-INF/resources or bundled using Maven esbuild plugin: pom.xml <plugin> <groupId>io.mvnpm</groupId> <artifactId>esbuild-maven-plugin</artifactId> <version>0.0.2</version> <executions> <execution> <id>esbuild</id> <goals> <goal>esbuild</goal> </goals> </execution> </executions> <configuration> <entryPoint>roq.js</entryPoint> (1) </configuration> <dependencies> (2) <dependency> <groupId>org.mvnpm.at.fortawesome</groupId> <artifactId>fontawesome-free</artifactId> <version>6.6.0</version> </dependency> <dependency> <groupId>org.mvnpm.at.fontsource</groupId> <artifactId>pt-serif</artifactId> <version>5.1.0</version> </dependency> </dependencies> </plugin> 1 Add your esbuild entrypoint from src/main/resources/web 2 Add mvnpm or webjars dependencies This bundle will be available in /static/bundle/roq.js and /static/bundle/roq.css which can be used in your theme html <head> You need to create an application.properties: src/main/resources/application.properties site.theme=roq-default (1) 1 This allows site referencing the theme to default to this theme. Links & Urls The output location of pages and documents is determined by the FrontMatter link key. This link value can include placeholders, which will be dynamically replaced with relevant values for routing. Those links are also available in the Qute data to allow Creating links between your pages. Link placeholders Type of page Placeholder Description Example Output All :path The file path of the page, slugified (converted to a URL-friendly format) without the extension. my-page, search or docs/my-doc All :raw-path The raw file path of the page without the extension. My$, my car or été/2024 All :slug The slugified title of the page, derived from the title. Defaults to the slug property in data, if available or using the slugified title, falling back to the name. my-page-title All :Slug The case-preserving slugified title of the page, derived from the title. Defaults to the slug property in data, if available or using the slugified title, falling back to the name. My-Page-Title All :name The slugified name of the file (or directory if index). If the filename contains a date (e.g., '2025-08-21-My-Blog-Post.md'), the date portion will be stripped away. This behavior mimics that found in Jekyll builds, making any migrations simpler. my-blog-post All :Name The case-preserving slugified name of the file (or directory if index). If the filename contains a date (e.g., '2025-08-21-My-Blog-Post.md'), the date portion will be stripped away. This behavior mimics that found in Jekyll builds, making any migrations simpler. My-Blog-Post All :ext The file extension with the dot. Empty for all files with html output (md, asciidoc, html, …​). .json All :ext! Force the output file extension. .html, .json All :year The year of the page’s date or the current year if the date is not available. 2024 All :month The month (formatted as two digits) of the page’s date or the current month if the date is not available. 10 All :day The day (formatted as two digits) of the page’s date or the current day if the date is not available. 28 Document :collection Represents the collection to which the document belongs, such as a specific category or folder name. blog, articles, recipes Paginated :page Represents the current page. 1, 2 The slug derivation replaces all non-alphanumeric characters by - to make them url friendly. Default link value: for pages: /:path:ext. for documents: /:collection/:slug/. for paginated page: /:collection/page:page/. You can define link in a layout to affect all the pages using that layout. Creating links between your pages The pages links are automatically converted to urls by Roq, they are available in the site.url and the page.url variables. This makes creating links very easy: <a href="{site.url}">Back to main page</a> or to get the next page url in a document: <a href="{page.next.url}">{page.next.title}</a> or when iterating on documents: {#for post in site.collections.posts} <a href="{post.url}">{post.title}</a> {/for} or also to manually retrieve a page url with site.page(sourcePath): <a href="{site.page('foo.html').url}">{site.page('foo.html').title}</a> By default, url will be rendered as the path from the site root. You can also get the full absolute url (i.e. from http(s)://) by using absolute on any url (e.g. {site.url.absolute}). Manual linking Sometimes, you want to create a link for a page without holding the variable, in this case, you can use site.url(relativePath) which will be automatically resolved from the site root path. Alternative expression syntax Qute supports an alternative expression syntax where output expressions use {=expr} instead of {expr}. This makes templates safer when content contains curly braces (e.g. code samples, JSON) since only {=…​} and {#…​} are interpreted as Qute expressions, everything else is plain text. This will become the default syntax for Roq in a future version. To enable it, add to your configuration: quarkus.qute.alt-expr-syntax=true With this enabled, templates use {=page.title} for expressions and {#for …​} / {#include …​} for sections (sections are unaffected). Regular {foo} is treated as plain text. Escaping pages content There are cases where you might not want your page content to be parsed by Qute, to avoid conflicts with the content. You have different options: Configure it globally via site.escaped-pages (globs are allowed): config/application.properties site.escaped-pages=posts/escaped**,my-page.html Set it in FrontMatter by adding escape: true in your page data (not working with layouts). Escape inline content by wrapping the section with \{| and |\}, or by manually escaping Qute expressions using \{. Setting the Root Path for your site (base-path) When the entire Roq site is under a root path such as mysite.io/foo/, configure quarkus.http.root-path in the Quarkus configuration: config/application.properties quarkus.http.root-path=/foo Environment variable: QUARKUS_HTTP_ROOT_PATH For GitHub Pages, this is already detected and handled by the Roq GitHub Action, no need to do anything. Debugging To debug errors, you may print debug information in the logs: roq -Dquarkus.log.category.\"io.quarkiverse.roq.frontmatter\".level=DEBUG Testing All templates will be validated at generation. Sometimes, for example on Pull-Request, you want to detect issues before actual generation. Roq provides a way to generate the full site during the test phase. First, include the quarkus-roq-testing test dependency in your pom.xml. pom.xml <dependency> <groupId>io.quarkiverse.roq</groupId> <artifactId>quarkus-roq-testing</artifactId> <version>{cdi:project-info.release.current-version}</version> <scope>test</scope> </dependency> Test Site Generation Once you’ve added the dependency, you can easily ensure all pages are generated without errors: src/test/java/RoqSiteTest.java @QuarkusTest @RoqAndRoll public class RoqSiteTest { @Test public void testGen() { // All pages will be generated/validated during test setup } } That’s it! This basic test already verifies that your site generation is error-free. You can also add checks on the actual generated content as it is served using a static file server: src/test/java/RoqSiteTest.java @QuarkusTest @RoqAndRoll public class RoqSiteTest { @Test public void testIndex() { RestAssured.when().get("/") .then() .statusCode(200) .body(containsString( "Ready to Roq my world!" )); } } The RestAssured port will automatically use the Roq static test server, running on port 8082 by default. The Roq test server port could be modified by an annotation parameter like this @RoqAndRoll(port=9090). Using standard Quarkus test It’s possible to use the standard Quarkus test support (Testing Your Application) to check the content, but then pages will be rendered dynamically on demand at runtime: src/test/java/QuteWebSiteTest.java @QuarkusTest public class QuteWebSiteTest { @Test public void testIndex() { RestAssured.when().get("/") .then() .statusCode(200) .body(containsString( "Ready to Roq my world!" )); } } In this case the RestAssured port will automatically use the Quarkus dynamic test server, running on port 8081 by default. Updating Roq Make sure your Quarkus cli is up-to-date: $ curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force quarkus@quarkusio Then run the update command: $ quarkus update This will update the Quarkus version and extensions (including Roq) and make sure they are compatible together. The releases and migration info can be found here. Site Configuration Site configuration is done in config/application.properties (or src/main/resources/application.properties): In a multi-module Maven project, use src/main/resources/application.properties instead. The config/application.properties location is resolved relative to the JVM working directory, which may not match the module directory when building from the reactor root. Configuration property fixed at build time - All other configuration properties are overridable at runtime Configuration property Type Default site.url the base hostname & protocol for your site, e.g. http://example.com Environment variable: SITE_URL string site.route-order The order of the route which handles the templates. <p> By default, the route is executed before the default routes (static resources, etc.). Environment variable: SITE_ROUTE_ORDER int 1100 site.ignored-files Add new ignored files to the default list. The ignored files (relative to the site directory). Only the content/, public/, and static/ directories are scanned. Environment variable: SITE_IGNORED_FILES list of string site.default-ignored-files The default ignored files (relative to the site directory) include: All files or directories starting with an underscore (_) These patterns are additional to the scanner’s own OS-level defaults (e.g. .DS_Store, Thumbs.db, *~, .class). Environment variable: SITE_DEFAULT_IGNORED_FILES list of string **/_**, _** site.escaped-pages Pages whose content should be escaped— i.e., included in Qute rendering but not parsed for Qute expressions. This is based on the page’s relative path from the content directory. This applies only to pages (not layouts or partials). Supports glob expressions. Environment variable: SITE_ESCAPED_PAGES list of string site.page-layout The layout to use for normal html pages if not specified in FM. When empty, the page will not use a layout when it doesn’t specify it in FM. Resolves local layout first, then theme layout as fallback. Environment variable: SITE_PAGE_LAYOUT string page site.content-dir The directory which contains content (pages and collections) in the Roq site directory. Environment variable: SITE_CONTENT_DIR string content site.static-dir The directory (dir name) which contains static files to be served (with 'static/' prefix). Environment variable: SITE_STATIC_DIR string static site.public-dir The directory which contains public static files to be served without processing (dir name) Environment variable: SITE_PUBLIC_DIR string public site.images-path The path containing static images (in the public directory) Environment variable: SITE_IMAGES_PATH string images/ site.generator When enabled it will select all FrontMatter pages in Roq Generator Environment variable: SITE_GENERATOR boolean true site.future Show future documents Environment variable: SITE_FUTURE boolean false site.theme The theme name. Used to resolve theme layouts when using theme-layout: in front matter. With a theme, layout: foo resolves local first, then theme layout as fallback. Environment variable: SITE_THEME string roq-base site.draft Show draft pages Environment variable: SITE_DRAFT boolean false site.draft-directory Directory name used to mark collection documents as draft when frontmatter does not define attribute draft. Frontmatter draft takes precedence over this directory-based fallback. Environment variable: SITE_DRAFT_DIRECTORY string drafts site.date-format Format for dates Environment variable: SITE_DATE_FORMAT string yyyy-M-d[ HH:mm][:ss][ Z] site.time-zone The default timezone Environment variable: SITE_TIME_ZONE string document timezone if provided or system timezone site.default-locale The default language to use when no language is specified in the frontmatter. This language will be used as a fallback for articles that don’t have a 'locale' property. Environment variable: SITE_DEFAULT_LOCALE string en site.slugify-files Indicates whether file names in the public directory and files attached to pages should be slugified (converted to a URL-friendly format). When enabled, file names will automatically be transformed into a URL-safe format. Additionally, page.file and site.file references can use the original file names, as they will also be slugified during the process. Environment variable: SITE_SLUGIFY_FILES boolean true site.collections."collections-map" If this collection is enabled Environment variable: SITE_COLLECTIONS__COLLECTIONS_MAP_ boolean true site.collections."collections-map".future Show future documents (overrides global future for this collection) Environment variable: SITE_COLLECTIONS__COLLECTIONS_MAP__FUTURE boolean false site.collections."collections-map".hidden If true, the collection won’t be available on path but consumable as data. Environment variable: SITE_COLLECTIONS__COLLECTIONS_MAP__HIDDEN boolean false site.collections."collections-map".layout The layout to use if not specified in FM data. When empty, the document will not use a layout when it doesn’t specify it in FM. Resolves local layout first, then theme layout as fallback. Environment variable: SITE_COLLECTIONS__COLLECTIONS_MAP__LAYOUT string site.collections."collections-map".from-data.id-key The data attribute to use as the page identifier (slug). Environment variable: SITE_COLLECTIONS__COLLECTIONS_MAP__FROM_DATA_ID_KEY string required site.generated-templates-output-dir The directory where the generated templates should be created inside the output directory. Environment variable: SITE_GENERATED_TEMPLATES_OUTPUT_DIR string roq-templates site.path-prefix READ CAREFULLY: The root path of your site (e.g. /blog) should be set using quarkus.http.root-path. This path prefix should be relative to the Quarkus HTTP root path and is meant to be used only when the Roq site is served alongside a Quarkus application on a separate path. Environment variable: SITE_PATH_PREFIX string ### [Roq the basics](/docs/basics/) If you find any issue or missing info, be awesome and edit this document to help others Roqers. By default, your site files should be located in the project root directory (or in the Java resources dir: src/main/resources/). Directory Structure The default directory structure is: my-site/ ├── data/ (1) │ ├── menu.yml │ └── tags.yml │ ├── content/ (2) │ ├── posts/ (3) │ │ ├── 2024-10-14-roq-ssg/ │ │ │ ├── index.md │ │ │ └── image.jpg │ │ └── 2024-10-20-heart-roq.md │ │ │ ├── roq-page.md (4) │ └── index.html (5) │ ├── public/ (6) │ └── images/ │ └── logo.png │ ├── web/ (7) │ ├── app.js │ └── app.css │ ├── templates/ (8) │ ├── partials/ (9) │ │ ├── head.html │ │ └── pagination.html │ │ │ └── layouts/ (10) │ ├── base.html │ ├── page.html │ └── post.html ├── config/ │ └── application.properties (11) └── pom.xml (12) 1 Roq Data Files The data/ directory contains data files like menu.yml and tags.yml. These files can hold structured data used across the site. 2 Content Files The content/ directory is where all content of the site that will be generated as pages resides (.html, .md, .adoc*, .json, .xml, …​) 3 Collections The posts/ directory is the default collection in Roq, it is optional. It holds content files for blog posts or similar structured documents. You can configure multiples collections (recipes, events, …​). 4 Additional pages You may provide additional pages files like roq-page.md outside a collection. You can also use sub-directories which will be part of the resulting path. 5 Index File The index.html file is required and serves as the homepage. It provides site-wide data using FrontMatter. 6 Static Files The public/ directory holds static files such as images, PDFs, or other assets. These files are served as-is without processing. The default image directory is public/images/. 7 Web Bundler The web/ directory contains JavaScript and CSS source files bundled by the Quarkus Web Bundler (included by default with Roq). 8 Templates The templates/ directory is optional as templates can be provided by a theme. It contains Qute templates for partials and layouts. 9 Qute Partials The partials/ directory contains reusable Qute template fragments, such as head.html and pagination.html, which can be included in layouts. 10 Layouts The layouts/ directory defines the structure for pages and documents. For example: base.html is the main layout. page.html and post.html are specific layouts for pages and posts. 11 Configuration The config/application.properties file contains the site configuration such as collections, theme, and other settings. 12 Build files The build file such as a pom.xml is needed to configure the build. It contains dependencies for your site such as theme and plugins. Qute and FrontMatter All templates may use the awesome type-safe Qute template engine. Type-safety doesn’t make it more complex—it just means that using wrong variables will result in a build error. This prevents issues from leaking into production. Templates for layouts, documents, and pages may also declare a FrontMatter (FM) header, delimited by two ---. This header contains YAML data used to configure things like: Routing Data for templates Content generation Pagination For example, a page template blog-post.html might start with: --- title: "My First Blog Post" date: 2025-09-08 author: "Andy" layout: post tags: qute, roq, tutorial --- **Hello World** Content The content/ directory contains the site index page and all the Pages and Collections (such as blog posts). It may also contain attached static files (Page attached static files). Content templates can be written in html, json, yaml, yml, or xml or using Markup languages. We sometimes refer to pages in collections as documents, documents are just a special kind of pages. Site index Your site index page is required and should be located in content/index.html (you can also use a markup extension). content/index.html --- title: Hello Roqers (1) description: It is time to start Roqing 🎸! --- <h1>Hello fellow Roqers 🤘</h1> <p> With Roq, it is very easy to link to another <a href="{site.url('/roq-page')}">page</a>. (2) </p> 1 The index.html also describe your site information through a FrontMatter header. 2 We use the {site.url(path)} using Qute to manually resolve other pages urls. There are different ways to link your pages as explained in the Links & Urls section. Pages Any content template file without the _ prefix in the site content/ directory (and subdirectories) will be scanned as pages. Let’s create your first page and spice things up a bit by using Markdown (included by default with Roq). roq-bottom.md --- title: Roq Bottom description: When you hit Roq bottom, try Roq to climb back up! link: /climb-back-up (1) the-rope: You Roq! (2) --- # Roq Bottom If you thought you hit Roq Bottom, take this 🪢 because : __{page.data.the-rope}!__ (3) 1 you can use link to give this page a custom link (by default it will use the file-name). 2 you can add other FM data. 3 FM data is available through page.data. By default, pages use the page layout and documents in collections use the post layout (from the theme if using one). You can override this with layout: in the FrontMatter. Markup languages You can use different markup languages in Roq content. Markdown Roq ships with Markdown support out of the box (powered by commonmark-java). To write pages or documents in Markdown, simply use the .md or .markdown file extension. This plugin also allows converting Qute data that contains Markdown into HTML using the mdToHtml template extension. content/page.html --- bar: | ## Hello This is using **Markdown** --- {page.data.bar.mdToHtml} If you don’t need Markdown, you can disable it by excluding the Markdown plugin from the Roq extension in your pom.xml. AsciiDoc AsciiDoc is also fully supported in Roq via the AsciiDoc plugin. Once installed, to write pages or documents in AsciiDoc, simply use the .adoc or .asciidoc file extension. Collections Collections are a great way to group related content such as blog posts, recipes, member of a team or talks at a conference. Once created you can easily iterate and link to them. By default, Roq is configured with a posts collection using the content/posts directory. Let’s create our first post: content/posts/2024-10-14-roq-solid.md --- title: Roq bad puns description: Roq is very good for bad puns 🤭 tags: (1) - funny - ai img: 2024/10/roq-solid.jpg --- # {page.title} (2) Here is a list of puns suggested by Chat GPT: 1. Roq and Rule – A play on "rock and roll," implying dominance or success. 2. Between a Roq and a Hard Place – Classic pun meaning stuck in a difficult situation. 3. Roq Solid – Something that is extremely reliable or stable. 4. You Roq! – A compliment, suggesting someone is awesome or does something well. 5. Roq Bottom – Referring to the lowest possible point, often used metaphorically. 6. Roq the Boat – To cause trouble or disturb the status quo. 7. Roq Star – A person who excels or stands out in their field. 8. Let's Roq – Slang for getting started or doing something exciting. 9. Roq On! – An enthusiastic way to say "keep going" or "stay awesome." 10. Roqy Road – Could be literal (the type of road) or metaphorical for a difficult journey. 11. Roq of Ages – A historical reference, often implying something long-standing and unchanging. 12. Roq the Cradle – Can be literal or a pun about nurturing or starting something new. 13. Roqy Relationship – A tumultuous or unstable relationship. 14. Heavy as a Roq – Something burdensome or difficult to manage. 15. Stone Cold Roq – Referring to something very cool or emotionless. 1 You can define tags (see Tagging plugin to create pages for tags). 2 You have shortcut on the page to access title and description. Ok, to dive a bit deeper, we could create a json listing all posts with some info: content/posts.json [ {#for post in site.collections.posts} (1) { "title": "{post.title}", "url": "{post.url.absolute}", (2) "image": "{post.image.absolute}", (3) "date": "{post.date}", (4) "read-time": "{post.readTime}" (5) }{#if !post_isLast},{/if} {/for} ] 1 You can use site.collections.[collection id] to access the full list of documents (it is also possible to paginate). 2 post.url contains the post url (as a RoqUrl), absolute to get the absolute url. 3 post.image is smart and is already resolved to the image url (as a RoqUrl), absolute to get the absolute url. 4 post.date returns a ZonedDateTime and can be formatted the way you want. 5 post.readTime is a Qute template extension which compute the read time based on the post content. Draft and Future To create a draft page or document, you can use the frontmatter field draft: true. Drafts are hidden by default unless you set %dev.site.draft=true in your Quarkus configuration (the %dev makes it effective only in dev mode). You can also place draft documents (for collections) in a drafts/ (for example posts/drafts/) directory. Documents in that directory are treated as drafts only when their frontmatter does not define draft. If frontmatter explicitly sets draft, that value takes precedence. You may also start roq with the option: roq -Dsite.draft. By default, documents with a date in the future (FrontMatter data or file name) will not be visible unless you have %dev.site.future=true in your Quarkus configuration (the %dev makes it only available in dev-mode). You may also start roq with the option: roq -Dsite.future. It is possible to configure a collection to always show future documents: site.collections.events.future=true (1) 1 Always show future documents for the "events" collection. How to create custom collections? You can easily create your own collection, such as documentation, recipes, team members, or conference talks. To do this, simply create a new folder under the content directory. For example, if you’re adding docs, it would look like this: content/ ├── docs │ ├── 01-chap │ │ ├── image1.png │ │ └── index.adoc │ ├── 02-chap │ │ ├── image2.png │ │ ├── index.adoc └── posts └── 2025-01-02-my-first-blog └── index.md In this example, we have two collections: posts and docs. You need to define the new collection in the config/application.properties (or src/main/resources/application.properties) file. If you created your site with roq create, this file already exists with the posts collection configured: site.collections.docs=true (1) site.collections.docs.layout="page" (2) site.collections.docs.future=true (3) site.collections.posts=true site.collections.posts.layout="post" 1 We are adding the new collection docs; 2 Here, we set the layout for docs pages to page; 3 Since the new collection is not a time-based collection, we need to set future as true to show all files. Since we’re adding a new collection, it’s also necessary to declare the existing posts collection to ensure it continues to function correctly. Now, we can access all the new collection docs data as follows: {#for doc in site.collections.docs} - [{doc.title}]({doc.url}) {/for} Since the new collection is also a normal page, we can use all variables described in the variable section. Using a theme If you created your site with roq create, you already have a theme installed. A theme provides layouts, styles, and scripts for your site. Pages automatically use layouts from the theme (local layouts take priority if they exist). The default theme comes with a full blog layout, dark mode, sidebar, and SEO support. The base theme provides a minimal HTML structure with just SEO, favicon, and Web Bundler, giving you full control over the design. Browse all available themes in the Plugins & Themes directory. For advanced usage (overriding, developing), refer to the Themes section. To add a theme to an existing project (adds the dependency only, without initial site files): roq add theme:default Templates (Layouts, Partials, and User Tags) Layouts, partials, and user tags are templates and must use one of the following extensions: html, xhtml, htm, json, yaml, yml, or xml. INFO: .md and .adoc files are not parsed as templates. Instead, you can use markup inside templates through Qute sections {#md} and {#adoc}, provided the corresponding plugins are available. Layouts For your site, you will have one or more kind of pages, this is what we call "layouts", located by default in templates/layouts/. For example: main: the base layout for all kind of pages page: the layout of normal pages post: the layout for blog posts recipe: the layout for recipes or whatever A layout may be specified in pages through the layout FrontMatter key (e.g., layout: page). By default (if the content of the file is not a full HTML page — i.e., it does not contain a <html> tag or <!DOCTYPE declaration), posts will use the post layout and normal pages will use the page layout. This can be configured through site configuration. Roq layouts are using the Qute include section under the hood to achieve template inheritance. For more details, see the Qute documentation on includes: Qute includes. Unlike partials, layouts can also define Frontmatter data, which is inherited along with the template structure. If you’re not using a theme, you can create your own templates (example templates). How to create a layout page If you’re using a theme, you can take advantage of its layouts, but you’re also free to add your own. Layouts are built on a powerful inheritance system, allowing flexibility and customization. When using a theme, you can create new layouts that extend the existing theme layouts or partially override them to better suit your needs. Learn more here: Overriding Theme. In this sample we will create a simple 3 steps inheritance layout. All below files should be located in the templates/layouts/ directory. To do so, you will first need a default.html file as followed: default.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{page.title}</title> (1) </head> <body> {#insert /} (2) </body> </html> 1 Use the title page attribute that will be defined by the using page 2 Allows to insert arbitrary content from the page using the layout. Then you can create a main.html file as followed: main.html --- layout: default (1) title: And now for something completely different (2) --- <header> Head </header> {#insert /} <footer> Toes </footer> 1 Uses the default layout. 2 Defines a default title attribute value for all its children. Finally, you can create a content.html file as followed: content.html --- layout: main (1) --- {#include partials/image /} (2) knees 1 Uses the main layout. 2 Includes a partial template. Then it will be rendered as followed: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>And now for something completely different</title> </head> <body> <header> Head </header> <img src="https://supersimple.com/wp-content/uploads/head-shoulders-knees-and-toes-flashcards-726x1024.png" alt="Illustration" /> knees <footer> toes </footer> </body> </html> To summarize, each page will be rendered using their parent layout recursively. The inheritance system works for the page content as much as for the FrontMatter data. Partials You can split layouts into partial, reusable templates. Partials make it easier to maintain different sections of your layouts. By default, they are located in templates/partials/. For example: ➡️ templates/partials/pagination.html can be included using: {#include partials/pagination /} Tags Tags (User Tags) are custom reusable snippets of code, similar to small components. They help reduce duplication and let you create reusable sections. For example, create a tag in templates/partials/post-link.html: {@io.quarkiverse.roq.frontmatter.runtime.model.DocumentPage post} <div class="post-link"> <a href="{post.url}"> <img src="{post.image}" alt="{post.title}" class="post-image"/> <h3>{post.title}</h3> <p>{post.description}</p> </a> </div> You can then use it in another template like this : {#post-link post=site.document('posts/2025-09-08-my-article.md')/} This would render a styled card linking to the given DocumentPage post. You can reference pages and documents by their source path. For example: site.document('posts/2025-09-08-my-article.md') site.page('about.md') To learn more, see the Qute User Tags guide. Built-in features Favicon Roq automatically discovers favicon files from your public/ directory. Place any of the following files and they will be included in the HTML head: favicon.svg (preferred, scalable) favicon.ico (legacy fallback) favicon.png (PNG fallback) apple-touch-icon.png (iOS devices) To override auto-discovery, set icon or favicon in your site index frontmatter: icon: my-custom-icon.svg SEO Roq includes built-in SEO support with meta tags, Open Graph, and Twitter cards. The \{#seo page site /} tag is automatically included by the default theme. If you use a custom layout, add it to your HTML head: <head> {#seo page site /} </head> It will automatically generate <title>, <meta> author/description, Open Graph and Twitter card tags from the FrontMatter data. Configure SEO data through the site index frontmatter: Key Description author Default author name for meta tags (can be overridden per page) lang Default language/locale (e.g. en, fr) twitter Twitter/X handle for Twitter cards (e.g. quarkusio) Facebook Open Graph facebook: app_id: "123456789" publisher: "https://www.facebook.com/yourpage" admins: "your-fb-admin-id" Webmaster Verifications webmasterVerifications: google: "your-google-verification-code" bing: "your-bing-verification-code" yandex: "your-yandex-verification-code" Available keys: google, bing, alexa, yandex, baidu, facebook. Analytics To add Google Analytics 4, configure it in the site index frontmatter (used by the default theme): analytics: ga4: XXXXXXXXXX If you use a custom layout, add the \{#ga4 /} tag to your HTML head. RSS The \{#rss site /} tag is automatically included by the default theme. If you use a custom layout, add it to your HTML head: <head> {#rss site /} </head> Then create a content/rss.xml file with: {#include fm/rss.html /} Roq will generate a valid RSS feed from your blog posts FrontMatter data. By default, <content:encoded> contains the post description. Use the contentLimit parameter to include richer content: \{#include fm/rss.html contentLimit=0 /} (1) \{#include fm/rss.html contentLimit=150 /} (2) 1 Full rendered content 2 Content abstract limited to 150 words LLMs.txt Roq includes built-in support for generating /llms.txt and /llms-full.txt following the llms.txt specification. AI systems like ChatGPT, Claude, and Perplexity use these files to understand site structure and content. /llms.txt — A structured index containing the site title, summary, and a list of all pages with their titles and descriptions. /llms-full.txt — The same structure, with the full plain-text content of each page included. To enable llms.txt generation, create the following content files: content/llms.qute.txt: {#include fm/llms.html} content/llms-full.qute.txt: {#include fm/llms-full.html} To exclude a specific page, set llmstxt: false in its frontmatter. Loading Roq context in your AI assistant You can give your AI coding assistant full context about Roq by pointing it to https://iamroq.dev/llms.txt (or /llms-full.txt for complete content). This provides the project structure, quick start instructions, template syntax, and links to detailed skill files. Variables You can use Qute to access site and pages data. For this use the site and page variables: The site (javadoc) variable allow to access site global info from any page, document, layout or partial. Show attributes Variable Type Description Example site.url RoqUrl The Roq site URL http://example.com/my-roq-site/ site.data JsonObject The site FM data (declared in the index.html) {"title": "My Site", "description": "A description"} site.pages java.util.List<NormalPage> All the pages in this site (without the documents) [Page1, Page2, Page3] site.collections RoqCollections All the collections in this site (containing documents) {"collection1": Collection1, "collection2": Collection2} site.title String The site title My Site site.description String The site description A description site.image RoqUrl The cover image URL of the page with disk check http://example.com/static/images/site.png site.image(String relativePath) RoqUrl The image from the public images directory with disk check site.image(‘foo.jpg’) ⇒ http://example.com/images/foo.jpg site.file(String relativePath) RoqUrl The file from the public directory with disk check site.file(‘foo.pdf’) ⇒ http://example.com/foo.pdf site.url(String path, String…​ others) RoqUrl Shortcut for site.url.resolve(path) site.url("/about") ⇒ http://example.com/my-roq-site/about site.page(String sourcePath) Page Get a page or document page by source path (e.g. pages/first-page.html) site.page(‘foo.html’).url.absolute ⇒ http://example.com/the-foo-page The page (javadoc) variable is available in pages, documents, layouts, and partials. It contains the info for the page it is used from. Show attributes Variable Type Description Example page.url RoqUrl The URL to this page http://example.com/about page.source Origin The page source (file name, …​) page.data JsonObject The FM data of this page {"title": "About Us", "description": "This is the about us page."} page.paginator Paginator The paginator if any Paginator{currentPage=1, totalPages=5} page.collection String The collection id if this a document posts page.title String The title of the page (shortcut from FM) About Us page.description String The description of the page (shortcut from FM) This is the about us page. page.image RoqUrl The cover image URL of the page with disk check http://example.com/static/images/about.png page.image(String relativePath) RoqUrl The image from the attached files (for index pages) or from the public image directory with disk check (for other pages) page.image(‘foo.jpg’) ⇒ http://example.com/foo-page/foo.jpg page.file(String relativePath) RoqUrl The file from the attached files with disk check page.file(‘foo.pdf’) ⇒ http://example.com/foo-page/foo.pdf page.date ZonedDateTime The publication date of the page or null 2023-10-01T12:00:00Z Global data It is possible to declare global data as yaml or json in data/ directory. For example: data/foo.yml bar: Roq Can be accessed with {cdi:foo.bar} in any template. You can also have a structure (Java type mapping) for the data among other features, learn more. Template Extensions The Qute templating language supports a concept called template extension methods. These methods allow us to add functionality to types and expose it in our templates. Moving logic from the template to Java code gives us the ability to use a more robust language for more complex logic and makes the functionality more easily reusable, as well as keeping our templates clean: Qute provides built-in template extensions Roq has several built-in template extensions (javadoc): Usage in a Qute template Description text.numberOfWords Returns the number of words in the string text.wordLimit(limit) Returns the text limited to limit words, adds "…​" if truncated text.slugify Returns a slugified version of the text htmlContent.contentAbstract(limit) Returns the HTML content limited to limit words htmlContent.stripHtml Returns the text with all HTML tags removed page.readTime Returns the estimated reading time in minutes for the page content page.contentAbstract Returns the first 75 words of the page content page.contentAbstract(limit) Returns the page content limited to limit words list.randomise Returns the list in random order jsonArray.asJsonObjects Returns a list of JsonObject. All items must be JSON objects. collections.collection(key) Returns the collection for the given key posts.filter(key, value) Returns only documents matching the front-matter key/value posts.future Returns only documents dated in the future posts.past Returns only documents dated in the past posts.sortBy(key, reverse) Sorts documents by a front-matter key (string), optionally reversed posts.sortByDate(reverse) Sorts documents by date, optionally reversed field.asStrings Normalizes a front-matter field into a list of strings fileName.mimeType Returns the MIME type based on the file name extension You can provide your own template extensions by adding a class to your projects src/main/java directory and annotating either class or the public static method with @TemplateExtension: public class Extensions { @TemplateExtension public static String doSomething(String text) { // .... } } and then you can use that extension in your template: {site.pageContent(page).doSomething} For more details, see the Quarkus and Qute documentation. Site static files Site static files are served as-is without any additional processing. By default, all files in public/ are scanned as static files. public/ ├── images/image.jpg (1) ├── scripts/script (2).js (2) └── presentation.pdf (3) 1 generated as on /images/image.jpg 2 generated as /scripts/script-2.js(slugified 👇) 3 generated as /presentation.pdf Site static files url can be accessed through site.file('presentation.pdf') or site.file('scripts/script (2).js') or just their relative paths. site.file(path) also checks that the file exists on disk and will adapt on site configuration (e.g. root path change). To improve SEO, all static files are slugified, Roq replaces non-URL-friendly characters with -. URL-friendly characters are alphanumeric, -, and _ (multiple dots are also tolerated for files). Using site.file and page.file variables automatically applies this replacement on returned url (same for images). To disable this behavior, set site.slugify-files=false in Roq’s configuration. Page attached static files Pages may have attached static files (image, pdf, slides, …​). For this, instead of creating a file page, create a directory with an index page: content/my-page/ ├── image.jpg (1) ├── slide.pdf (1) └── index.md (2) 1 Every non page files in the directory will be attached to the page. 2 Use an index.(html,md,…​) for the page content; this also works in collections. In that case, those attached files will be served under the same path as the page and can be accessed via a relative link: [slide](./slide.pdf) The resulting link for a page can be different from its directory name, attached files will be relative to the resulting link. This way it works both in IDEs preview and in the browser. Let’s imagine for a minute that the page link is https://my-site.org/awesome-page/, then the slide will be served on https://my-site.org/awesome-page/slide.pdf. You can use {page.file("slide.pdf")} to resolve the file url and check that the file exists. This is also useful in other cases, for example from another page (e.g. {site.page("my-page/index.md").file("slide.pdf")}) or if you want the absolute url (e.g. {page.file("slide.pdf").absolute}): If you want to iterate over page files, they can be listed using {page.files}. Images This section explains how to access images in your site or in a specific page. Site images Site‑level images live in public/images/ (e.g. my-site/public/images/image-1.png). The default public path is images/ and can be customized in the site configuration. Use site.image() to generate the correct URL: <img src="{site.image('image-1.png')}" /> site.image(name) is equivalent to: <img src="{site.file('images/' + name)}" /> Page images When a page is a directory (for example posts/surf/index.html), the method {page.image(name)} checks if the image is attached to that page and returns its URL. For single‑file pages (posts/basketball.md), {page.image(name)} behaves like site.image(name) and resolves from public/images/. Example structure: my-site/ ├── content/ │ └── posts/ │ ├── basketball-article.md (1) │ └── surf-article/ │ ├── cover.jpg │ ├── surf.jpg (2) │ └── index.html └── public/ └── images/ (3) ├── basketball-cover.png ├── basketball.png └── football.jpg 1 Non-directory pages → page.image() == site.image(). 2 Page-attached file → accessible via {page.image('surf.jpg')}. 3 Site images → accessible everywhere via site.image(name). Usage example File: `surf-article/index.html` --- image: cover.jpg --- <h2>👍</h2> <img src="surf.jpg" /> <!-- 1 --> <img src="{page.image()}" /> <!-- 2 --> <img src="{page.image('surf.jpg')}" /> <!-- 3 --> <img src="{site.image('basketball.jpg')}" /> <!-- 4 --> <img src="{site.image('basketball.png').absolute}" /> <!-- 5 --> <h2>👎</h2> <img src="{site.image('surf.jpg')}" /> <!-- 6 --> <img src="{page.image('soccer.jpg')}" /> <!-- 6 --> <img src="{page.image('basketball.jpg')}" /> <!-- 6 --> Page & Site cover image Page cover image is referenced in the page FM image data. some-page.md --- image: my-page.png --- {page.image} The url can be accessed from this template (and its parent layouts) through {page.image}. index.html --- image: my-site.png --- It can be accessed in any template through {site.image}. Styles and Javascript Here are two options to consume scripts and styles: Add css and scripts in your site static directory, see Site static files section. Use the Quarkus Web Bundler to bundle your script and styles 👇. The Quarkus Web Bundler is included by default in Roq. To use bundling, add your scripts (js, ts) and styles (css, scss) in the web/ directory at the project root: my-site/ ├── web/ │ ├── app.js │ └── app.scss src/main/resources/web/app/ also works if you prefer the standard Java resources layout. To include the generated bundle in your template, specify the bundle tag in the html>head tag: layouts/head.html <head> ... {#bundle /} </head> It will be rendered with the relevant <script> and <style> tags to include your bundle. You may also consume and bundle npm dependencies among other cool things. For more info, read the Quarkus Web Bundler documentation. ### [Getting started](/docs/getting-started/) Install the Roq CLI with JBang and create your first site in seconds. Get up and running with Roq 1. Install the Roq CLI via JBang (installs JBang if needed): Linux/macOS Windows $ curl -Ls https://sh.jbang.dev | bash -s - trust add https://repo1.maven.org/maven2/io/quarkiverse/roq/ $ curl -Ls https://sh.jbang.dev | bash -s - app install --fresh --force roq@quarkiverse/quarkus-roq ✓ roq installed > iex "& { $(iwr https://ps.jbang.dev) } trust add https://repo1.maven.org/maven2/io/quarkiverse/roq/" > iex "& { $(iwr https://ps.jbang.dev) } app install --fresh --force roq@quarkiverse/quarkus-roq" ✓ roq installed 2. Create your site (you can change the name): Create $ roq create my-site Creating Roq site: my-site ✓ Roq site created in ./my-site This creates a site with the default theme (blog layout, dark mode, sidebar, SEO). To start from scratch with a minimal HTML structure and full control over the design, use the base theme instead: roq create my-site -x theme:base. Browse all available themes. 3. Start dev mode: Dev $ cd my-site $ roq start Listening on http://localhost:8080 ✓ Live-reload enabled Open localhost Roq the basics → ### [Migrating to Roq](/docs/migrating/) If you find any issue or missing info, be awesome and edit this document to help others Roqers. Roq uses Qute templates and a different content model than Jekyll, Hugo, or other static site generators. This guide covers the workflow, syntax mappings, and Roq-specific pitfalls for migrating an existing static site to Roq. Prerequisites Familiarity with Roq concepts (see the Getting Started guide) An existing static site you want to migrate (Jekyll, Hugo, or similar) The Roq CLI installed (see Getting Started) Java 21+ installed Using an LLM to accelerate migration An LLM (Large Language Model) such as Claude, ChatGPT, or a locally hosted model can accelerate the migration of your templates, layouts, and content files. Template conversion is mostly mechanical syntax mapping, which LLMs handle effectively. To give your LLM full context about Roq, point it to https://iamroq.dev/llms-full.txt. LLM-assisted migration is not fully automatic. Expect to review and adjust the output. The prompts in this guide are a starting point, refine them as you learn what works for your site. Overview of the migration process Migrating a static site to Roq involves converting four categories of files: Project scaffold — roq create, application.properties, and directory structure Layouts and templates — Liquid/Jinja/Go templates to Qute templates Content files — Markdown or AsciiDoc with front matter adjustments Static assets — JavaScript, SCSS/CSS, images, and data files Content files typically need minimal changes. Configuration and asset migration require more manual work. Roq expects content in a content/ directory by default (configurable via site.content-dir). Templates go in templates/layouts/, static files in public/, and data files in a configurable data directory. Recommended phased approach Do not attempt to migrate everything at once. Use a phased approach with validation gates: Phase Scope Gate A: Foundation Roq project + one page rendering correctly Stop if content does not render. Verify quarkus.qute.alt-expr-syntax=true is set so curly braces in code samples are treated as plain text. B: Styling + scale JavaScript, CSS/SCSS, all content pages Stop if build time exceeds 10 minutes or memory exceeds 4 GB C: Full site All templates, blog, homepage, static pages, redirects, CI/CD Production-ready Commit after each step. Prepare reference material Having concrete examples of working Roq templates makes migration smoother (whether you are converting manually or with an LLM). Collect these files from a working Roq project (the Roq blog is a good source): pom.xml — for Maven dependency structure config/application.properties — for Roq configuration patterns A sample Qute layout (for example, templates/layouts/default.html) A sample content page with front matter (for example, a .md or .adoc file from content/) If you are using an LLM, attach these files directly or paste them as code blocks. You can also point the LLM to https://iamroq.dev/llms-full.txt for complete Roq documentation. Create the project scaffold Before converting any templates, set up the project and validate that a single page renders. Create a new Roq project with the Roq CLI: roq create my-site This creates a project with the default theme (full blog layout, dark mode, sidebar, SEO support). If you want full control over the design and prefer to build your own layouts from scratch, use the base theme instead: roq create my-site -x theme:base The base theme provides a minimal HTML structure with just SEO, favicon, and Web Bundler. It is a better starting point if you plan to port your existing site’s design rather than adopt Roq’s default look. Add any plugins you need: roq add plugin:asciidoc # if using AsciiDoc content roq add plugin:sitemap roq add plugin:aliases # for URL redirects roq add plugin:tagging # if using tags LLM prompt for project setup I am migrating a static website from Jekyll to Roq (a Quarkus-based static site generator). I have already created the project with `roq create` and the base theme. Help me configure application.properties with: - site.url=https://mysite.example.com - site.collections.posts.layout=post - quarkus.qute.alt-expr-syntax=true - site.slugify-files=false - quarkus.default-locale=en Here is my Jekyll _config.yml for reference: [paste or attach _config.yml] Roq-specific configuration details Alternative expression syntax (recommended) Roq supports an alternative expression syntax where output expressions use {=expr} instead of {expr}. With alt syntax enabled, only {=...} and {#...} are interpreted as Qute expressions. Regular {...} is treated as plain text, so curly braces in code samples and JSON are safe without escaping. Add to your application.properties: quarkus.qute.alt-expr-syntax=true This will become the default syntax for Roq in a future version. All Qute examples in this guide use the alt syntax ({=expr} for output, {#...} for sections). Qute escaping (without alt syntax) If you choose not to enable the alternative expression syntax, Qute treats {...} as template expressions. Content with curly braces (Java code, JSON examples) must be escaped from Qute parsing. AsciiDoc files: Qute parsing is disabled by default (quarkus.asciidoc.qute=false). Curly braces in AsciiDoc content are safe without any extra configuration. To enable Qute parsing for a specific AsciiDoc file, add the :qute: attribute to the document header. Markdown and HTML files: Qute parsing is enabled by default. If your Markdown files contain curly braces in code samples, set site.escaped-pages in application.properties: site.escaped-pages=posts/** This wraps matched page content with Qute escape markers so curly braces are not parsed as template expressions. site.collections Defining any custom collection replaces Roq’s defaults. If you define site.collections.guides.layout=guide, you must also explicitly add site.collections.posts.layout=post — otherwise Roq’s default posts collection is silently dropped. quarkus.roq.data.dir Set this to _data to reuse Jekyll’s data directory in place, avoiding the need to move data files. site.slugify-files Set to false to preserve original filenames in URLs instead of slugifying them. Validate the scaffold (Phase A gate) Copy a single content page into content/ and start dev mode: roq start Verify: The page renders with your content (AsciiDoc or Markdown) Curly braces in code samples are treated as plain text (verify quarkus.qute.alt-expr-syntax=true is set) Content files without YAML front matter are recognized as collection members (Roq discovers content by directory, not by front matter presence) Files and directories starting with _ inside content/ (such as _includes/ or _attributes.adoc) are NOT rendered as standalone pages If you use AsciiDoc include:: directives, they resolve correctly AsciidoctorJ may enforce a security boundary (ROOTDIR) that prevents include:: directives from resolving paths outside the content directory. If includes fail with a security error, move the included files inside content/ or configure AsciidoctorJ’s safe mode. Do not proceed to templates until this gate passes. Convert layouts and templates Layouts are the highest-value conversion target. Jekyll uses Liquid templates; Hugo uses Go templates. Roq uses Qute, which has a different syntax but similar concepts. If you created your project with the default theme, it already provides main, page, and post layouts with a full blog design. You can override any theme layout by creating a file with the same name in templates/layouts/. If you used the base theme, you have a minimal HTML structure and will need to create your own layouts to match your existing site’s design. Key syntax differences (Jekyll Liquid to Qute) Concept Jekyll (Liquid) Roq (Qute) Variable output {{ page.title }} {=page.title} Conditional {% if page.image %}...{% endif %} {#if page.image}...{/if} Loop {% for post in site.posts %}...{% endfor %} {#for post in site.collections.get('posts')}...{/for} Include / partial {% include header.html %} {#include header.html /} Layout inheritance layout: default in front matter layout: default in front matter (same concept) Content insertion {{ content }} {#insert /} Date formatting {{ post.date | date: "%B %d, %Y" }} {=post.date.format('MMMM dd, yyyy')} Null / empty check {% if page.image %} {#if page.image} (Qute has different null semantics — test carefully) If you are migrating from Hugo rather than Jekyll, replace the Liquid syntax column with Go template equivalents ({{ .Title }}, {{ if .Params.image }}, {{ range .Pages }}, etc.) and include the Hugo equivalents in your prompt. The Qute (alt syntax) column stays the same. LLM prompt for layout conversion I am migrating a static website from Jekyll to Roq (a Quarkus-based static site generator that uses Qute templates). Convert the attached Jekyll Liquid layout to a Roq Qute template. Roq uses the alternative expression syntax: output expressions use {=expr} instead of {expr}. Section tags ({#if}, {#for}, {#include}) are unchanged. Key rules: - Replace Liquid {{ variable }} with Qute {=variable} syntax - Replace {% if %} with {#if } ... {/if} - Replace {% for item in collection %} with {#for item in collection} ... {/for} - Replace {{ content }} with {#insert /} - Replace {% include file.html %} with {#include file /} - Replace Liquid filters (| date, | upcase, etc.) with Qute method calls (e.g., {=post.date.format('yyyy, MMM dd')}) - Site-level variables use the `site` object (e.g., {=site.title}) - Page-level variables use the `page` object (e.g., {=page.title}) - Collections are accessed via site.collections.get('name') - Preserve all HTML structure and CSS classes unchanged - Qute null handling differs from Liquid: test conditionals carefully Here is my Jekyll layout: [paste or attach your layout file] Here is an example of a working Roq Qute layout for reference: [paste or attach a working Roq layout] Iterate on complex layouts Template porting is skilled translation work. Liquid and Qute differ in conditionals, loops, filters, null handling, and partial inclusion syntax. Budget extra time for complex templates like headers, footers, and sidebars. For layouts with many includes, navigation logic, or pagination: Convert the main layout first (usually default.html) Convert each include/partial file separately Convert pagination logic last (Roq pagination works differently from Jekyll) After each conversion, test in dev mode (roq start). Qute provides clear error messages with line numbers. Fix errors before moving to the next file. Convert content files Content files (blog posts, pages) usually need fewer changes than layouts. Content that works without changes Markdown files (.md) with YAML front matter work as-is in most cases AsciiDoc files (.adoc, .asciidoc) are supported natively by the quarkus-roq-plugin-asciidoc-jruby plugin AsciiDoc files without YAML front matter are recognized as collection members based on their directory — Roq discovers content by directory, not by front matter presence The layout field in front matter resolves automatically — writing layout: post is sufficient because Roq maps it to templates/layouts/post.html Front matter differences Field Jekyll Roq Layout layout: post layout: post (same — Roq resolves to templates/layouts/post.html) Date date: 2024-01-15 date: 2024-01-15 (same) Permalink permalink: /about/ Use file path or redirect_from for old URLs Categories categories: [blog, tech] Use tags or directory-based collections Excerpt excerpt: "…​" description: "…​" LLM prompt for content migration I am migrating content files from Jekyll to Roq. Convert the YAML front matter in these files to Roq format: - Keep `layout`, `title`, `date`, and `author` fields unchanged - Rename `excerpt` to `description` - Convert `permalink: /path/` to `redirect_from: [/path/]` (Roq uses the file path as the URL by default; redirect_from handles old URLs) - Remove `categories` (use directory structure or `tags` instead) - Keep the body content unchanged (Markdown and AsciiDoc work as-is) Here are my content files: [paste or attach files] For bulk content migration, write a script (or ask an LLM to generate one) that processes all files in a directory rather than converting files one at a time. Moving content directories When moving content from Jekyll directories to Roq’s content/ directory, use git mv instead of cp to preserve file history: git mv _posts content/posts If the target directory already exists, git mv moves the source directory into it (for example, content/posts/_posts/). Remove the target first if it was created during earlier testing. Migrate static assets JavaScript Copy JavaScript files to the public/ directory: mkdir -p public/js cp path/to/your/javascript/*.js public/js/ Add <script> tags to your root layout, or place JS/CSS sources in web/ to use the built-in Web Bundler (see Styles and Javascript). SCSS/CSS Jekyll processes Sass files automatically and supports Jekyll-specific features in SCSS entry points. With Roq, the quarkus-web-bundler extension (a transitive dependency of quarkus-roq) handles CSS/SCSS bundling. Watch for these Jekyll-specific patterns in your SCSS entry point: Jekyll front matter (a pair of --- lines at the top of .scss files) — remove it Liquid variables (for example, $baseurl: "{{ site.baseurl }}") — replace with hardcoded values @import paths may need updating for the new directory structure Place SCSS files in the web/ directory. The import hierarchy (@import partials referencing other partials) must be ported as a complete tree — do not split individual files. Images and other static files Copy images and other static files (fonts, favicons, etc.) to the public/ directory. Jekyll typically serves these from assets/ or directory-relative paths. In Roq, files in public/ are served at the site root. cp -r assets/images public/images Update any hardcoded image paths in templates and content to match the new location. Data files Set quarkus.roq.data.dir=_data in application.properties to reuse Jekyll’s data directory in place. Each YAML or JSON file in _data/ automatically registers as a named CDI bean accessible in Qute templates. For example, _data/books.yaml becomes accessible as {=cdi:books}, and nested fields via dot notation such as {=cdi:books.items}. The file format (YAML/JSON) stays the same. Only the access syntax in templates changes: replace Jekyll’s {{ site.data.books.items }} with Roq’s {=cdi:books.items}. Convert site configuration Site configuration does not map cleanly between generators. Key configuration mappings Jekyll (_config.yml) Roq (application.properties) title: My Site Set in a data file or template partial url / baseurl site.url=https://mysite.example.com permalink: /:categories/:title/ Roq uses file-path-based URLs by default plugins: [jekyll-sitemap] roq add plugin:sitemap collections: site.collections.<name>.layout=<layout> exclude: [vendor, node_modules] site.ignored-files=vendor/**,node_modules/** LLM prompt for configuration I am migrating from Jekyll to Roq. Convert my Jekyll _config.yml to Roq application.properties format. Key mappings: - url / baseurl → site.url in application.properties - permalink → Roq uses file-path-based URLs by default - plugins → Roq uses plugins (install with `roq add plugin:<name>`) - collections → site.collections.<name>.layout in application.properties - exclude → site.ignored-files Important Roq behaviors: - Defining ANY custom collection replaces ALL defaults (including posts) so always explicitly define site.collections.posts if you have blog posts - Set quarkus.roq.data.dir=_data to reuse Jekyll's data directory - Set quarkus.qute.alt-expr-syntax=true (uses {=expr} for output, plain {..} is not parsed) Here is my Jekyll _config.yml: [paste or attach _config.yml] Scale to all content (Phase B gate) After the foundation works with a single page, move all remaining content directories using git mv (as described in Convert content files) and measure performance: roq start -Djvm.args="-Xmx4g" Check: Build time: under 5 minutes is good, under 10 is acceptable, over 10 minutes is a signal to investigate Memory: should stay under 4 GB for most sites Spot-check 5-10 pages across different content types: verify includes, code samples, images, and cross-references If the build is too slow, try reducing the content to a subset during development (move extra files to a temporary directory outside content/) and build the full site only for production validation. Handle redirects Jekyll sites often have permalink-based URLs that differ from Roq’s file-path-based URLs. Use the quarkus-roq-plugin-aliases extension to set up redirects from old URLs to new ones. The plugin recognizes three equivalent front matter keys: redirect_from, redirect-from, and aliases. --- title: My Page redirect_from: - /old/permalink/path/ - /another/old/path/ --- For bulk redirect migration, write a script that reads your Jekyll _config.yml permalink patterns and generates redirect_from front matter for each content file. Tips General Commit after each step Frequent commits let you roll back if a conversion introduces issues. Test in dev mode after each change Run roq start after each conversion. Qute provides clear error messages with line numbers. When using an LLM Ask for explanations When the LLM converts a template, ask it to explain each change. This helps you learn Qute syntax and catch incorrect conversions. Provide error messages Paste the full error message from roq start back to the LLM. Qute error messages are specific enough for the LLM to diagnose. Batch similar files Group similar templates or content files and convert them together. The LLM produces more consistent output when it can see patterns across files. Start new conversations for each phase After 2-3 steps of implementation, build output and file contents fill the LLM context window. A fresh conversation with "Continue from Phase B" works better than pushing through a long session. Known limitations Liquid filters: Jekyll’s Liquid filters (for example, | date: "%B %d, %Y") do not have direct Qute equivalents. Qute uses method calls instead (for example, {=post.date.format('MMMM dd, yyyy')}). The LLM usually handles common filters, but verify date formats and edge cases. Jekyll plugins: Jekyll plugins cannot be reused in Roq, but Roq has its own plugin ecosystem covering common needs (sitemap, tagging, aliases, RSS, etc.). Check the Plugins & Themes directory and install with roq add plugin:<name>. SCSS processing: Jekyll processes Sass files automatically and supports Jekyll-specific front matter and Liquid variables in SCSS. With Roq, the web-bundler handles SCSS, but you must remove Jekyll-specific syntax from entry points and update import paths. The LLM can help with the syntax changes but not with debugging build tool differences. Data file access: Jekyll’s _data/ files are accessed as {{ site.data.filename.key }} in Liquid. In Roq, data files register as CDI beans and are accessed as {=cdi:filename.key} in Qute templates. The file format (YAML/JSON) stays the same. Build error strictness: Jekyll silently ignores missing includes. Roq and AsciidoctorJ may fail the entire build on a single broken include:: directive. Validate includes early when scaling to all content. AsciidoctorJ security boundaries: AsciidoctorJ may block include:: directives that resolve to paths outside the content directory. If you see security errors, move included files inside content/ or adjust the safe mode configuration. RSS feeds: Jekyll’s feed.xml uses Liquid syntax. Roq has built-in RSS support (see RSS). Create a content/rss.xml with {#include fm/rss.html} and add {#rss site /} to your layout’s <head>. Clean up Jekyll artifacts After migration is complete and validated, remove Jekyll-specific files: _config.yml (and any variant config files) _layouts/, _includes/ (top-level Jekyll directories) _sass/ (if ported to web/) _plugins/ Gemfile, Gemfile.lock, .bundle/, .ruby-version Any Jekyll serve scripts Keep files that Roq still uses: _data/ (if quarkus.roq.data.dir=_data is configured) What’s next Read the Roq the basics for the full feature set Browse the Plugins & Themes directory Check the Roq blog source for a complete working example If you develop migration scripts or improved prompts, consider contributing them back to the project (see issue #780) ### [Publishing a Roq Site](/docs/publishing/) If you find any issue or missing info, be awesome and edit this document to help others Roqers. Generating your Roq site This command: roq generate 🚀 The site will be generated in target/roq, use roq serve to serve it. Without the Roq CLI using Maven: QUARKUS_ROQ_GENERATOR_BATCH=true ./mvnw -B package quarkus:run Roq GitHub Action Roq provides a GitHub action to publish to GitHub pages or other services. To GitHub Pages Check if you already have the .github/workflows/deploy.yml file, if you don’t create it: .github/workflows/deploy.yml ## Deploy to GH-Pages for your Quarkus Roq site. name: Roq Site Deploy on: push: branches: [ main ] # Switch to the branch which should be deployed to GitHub Pages schedule: - cron: "0 5 * * *" # Runs every day at 05:00 UTC (10:30 AM IST) workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate Roq Site uses: quarkiverse/quarkus-roq@v1 with: github-token: ${{ secrets.GITHUB_TOKEN }} # Used to automatically get the GitHub Pages url deploy: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} permissions: pages: write # to deploy to Pages id-token: write # to verify the deployment originates from an appropriate source runs-on: ubuntu-latest needs: build steps: - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4 Then to enable GitHub Pages: Open your GitHub repository page Go to Settings→Page Pick: Source: GitHub Actions, that’s enough (no save button) It’s all good, restart your deploy workflow and enjoy! To other services .github/workflows/deploy-other.yml ## Deploy to another service for your Quarkus Roq site. name: Roq Site Deploy other on: push: branches: [ main ] # Switch to the branch which should be deployed to GitHub Pages workflow_dispatch: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Generate Roq Site uses: quarkiverse/quarkus-roq@v1 with: github-pages: false - name: Publishing blog uses: actions/upload-artifact@v4 with: name: site path: target/roq retention-days: 3 This will create a GitHub artifact named site that you can download from another job (or another workflow). For example, the PR Preview workflow of Roq publishes to Surge. Gitlab CI Add this file at the root of your Gitlab repository .gitlab-ci.yml stages: - build - deploy build_roq: # Look for appropriate maven docker images in https://hub.docker.com/_/maven/tags image: "maven:3.9.9-eclipse-temurin-23-alpine" stage: build # Generate the static site on merge request events and on the main branch script: - QUARKUS_ROQ_GENERATOR_BATCH=true mvn -B -q package quarkus:run rules: - if: '$CI_PIPELINE_SOURCE == "merge_request_event"' - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' artifacts: reports: junit: target/surefire-reports/*.xml paths: - target/roq - target/surefire-reports deploy_roq: image: alpine pages: true stage: deploy # For main branch take the artifacts from `build_roq` and deploy them. needs: - build_roq script: - cp -R target/roq public - echo "Quarkus Roq static site deployed to Gitlab Pages at $CI_PAGES_URL" rules: - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' artifacts: paths: - public If everything goes well the pipeline will deploy, the url of the deployment is found via these options: Console output of deploy_roq job. Clicking Deploy ⇒ Pages on the project sidebar Navigating to the url https://gitlab.example.com/user-or-organization/projectpath/project/pages Other CIs Using the command above should be easy to configure on any CI. if you created a configuration for a given CI which could help others, please share it here (or create an issue) 🙏 ### [Roq Release Notes](/docs/releases/) If you find any issue or missing info, be awesome and edit this document to help others Roqers. We aim to keep the API stable, but since Roq is still young, breaking changes may happen. The good news: almost all breakage will be caught during build or site generation tests. Want to follow Roq’s progress and update your project safely? You’re in the right place. Roq 2.1 ✏️ Built-in Block Editor: a powerful block editor right in your browser during dev mode, with live preview, front matter editing, and image management. No IDE needed to write your next post! 🎨 Simplified layout resolution: layout: page now resolves local layouts first, then falls back to the theme. No more :theme/ prefix needed 🎨 Default theme rewritten with TailwindCSS instead of SCSS for better maintainability and modern styling 🌙 Built-in dark mode with automatic system preference detection 🎨 Color palette system: three customizable palettes (accent, pop, neutral) via CSS variables 🖼️ Favicon auto-discovery: automatically detects favicon.svg, favicon.ico, favicon.png, apple-touch-icon.png in public/ 🛒 Marketplace: new collection type for discovering plugins, themes, and web extensions 🤖 llms.txt: automatic generation of llms.txt for AI-friendly site indexing 🖥️ CLI: new roq add command for adding plugins, themes, and web extensions 🔧 Internal refactoring: the frontmatter pipeline is now split into clear numbered steps (Step0-Step6) for better maintainability 🔧 Migrated to ProjectScanner API and StringPaths library for file scanning ⚠️ page.date now returns null for normal pages without a date. Collection documents (posts) still default to the current date. 🔧 Common RoqException: all Roq exceptions (roq-frontmatter, roq-data) now extend a common io.quarkiverse.roq.exception.RoqException in roq-common, providing structured error pages with title, detail, hint, and source info across all modules → Guide for migrating to 2.1 Roq 2.0 🕵️ Added lightning filesystem watcher for live reload 📂 Allow web directory at the root of the Roq site 🧩 Simplified default app structure: supports web/app.js and web/app.scss (or web/app/app.js like before …​) ⚡️ TailwindCSS support without any config 💫 Directory support for data and allow iterating on nested data files using the directory name → Guide for migrating to 2.0 Roq 1.8 Sorry for the breaking releases back to back but this includes a refactor to allow safely including files from the whole site directory when using AsciidocJ (requested by a user). This mostly change internal api, but can eventually break really specific usage. → Guide for migrating to 1.8 Roq 1.7 The Asciidoc support was already available, but with this new release, we made it a Roq top level citizen: Support for Asciidoc headers to control the Roq data Includes Roq page and site attributes (urls, …​) xref are working out of the box for structured content such as docs Fine grained Asciidoc attributes (config, layout, page) Harmonization between Ruby and Java implementation Dynamic TOC support 👉 The Roq Asciidoc plugin doc A few weeks ago, we added support for search as a plugin to Roq. I wasn’t fully happy with the style and the fact that it was targetting the full page instead of the nearest fragment for the actual keyword. I spend a bit of time on this and came up with a new way of indexing the content which slice the content based on fragments. Currently, it supports both Asciidoc and Markdown output. Give it a try, it is enabled on this site. If you want this for your site: 👉 The Roq Search plugin doc → Guide for migrating to 1.7 Migration guide Make sure you update using Quarkus CLI Make sure you implemented generation tests to 2.1 Applies to Before After Action All users io.quarkiverse.roq.util.PathUtils io.quarkiverse.tools.stringpaths.StringPaths ⚠ Update import and adapt usage All users layout: :theme/foo layout: foo or theme-layout: foo ⚠ Update layout references in front matter All users Layouts in templates/layouts/{theme-name}/ templates/layouts/ ⚠ Move custom layouts All users page.date returns current date for all pages Returns null for non-collection pages ⚠ Wrap with {#if page.date}…​{/if} Theme users index.html layout for blog listing New blog.html layout (with pagination support); index.html now delegates to it ⚠ If using layout: blog without pagination (paginate: false), add paginate: posts; if you have a custom blog.html override, use {#if page.paginator and page.paginator.isFirst} instead of {#if page.paginator.isFirst} Theme users SCSS (app.scss) CSS with TailwindCSS ⚠ Migrate custom styles Theme users {#author-card …​} (kebab-case) {#roq/authorCard …​} (namespaced camelCase) ⚠ Update tag references Plugin authors RoqFrontMatterScanProcessor Step-based build items ⚠ Update plugin code Plugin authors deployment.scan.\* deployment.items.scan.* (same for data, publish) ⚠ Update imports All users Generated templates in target/roq-templates/full/ Now in target/roq-templates/content/ (#861) ℹ Update scripts or workflows referencing this path Plugin authors TemplateSource.generatedQuteContentTemplateId(), RoqFrontMatterRawPageBuildItem.generatedContentTemplate() Removed, page content now extracted via {#fragment RoqPageContent} (#861) ⚠ Update plugin code Plugin authors PAGINATE_KEY in scan package RoqFrontMatterKeys (runtime) ⚠ Update imports Plugin authors io.quarkiverse.roq.frontmatter.runtime.exception.RoqException io.quarkiverse.roq.exception.RoqException (in roq-common) ⚠ Update imports Plugin authors RoqException.Builder.source(TemplateSource) RoqException.Builder.sourceInfo(new RoqSourceInfo(…​)) ⚠ Update builder calls Plugin authors roq-data exceptions extend RuntimeException / UncheckedIOException All extend RoqException with builder pattern ⚠ Update exception construction Theme users Custom SCSS/CSS overrides Theme CSS completely rewritten ⚠ Review your overrides — some may be unnecessary now, others may need updating Theme users Custom color variables Three customizable color palettes: accent, pop, neutral ℹ See Color Palettes Theme users Custom CSS classes for prose not-prose class to exclude from prose styling ℹ Good to know Theme users No dark mode Built-in with dark: variants ℹ Good to know to 2.0 Applies to Before After Action All users Nested data mapped with _ (e.g. dir_bar) Mapped with / (e.g. dir/bar) ⚠ Update data references to 1.8 Applies to Before After Action All users page.info() page.source() and page.source().template() ⚠ Update page info calls Plugin authors Previous BuildItems API Restructured BuildItems ⚠ Update plugin code to 1.7 Applies to Before After Action AsciiDoc users Qute parsing enabled by default Disabled by default ⚠ Use :qute: per page or quarkus.asciidoc.qute=false AsciiDoc users quarkus.asciidoctorj quarkus.asciidoc ⚠ Rename config AsciiDoc users quarkus.asciidoctorj.templates-dir Removed (TOC handled by script) ⚠ Remove config Search users Previous search result DOM Updated DOM structure ⚠ Verify custom search styles All users site.ignored-files replaces defaults Now extends site.default-ignored-files ⚠ Check ignore config ### [Roq Events](/events/) 26 May 2026 Static You Can Maintain. Static With a Live CMS… What Is the Missing Roq? Andy Damevin talks about Quarkus Roq at JNation 2026. 09 Jul 2025 Roq: Create your static site with superpowers – fun, powerful, and easy to maintain! Andy Damevin talks about Quarkus Roq at Riviera Dev. 09 Dec 2025 Roq 2.0 Roq 2.0 release featuring enhanced capabilities and improved developer experience. Learn more 11 Nov 2024 Quarkus Insight - What is Quarkus Roq? Andy Damevin, Matheus Cruz and Melloware join us to discuss Quarkus Roq, which includes tooling for generating a static website with Quarkus. Learn more 31 Oct 2024 Roq 1.0 Roq 1.0 is out, it's time to Roq with blogs! Learn more 20 Oct 2024 Roq 1.0 Beta You can start building your site or blog with Roq. More features will come to cover all the needs you can expect from an awesome SSG! ### [Plugins & Themes](/marketplace/) ### [AsciiDoc Markup Example](/markups/asciidoc/) This is a paragraph under heading 1. It contains strong text, emphasized text, and inline code. Heading 2 This is a paragraph under heading 2 with a link to example.com. Heading 3 This is a paragraph under heading 3. Heading 4 This is a paragraph under heading 4. Heading 5 This is a paragraph under heading 5. Heading 6 This is a paragraph under heading 6. Blockquotes This is a blockquote. It can span multiple lines. It can even have multiple paragraphs. Strong and Emphasis This paragraph contains bold/strong text, italic/emphasized text, and bold and italic text. Code Inline Code This paragraph contains inline code within regular text. Code Blocks public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } function greet(name) { return `Hello, ${name}!`; } console.log(greet("World")); Code Blocks with Callouts public class Example { public static void main(String[] args) { String message = "Hello"; (1) System.out.println(message); (2) } } 1 Initialize the message variable 2 Print the message to console server: port: 8080 (1) host: localhost (2) database: url: jdbc:postgresql://localhost:5432/mydb (3) username: admin 1 Configure server port 2 Set server host 3 Database connection URL Lists Unordered Lists First item Second item Third item Nested item 1 Nested item 2 Fourth item Ordered Lists First step Second step Third step Nested step 1 Nested step 2 Fourth step Tables Header 1 Header 2 Header 3 Cell 1 Cell 2 Cell 3 Cell 4 Cell 5 Cell 6 Cell 7 Cell 8 Cell 9 Cell 10 Cell 11 Cell 12 Table with Alignment Left Aligned Center Aligned Right Aligned Left Center Right Left Center Right Horizontal Rule Paragraphs This is a standard paragraph with regular text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. This is another paragraph. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Links Here is an inline link and here is a link with title. Mixed Content Here’s a paragraph with strong text, emphasized text, inline code, and a link all in one. And here’s a blockquote that contains strong text, emphasized text, and inline code as well. Complex List First item with strong text Second item with inline code Third item with a link Nested unordered item Another nested item with emphasis Fourth item Code in Other Elements Code in Headings: inline-code This heading has inline code: variable = value Code in Lists Item with inline code Item with code block: def hello(): print("Hello") Code in Blockquotes This blockquote contains inline code and shows how code is styled within quotes. AsciiDoc-Specific Elements Admonition Blocks This is a note admonition. It provides additional information. This is a tip admonition. It offers helpful advice. This is an important admonition. Pay attention to this. This is a warning admonition. Be careful about this. This is a caution admonition. Proceed with care. Verse Block This is a verse block. It preserves line breaks and formatting exactly as written. — Attribution Source Example Block This is an example block. It’s used to highlight examples or demonstrate concepts. It can contain multiple paragraphs and other elements. Sidebar Block Optional Title This is a sidebar. It contains supplementary information that’s related but not essential to the main content. Definition Lists Term 1 Definition 1 Term 2 Definition 2 Term 3 Definition 3 With additional paragraph. Checklist Checked item Another checked item Unchecked item Another unchecked item Special List Styles Circle item 1 Circle item 2 Square item 1 Square item 2 Code Listing with Language fn main() { println!("Hello, world!"); } Complex Table Name Description Status Feature 1 This is a longer description of feature 1 ✓ Feature 2 This is a longer description of feature 2 ✓ Feature 3 This is a longer description of feature 3 Pending ### [Markdown Markup Test](/markups/markdown/) Heading 1 This is a paragraph under heading 1. It contains strong text, emphasized text, and inline code. Heading 2 This is a paragraph under heading 2 with a link to example.com. Heading 3 This is a paragraph under heading 3. Heading 4 This is a paragraph under heading 4. Heading 5 This is a paragraph under heading 5. Heading 6 This is a paragraph under heading 6. Blockquotes This is a blockquote. It can span multiple lines. It can even have multiple paragraphs. Strong and Emphasis This paragraph contains bold/strong text, italic/emphasized text, and bold and italic text. Code Inline Code This paragraph contains inline code within regular text. Code Blocks public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } function greet(name) { return `Hello, ${name}!`; } console.log(greet("World")); Lists Unordered Lists First item Second item Third item Nested item 1 Nested item 2 Fourth item Ordered Lists First step Second step Third step Nested step 1 Nested step 2 Fourth step Tables Header 1 Header 2 Header 3 Cell 1 Cell 2 Cell 3 Cell 4 Cell 5 Cell 6 Cell 7 Cell 8 Cell 9 Cell 10 Cell 11 Cell 12 Table with Alignment Left Aligned Center Aligned Right Aligned Left Center Right Left Center Right Horizontal Rule Paragraphs This is a standard paragraph with regular text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. This is another paragraph. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Links Here is an inline link and here is a link with title. Mixed Content Here's a paragraph with strong text, emphasized text, inline code, and a link all in one. And here's a blockquote that contains strong text, emphasized text, and inline code as well. Complex List First item with strong text Second item with inline code Third item with a link Nested unordered item Another nested item with emphasis Fourth item Code in Other Elements Code in Headings: inline-code This heading has inline code: variable = value Code in Lists Item with inline code Item with code block: def hello(): print("Hello") Code in Blockquotes This blockquote contains inline code and shows how code is styled within quotes. ### [🎸 The Roqers Hall Of Fame](/roqers/) const giscusScript = document.createElement('script'); giscusScript.src = 'https://giscus.app/client.js'; giscusScript.setAttribute('data-repo', 'quarkiverse/quarkus-roq'); giscusScript.setAttribute('data-repo-id', 'R_kgDOL4WdMA'); giscusScript.setAttribute('data-category', 'Comments'); giscusScript.setAttribute('data-category-id', 'DIC_kwDOL4WdMM4CjtXB'); giscusScript.setAttribute('data-mapping', 'pathname'); giscusScript.setAttribute('data-strict', '0'); giscusScript.setAttribute('data-reactions-enabled', '1'); giscusScript.setAttribute('data-emit-metadata', '0'); giscusScript.setAttribute('data-input-position', 'bottom'); giscusScript.setAttribute('data-theme', document.documentElement.classList.contains('dark') ? 'dark' : 'light'); giscusScript.setAttribute('data-lang', 'en'); giscusScript.setAttribute('crossorigin', 'anonymous'); giscusScript.async = true; document.currentScript.parentNode.insertBefore(giscusScript, document.currentScript.nextSibling); ### [Blog](/blog/) ### [Blog](/posts/page2/) ### [Blog](/posts/page3/) ### [#features](/posts/tag/features/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #features - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × features GFM Alert Blocks: Styled Callouts in Your Markdown Roq supports GitHub Flavored Markdown alert blocks with icons and themed colors. Learn how to use NOTE, TIP, IMPORTANT, WARNING, and CAUTION blocks, and how to add custom alert types. 2026, Apr 08 — 4 minute(s) read ### [#styling](/posts/tag/styling/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #styling - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × styling How to add syntax highlighting to your Roq site Learn how to integrate syntax highlighting into your Roq site using Highlight.js and the Quarkus web-bundler extension. This guide walks you through the simple steps to add it via the pom.xml, JavaScript, and SCSS files. 2024, Sep 20 — 2 minute(s) read ### [#plugin](/posts/tag/plugin/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #plugin - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × plugin More diagram than you could have dreamed of. Leveraging Kroki.io to generate diagram from text 2025, Jun 11 — 1 minute(s) read 🔎 Your users deserve searching capabilities! No third party service needed 🚀 2025, Apr 04 — 2 minute(s) read Easily Generate a `sitemap.xml` for Your Site with Roq Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin. 2025, Jan 08 — 1 minute(s) read Do you want to publish a blog post series ? Make your blog posts part of a series. 2024, Dec 06 — 2 minute(s) read Need a QR Code? Add a QR Code to your Roq website. 2024, Nov 14 — 1 minute(s) read Page 1 of 2 ### [#plugin](/posts/tag/plugin/page2/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #plugin - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × plugin Write your blog posts in AsciiDoc Automatically generate html from AsciiDoc content 2024, Oct 22 — 1 minute(s) read RSS Feed of your blog posts Automatically generate an RSS feed of your blog links. 2024, Oct 10 — 26 minute(s) read The second Roq plugin is for redirecting your page to a better place! We introduced a way to declare aliases in FrontMatter. It is now easy create redirections to your blog posts! 2024, Oct 09 — 1 minute(s) read The first Roq plugin is for tagging (with pagination) We introduced the first Roq plugin, it is for collection tagging & with pagination support! 2024, Oct 08 — 1 minute(s) read Page 2 of 2 ### [#blogging](/posts/tag/blogging/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #blogging - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × blogging Roq 2.0 and Java Advent Calendar article An introduction to Roq 2.0, a Quarkus-inspired approach to static site generation in Java. Learn about its new foundation, plugin support, and live-reload feature through a practical tutorial. 2025, Dec 09 — 2 minute(s) read Major site migrations to Roq ✨ Two prominent websites have just migrated to Roq—any guesses who they might be? 2025, Aug 26 — 2 minute(s) read Comparing Roq with Hugo, Jekyll, and JBake: A Feature Breakdown Here’s a feature comparison with some popular SSGs to highlight how Roq stacks up. Feature Roq Hugo Jekyll JBake Performance Fast, and leveraging Quarkus dev-mode Extremely fast (written in Go) Slower due to Ruby and plugins Slower, runs on Java with Freemarker/Groovy templates Templating Qute (simple & readable) Go templates (powerful but complex) Liquid (easy but limited) Freemarker, Groovy, or Thymeleaf Extensibility Leverages Quarkus extensions Limited plugin system Large plugin ecosystem Limited... 2025, Feb 27 — 2 minute(s) read Roq with Blogs 🚀 Roq 1.0 is ON! It is time to give it a shot and give us feedback 🚀 2024, Oct 31 — 2 minute(s) read Welcome to Roq! This is the first article ever made with Quarkus Roq 2024, Aug 29 — 2 minute(s) read ### [#happy-users](/posts/tag/happy-users/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #happy-users - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × happy-users Already some happy users 🧑‍💻 This is a good start, we already have a few happy users! 2024, Dec 10 — 2 minute(s) read ### [#markdown](/posts/tag/markdown/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #markdown - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × markdown GFM Alert Blocks: Styled Callouts in Your Markdown Roq supports GitHub Flavored Markdown alert blocks with icons and themed colors. Learn how to use NOTE, TIP, IMPORTANT, WARNING, and CAUTION blocks, and how to add custom alert types. 2026, Apr 08 — 4 minute(s) read ### [#frontmatter](/posts/tag/frontmatter/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #frontmatter - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × frontmatter Easily Generate a `sitemap.xml` for Your Site with Roq Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin. 2025, Jan 08 — 1 minute(s) read ### [#cool-stuff](/posts/tag/cool-stuff/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #cool-stuff - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × cool-stuff Set It in Roq: The Editor that change the game! Roq introduces a TipTap-powered editor with Markdown support, transforming it from a static site generator into a lightweight, developer-friendly CMS. Create, edit, and preview content seamlessly within the Quarkus dev experience. 2026, Feb 01 — 2 minute(s) read Roq 2.0 and Java Advent Calendar article An introduction to Roq 2.0, a Quarkus-inspired approach to static site generation in Java. Learn about its new foundation, plugin support, and live-reload feature through a practical tutorial. 2025, Dec 09 — 2 minute(s) read Major site migrations to Roq ✨ Two prominent websites have just migrated to Roq—any guesses who they might be? 2025, Aug 26 — 2 minute(s) read Roq n Roll Your Tests 🎶 Testing the actual Roq generation has never been this cool! 🎸 2025, Jan 28 — 2 minute(s) read Easily Generate a `sitemap.xml` for Your Site with Roq Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin. 2025, Jan 08 — 1 minute(s) read Page 1 of 3 ### [#cool-stuff](/posts/tag/cool-stuff/page2/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #cool-stuff - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × cool-stuff Static attached files for posts and pages This Christmas, I’m Roq-ing a cool new feature (inspired by Hugo 😅): it is possible to attach static files to posts and pages. They will be served relative to the page. 🎁🤩 2024, Dec 26 — 1 minute(s) read Do you want to publish a blog post series ? Make your blog posts part of a series. 2024, Dec 06 — 2 minute(s) read Need a QR Code? Add a QR Code to your Roq website. 2024, Nov 14 — 1 minute(s) read The second Roq plugin is for redirecting your page to a better place! We introduced a way to declare aliases in FrontMatter. It is now easy create redirections to your blog posts! 2024, Oct 09 — 1 minute(s) read The first Roq plugin is for tagging (with pagination) We introduced the first Roq plugin, it is for collection tagging & with pagination support! 2024, Oct 08 — 1 minute(s) read Page 2 of 3 ### [#cool-stuff](/posts/tag/cool-stuff/page3/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #cool-stuff - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × cool-stuff Out of the box awesome SEO Learn how to implement SEO in Roq in a blink of an eye. 2024, Sep 23 — 3 minute(s) read How to add syntax highlighting to your Roq site Learn how to integrate syntax highlighting into your Roq site using Highlight.js and the Quarkus web-bundler extension. This guide walks you through the simple steps to add it via the pom.xml, JavaScript, and SCSS files. 2024, Sep 20 — 2 minute(s) read Effortless URL Handling in Roq with Qute super-power Effortlessly manage both relative and absolute URLs with our enhanced Qute-powered feature. Utilizing the RoqUrl class, you can easily join and resolve paths, ensuring clean and predictable URLs. This update simplifies URL handling, making your code more efficient and your content easier to navigate and share. 2024, Sep 16 — 2 minute(s) read Page 3 of 3 ### [#seo](/posts/tag/seo/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #seo - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × seo Out of the box awesome SEO Learn how to implement SEO in Roq in a blink of an eye. 2024, Sep 23 — 3 minute(s) read ### [#guide](/posts/tag/guide/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #guide - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × guide Set It in Roq: The Editor that change the game! Roq introduces a TipTap-powered editor with Markdown support, transforming it from a static site generator into a lightweight, developer-friendly CMS. Create, edit, and preview content seamlessly within the Quarkus dev experience. 2026, Feb 01 — 2 minute(s) read More diagram than you could have dreamed of. Leveraging Kroki.io to generate diagram from text 2025, Jun 11 — 1 minute(s) read 🔎 Your users deserve searching capabilities! No third party service needed 🚀 2025, Apr 04 — 2 minute(s) read No pain updates with Roq One of the most overlooked aspects when choosing a Static Site Generator (SSG) is how easy it is to keep your project up to date. Many developers have struggled with complex upgrade processes, dependency conflicts, and breaking changes when using traditional SSGs like Jekyll or Hugo. 2025, Mar 24 — 1 minute(s) read Easily Generate a `sitemap.xml` for Your Site with Roq Learn how to quickly set up and customize a sitemap.xml for your site using the Roq plugin. 2025, Jan 08 — 1 minute(s) read Page 1 of 4 ### [#guide](/posts/tag/guide/page2/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #guide - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × guide Static attached files for posts and pages This Christmas, I’m Roq-ing a cool new feature (inspired by Hugo 😅): it is possible to attach static files to posts and pages. They will be served relative to the page. 🎁🤩 2024, Dec 26 — 1 minute(s) read Do you want to publish a blog post series ? Make your blog posts part of a series. 2024, Dec 06 — 2 minute(s) read Need a QR Code? Add a QR Code to your Roq website. 2024, Nov 14 — 1 minute(s) read Write your blog posts in AsciiDoc Automatically generate html from AsciiDoc content 2024, Oct 22 — 1 minute(s) read RSS Feed of your blog posts Automatically generate an RSS feed of your blog links. 2024, Oct 10 — 26 minute(s) read Page 2 of 4 ### [#guide](/posts/tag/guide/page3/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #guide - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × guide The second Roq plugin is for redirecting your page to a better place! We introduced a way to declare aliases in FrontMatter. It is now easy create redirections to your blog posts! 2024, Oct 09 — 1 minute(s) read The first Roq plugin is for tagging (with pagination) We introduced the first Roq plugin, it is for collection tagging & with pagination support! 2024, Oct 08 — 1 minute(s) read Out of the box awesome SEO Learn how to implement SEO in Roq in a blink of an eye. 2024, Sep 23 — 3 minute(s) read Mastering Pagination in Roq Learn how to implement pagination in Roq to enhance your content navigation. This article walks through the process of adding pagination, configuring page size, and customizing links. 2024, Sep 20 — 1 minute(s) read How to add syntax highlighting to your Roq site Learn how to integrate syntax highlighting into your Roq site using Highlight.js and the Quarkus web-bundler extension. This guide walks you through the simple steps to add it via the pom.xml, JavaScript, and SCSS files. 2024, Sep 20 — 2 minute(s) read Page 3 of 4 ### [#guide](/posts/tag/guide/page4/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #guide - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × guide Easily manage Drafts and Future articles in Roq Roq SSG introduces a new feature that allows you to hide or show draft and future articles using simple Quarkus configurations. This update gives developers greater control over which content is visible, improving content management and workflow. 2024, Sep 19 — 1 minute(s) read Effortless URL Handling in Roq with Qute super-power Effortlessly manage both relative and absolute URLs with our enhanced Qute-powered feature. Utilizing the RoqUrl class, you can easily join and resolve paths, ensuring clean and predictable URLs. This update simplifies URL handling, making your code more efficient and your content easier to navigate and share. 2024, Sep 16 — 2 minute(s) read Page 4 of 4 ### [#gfm](/posts/tag/gfm/) const savedTheme = localStorage.getItem('darkMode'); const isDark = savedTheme !== null ? savedTheme === 'true' : window.matchMedia('(prefers-color-scheme: dark)').matches; if (isDark) { document.documentElement.classList.add('dark'); } #gfm - Hello, world! I'm Roq — a funny little SSG (Static Site Generator) with a Java soul and Quarkus energy — Open Source and Free. setupSearch({ url: '/search-index.json' }); I am ROQ Java Static Site Generator 2.1.1 Search... ⌘K MENU Home Blog Events About Roqers Doc Getting Started Roq the Basics Plugins & Themes Publishing Advanced stuff Migrating LLMs.txt Social 2026 © ROQ × gfm GFM Alert Blocks: Styled Callouts in Your Markdown Roq supports GitHub Flavored Markdown alert blocks with icons and themed colors. Learn how to use NOTE, TIP, IMPORTANT, WARNING, and CAUTION blocks, and how to add custom alert types. 2026, Apr 08 — 4 minute(s) read