Skip to content

Add interactive R and Python code cells using WebR and Pyodide#292

Open
jeroenjanssens wants to merge 53 commits into
mainfrom
hugo-live
Open

Add interactive R and Python code cells using WebR and Pyodide#292
jeroenjanssens wants to merge 53 commits into
mainfrom
hugo-live

Conversation

@jeroenjanssens

@jeroenjanssens jeroenjanssens commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Adds the quarto-live v0.2.0 runtime (webR + Pyodide + CodeMirror editor) as static assets
  • Adds {{< pyodide >}} and {{< webr >}} shortcodes for interactive, editable code cells that run entirely in the browser
  • Runtime is auto-injected only on pages that use the shortcodes; packages can be specified inline via packages="..."
  • Adds "Try it" examples to the plotnine, ggplot2, gt, and great-tables software pages
  • Makes sure the interactive examples in the webR blog posts work.

Usage

{{</* pyodide packages="numpy" */>}}
import numpy as np
print(np.arange(10))
{{</* /pyodide */>}}

{{</* webr packages="ggplot2" */>}}
library(ggplot2)
ggplot(mpg, aes(displ, hwy)) + geom_point()
{{</* /webr */>}}

Vendor the three runtime assets from the quarto-live extension
(r-wasm/quarto-live tag v0.2.0):
- live-runtime.js: bundled ES module with CodeMirror, webR, and Pyodide
- pyodide-worker.js: Web Worker for non-blocking Python execution
- live-runtime.css: editor/output/loading UI styles
Implement Hugo shortcodes and orchestration layer for browser-based
R (webR) and Python (Pyodide) code execution, replacing Quarto's
OJS reactive runtime with a standalone init script.

New files:
- layouts/shortcodes/pyodide.html, webr.html: code cell shortcodes
- layouts/shortcodes/live-setup.html: optional config override
- static/js/live-init.js: orchestration (runtime init, editor wiring)
- static/css/live-compat.css: Bootstrap utility fallbacks for Tailwind

The runtime is auto-injected via extended_footer.html when pyodide/webr
cells are detected in page content. Packages can be specified per-cell
via a packages="" attribute, via front matter, or via the live-setup
shortcode. Base packages (ipython, evaluate, etc.) are always included.

Includes a monkey-patch for PyodideEvaluator.evaluate() to resolve
Comlink proxy values before they reach the rendering layer.
- plotnine: Pyodide cell with scatter plot using mtcars data
- ggplot2: webR cell with scatter plot using mpg data
- gt: webR cell creating a formatted table from exibble
- great-tables: Pyodide cell creating a formatted table from exibble
@netlify

netlify Bot commented Jun 4, 2026

Copy link
Copy Markdown

Deploy Preview for posit-open-source canceled.

Name Link
🔨 Latest commit 7480339
🔍 Latest deploy log https://app.netlify.com/projects/posit-open-source/deploys/6a29ed0f7779f100094d1a2d

@jeroenjanssens jeroenjanssens changed the title Add interactive R/Python code cells via quarto-live Add interactive R and Python code cells using WebR and Pyodide Jun 4, 2026
@github-actions

github-actions Bot commented Jun 4, 2026

Copy link
Copy Markdown

jeroenjanssens and others added 20 commits June 4, 2026 10:52
- live-setup: redundant since the footer auto-injects config and
  packages can be specified via the shortcode packages="" attribute
- webr-init/webr-editor: legacy no-ops from ported blog posts that
  never had a real implementation

Remove the shortcode references from the 4 affected blog posts.
Simplify the footer partial by dropping the hasSetup guard.
Replace the removed webr-init/webr-editor shortcode references with
working {{< webr >}} shortcodes containing the original example code.
Also remove leftover empty <div class="highlight"> blocks.
The monospace font family argument causes issues in the webR
canvas device; use the default font instead.
Relocate the webR/Pyodide loading status from a global fixed-position
indicator in the bottom-right corner to inline status within each code
editor's card header, positioned before the Run Code button.

Benefits:
- Contextual placement: status appears next to the button it affects
- No viewport obstruction: removes fixed-position overlay
- Per-editor status: each code block shows its own loading state

Implementation:
- Remove global #exercise-loading-indicator from extended_footer.html
- Refactor live-init.js to inject status elements into card headers
- Status format: "Downloading: [package-name] [spinner]"
- Track status by engine type (pyodide/webr) with updateStatus/hideStatus
- Insert before Run Code button so button position stays fixed

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Fix UX issues with the inline loading indicator:

- Hide the built-in .exercise-editor-eval-indicator spinner since we now
  show our own loading status with spinner in the card header
- Add margin-left: auto to button container to keep Run Code button
  anchored to the right side when loading indicator appears/disappears
- Hide "Downloading:" prefix when showing error messages so error text
  stands alone in red

Result: Single spinner, stable button position, cleaner error display.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace Bootstrap default colors with Posit brand palette using CSS
custom properties from main.css (Tailwind-based design system).

Changes:
- Primary button: Posit blue (#447099) instead of Bootstrap blue
- Card header: Light blue background (#f8fafb) matching Posit palette
- Card border/shadow: Posit gray tones with brand shadow style
- Outline buttons: Posit gray with subtle hover states
- Alert colors: Updated info alerts to use Posit blue

Uses var(--color-blue-500) syntax to reference Tailwind/Posit color
system while maintaining fallbacks for compatibility.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Update card and card-header borders to use Posit blue-100 (#e8edf2)
for a softer, more cohesive look with the blue-50 header background.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Override header bottom border and gutter right border to use Posit
blue-100 (#e8edf2) for consistent border styling throughout the card.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Use blue-200 (#d1dbe5) for the card's outer border for better contrast
while keeping internal borders at blue-100.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Make 'R Code' / 'Python Code' title medium weight (500) for better
visual hierarchy in the card header.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change gap from gap-3 (0.75rem) to gap-6 (1.5rem) for better spacing
in the card header left side.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…r, and shiny pages

Each page gets a "Try it" section with a concise, editable code cell:
- dplyr: filter/mutate/group_by/summarise pipeline on starwars
- tidyr: pivot_longer reshaping quarterly sales data
- purrr: map_dbl computing means over a named list
- glue: string interpolation with expressions and glue_collapse
- tibble: tibble() and tribble() construction with nice printing
- stringr: str_subset, str_extract, str_replace on fruit/sentences
- shiny-r: UI DSL building a fluidPage layout (webR)
- shiny-python: UI DSL building a page_fluid layout (Pyodide)
Show a centered "Running code..." spinner in the output area while code
executes, with smooth transitions:
- Reserve 80px min-height during execution
- Fade in the loading indicator
- Transition content below smoothly down/up
- Replace loader with output when ready

Also set all buttons to use Open Sans font family to match site design.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Instead of fixed min-height, measure actual content height and animate
between states:
1. Grow from 0 to loader height (80px)
2. Grow from loader height to actual output height
3. Return to auto height after transition

This eliminates jumpiness and provides smooth expansion regardless of
output size.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Listen for Start Over button clicks and smoothly collapse the output
area back to 0 height before clearing content. This provides visual
continuity when resetting the code editor.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Issues fixed:
- Add isCollapsing flag to prevent race conditions
- Capture starting height before animating (handles existing output)
- Clear height style after collapse completes
- Prevent Run Code execution during collapse

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Intercept Start Over clicks in capture phase to animate collapse before
the editor clears output. Use allowStartOver flag to let the click
through after animation completes.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Keep container at 0 height through Start Over click, then reset styles
after editor has cleared content. This prevents the jump down and back up.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Only animate Start Over collapse if there's actual visible output
(children.length > 0 AND offsetHeight > 0). This prevents unnecessary
shifting when the editor hasn't been run yet.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
gregswinehart and others added 28 commits June 4, 2026 12:13
Lock height, minHeight, padding, and margin all to 0 when Start Over
is clicked with no output, preventing any layout shifts.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Apply the same comprehensive dimension locking (height, minHeight,
padding, margin) after collapse animation completes, before triggering
Start Over. This prevents the bump at the end of the transition.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add explicit reflow (outputContainer.offsetHeight) after setting
starting height to ensure the browser registers the initial state
before animating to loader height.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Reduce gap from 1.5rem (gap-6) to 1rem (gap-4) for tighter spacing
between 'R Code' title and Start Over button.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Replace opacity: 0.75 with explicit gray-400 color for better contrast
and clearer loading status text.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The tribble(~col, ...) syntax produces + characters in base64
which Hugo's minifier escapes as &#43;, breaking the JSON payload.
Replaced with a simpler tibble() example.
Remove the Start Over button from the code editor header.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Remove the vertical border between line numbers and code, right-align
the line numbers, and add equal padding (0.75rem) on left and right.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Set cm-gutter.cm-foldGutter to 0 width to eliminate the gap between
line numbers and code.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Set text-align: right on .cm-gutterElement to right-align line numbers.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- ggplot2: faceted diamond price scatter with color brewer palette
- gt: air quality table with conditional coloring and formatting
- great-tables: population pivot table with compact numbers and data color
Add equal left/right padding of 0.375rem to line number elements.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change left/right padding from 0.375rem to 0.5rem (8px).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change code editor font size from 1rem to 0.875rem (14px).

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Force font-size on cm-gutterElement, cm-content, and cm-line to
0.875rem (14px) to override live-runtime defaults.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change padding-top/bottom from 4px to 0.75rem (12px) for more breathing
room in the code editor.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Change padding from 0.75rem to 0.5rem (8px) for tighter spacing.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Prevent border-top from appearing when code editor is focused.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add px-4 sm:px-6 lg:px-8 padding to center content containers,
matching the blog post layout. This properly centers software pages
and other single pages.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add mx-auto to the main flex container to center content on software
detail pages, matching the layout pattern used on blog posts.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

Blog YAML Checks

content/blog/ported/tidyverse/2023/webr-0-1-0/index.md

  • ⚠️ image-alt is required but missing.
  • ⚠️ software is missing. Use folder names from content/software/.

content/blog/ported/tidyverse/2023/webr-0-2-0/index.md

  • ⚠️ image-alt is required but missing.
  • ⚠️ software is missing. Use folder names from content/software/.

content/blog/ported/tidyverse/2024/webr-0-3-1/index.md

  • ⚠️ image-alt is required but missing.
  • ⚠️ software is missing. Use folder names from content/software/.

content/blog/ported/tidyverse/2024/webr-0-4-2/index.md

  • ⚠️ image-alt is required but missing.
  • ⚠️ software is missing. Use folder names from content/software/.

Summary: 4 files checked, 8 warnings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants