commits
New blog posts (monopam-madness, open-source-and-ai, weeknotes-2026-10),
notebook showcase with card layout and screenshots, Atom feed generator,
foundations notebook fixes, ONNX test improvements, widget interaction
tests, deploy script updates for oxcaml switch, and .gitignore for
build artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Interactive mode was incorrectly set to read-only, preventing users
from typing in code cells. Interactive cells should be editable with
ephemeral changes (lost on refresh), unlike Exercise cells which
persist edits to localStorage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add index.mld files for all packages that were missing them, which
caused odoc to generate default pages titled "<package> index". Also
fix leaf item indentation by always adding a spacer span regardless
of the node kind.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add cppo preprocessing for merlin-js and x-ocaml workers to support
conditional compilation with OXCAML flag
- Guard day10 packages with enabled_if >= 5.3.0 since they need recent OCaml
- Remove fatal odoc warnings from dune-workspace (handled per-package now)
- Bump merlin-js dune lang to 3.17
- Add warning suppression flags where needed (-w -58, -w -67)
- Add interactive extension exercise pages (FOCS 2020/2024/2025, OxCaml
stack allocation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add managed widget protocol (display_managed, command, register_adapter)
for external widget adapters like Leaflet maps
- Extract Leaflet map adapter into separate js_top_worker-widget-leaflet
library, loadable via #require
- Add widget rendering to x-ocaml web component (widget_render.ml) so
widgets work in .mld documentation pages
- Wire widget callbacks through OCaml client (js_top_worker_client_msg.ml)
- Complete the preloaded list in findlibish.ml to match all transitive
worker dependencies, preventing "file already exists" errors when
#require loads packages already compiled into the worker
- Add demo_widgets.mld and demo_map.mld documentation pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three features for x-ocaml interactive cells:
1. Worker busy indicator + stop/reset: When a cell is running (e.g. infinite
loop), the run button transforms into a spinning stop button. Clicking it
terminates the web worker, creates a fresh one, replays init messages, and
resets all cells to Not_run. Both builtin and jtw worker backends support
reset.
2. localStorage persistence: Exercise cells with data-id save their source
to localStorage (debounced 300ms). On reload, saved source is restored.
A small Reset button (bottom-left) appears when saved state exists,
allowing revert to the original HTML source.
3. Colab-style circular run/stop button: Replaces the old boxy text button
with a filled circle + white play triangle (CSS mask + ::after pseudo-
element). Running state shows a spinning arc with red accent and stop
square. Test cells get collapsible details with pass/fail/error indicators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
backend_name used read_meta before it was defined. Move it after
read_meta and add fallback to <meta name="x-ocaml-backend"> for when
x-ocaml.js is loaded via a plain <script src> (Js_url) without custom
attributes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The inline script loader hardcoded ./_x-ocaml/x-ocaml.js relative to the
page, but support files live under odoc.support/ at the doc root. Switch
to Js_url which odoc resolves against support_uri (like odoc.css). The
backend config is now communicated via a <meta> tag instead of a script
attribute.
Also: add x-ocaml dependency on merlin-js, add odoc-interactive-extension
dependency on x-ocaml, and remove unused js_top_worker-rpc.message dep.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Install x_ocaml.bc.js into the opam share directory and register it as
an odoc support file so that `odoc support-files -o DIR` copies
_x-ocaml/x-ocaml.js automatically, removing the need for manual
deployment in deploy.sh.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findlibish.mli: use Js_top_worker.Impl.dynamic_cmis (RPC module removed)
- worker.ml: use Impl.dcs_url instead of Toplevel_api_gen.dcs_url
- x-ocaml/src/jtw_client: convert to cppo for OxCaml-only
ppx_template_generated field in Query_protocol.Compl
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a findlib_index.json contains a "compiler" field with version
and content_hash, x-ocaml now constructs the worker URL automatically.
This means .mld files only need @x-ocaml.universe — no separate
@x-ocaml.worker tag is required. The explicit x-ocaml-worker meta
tag still takes priority when present.
Uses a synchronous XHR pre-fetch of the findlib_index.json (~200 bytes)
before creating the worker, with browser JSON.parse for extraction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable loading .cma.js files from a different origin (e.g., ocaml.org)
by working around Chrome's CORB which blocks cross-origin importScripts
for files with embedded binary CMI data.
worker.ml: detect cross-origin URLs in import_scripts and use
synchronous XHR + eval() instead of importScripts. Same-origin
URLs continue to use the standard path.
jtw_client.ml: create blob: URL wrapper for cross-origin worker.js
(browsers block cross-origin Worker construction), derive stdlib_dcs
URL from findlib_index base, switch to eval_stream for streaming
phrase-by-phrase output.
interactive_extension.ml: always load x-ocaml.js and worker.js from
local _x-ocaml/ path (same-origin), communicate universe URL via
<meta> tag. Set backend to "jtw" when a universe is configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --copy-file flag to jtw opam/opam-all for including x-ocaml.js
and other assets in universe output
- Pass findlib_requires and findlib_index from meta tags through to
the JTW worker init, so @x-ocaml.requires packages are loaded
during setup
- x_ocaml.ml reads <meta name="x-ocaml-packages"> and
<meta name="x-ocaml-universe"> before creating the backend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Add_cmis to X_protocol.request so pages can register external
package CMIs with the merlin worker. Page.create reads
<meta name="x-ocaml-packages" content="pkg1,pkg2,..."> and optional
<meta name="x-ocaml-cmis-url" content="./cmis/"> from the document
head. For each package, dynamic CMIs are registered so merlin can
provide completions, type-on-hover, and error checking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract page-level orchestration into a new Page module, separating
cell registry, test linking, message routing, and auto-run from the
WebComponent definition in x_ocaml.ml.
Key changes:
- Page module: cell registry, test linking (positional + data-for),
backend message routing, universe discovery stub, format config
- Cell: add ?merlin param, set_on_completed hook, has_completed,
string_of_mode, cell_for/cell_env accessors
- Editor: improved docstrings
- x_ocaml.ml: simplified to thin WebComponent + Page delegation
- Playwright browser tests: 17 assertions across 7 test scenarios
covering hidden/interactive/exercise/test modes, read-only state,
default mode, merlin disable, and full assessment chain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prepare for merlin-js to be a top-level monopam subtree instead of
a vendored submodule inside x-ocaml.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mode type and data attributes (data-id, data-for, data-env) to cells
- Hidden cells: no editor/UI, still execute in linked list chain
- Exercise cells: editable (default CodeMirror behaviour)
- Interactive/Test cells: read-only via EditorState.readOnly facet
- Read mode attribute from <x-ocaml mode="..."> elements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
# FEATURE.md
# x-ocaml/src/jtw_client.ml
Read data-filename attribute from x-ocaml elements. Store in cell
record and Merlin_ext context. Pass through Protocol.action to both
builtin and jtw backends for correct .mli handling.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add string option filename parameter to Complete_prefix, Type_enclosing,
and All_errors action variants. Thread through builtin worker config and
merlin_client query functions. When provided, Merlin uses the filename
extension to determine .ml vs .mli syntax.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace Js_top_worker_client_fut (old RPC/IDL layer) with
Js_top_worker_client_msg (JSON message protocol). This removes the
dependency on rpclib, ppx_deriving_rpc, and toplevel_api_gen types
from the x-ocaml frontend.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer architecture separating content, theme, and renderer:
Phase 1 — Scrollycode refactor:
- Strip ~1030 lines of embedded theme CSS from scrollycode_extension.ml
- Create scrollycode_css.ml with structural CSS using CSS custom properties
- Create scrollycode_themes.ml with three theme files (warm/dark/notebook)
registered as support files
- Simplify @scrolly tag: theme suffix now ignored (CSS concern, not content)
- Playground overlay styled via --xo-* custom properties on x-ocaml element
Phase 2 — Extra CSS support:
- Add --extra-css flag to odoc html-generate for injecting additional
<link> tags (used for per-page theme selection)
Phase 3 — Shell plugin system:
- Add Html_shell module with Shell interface and hashtable registry
- Register "default" shell in html_page.ml, "json" shell in
html_fragment_json.ml
- Replace hardcoded if/else in generator.ml with shell registry lookup
- Add --shell NAME flag (--as-json kept as backward-compat alias)
x-ocaml theming:
- Replace hardcoded colors in style.css with var(--xo-*, fallback)
covering editor, gutter, buttons, tooltips, and output areas
- CSS custom properties inherit through shadow DOM boundary, so
consumers theme x-ocaml with pure CSS — no JS injection needed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comprehensive JS stubs for OxCaml-specific primitives (domain TLS,
arch detection, blocking sync, basement/capsule) needed by the OxCaml
js_of_ocaml runtime
- Fix demo.js to load rpc_worker.bc.js (JSON-RPC) instead of the
non-RPC _opam/worker.js, fixing a protocol mismatch bug
- Fix exec RPC method never resolving: rename phrase_p parameter from
~name:"string" to unnamed, preventing rpclib from incorrectly treating
the phrase as a named parameter in the dispatch dict
- Remove unused cbort, zarith, bytesrw dependencies from opam and
dune-project
- Bump dune version in x-ocaml opam files to 3.21 for OxCaml support
- Update cram test expected output for current package list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix client.ml absolute_url to handle root-relative paths (/ prefix)
using window.location.origin instead of page directory path
- Abstract merlin_ext.ml to use a post function closure instead of
concrete Client.t, decoupling from specific backend
- Update cell.ml/mli to accept eval/fmt/post function closures
instead of Client.t, and split init/start to avoid synchronous
response race condition with jtw backend
- Wire x_ocaml.ml to read backend attribute and dispatch through
Backend module (jtw or builtin)
- Add W.setup call after W.init in jtw_client to load stdlib
- Create rpc_worker.ml: full-featured JSON-RPC worker combining
the complete S module (findlibish, stdlib) with JSON-RPC protocol
Verified: code execution and Merlin type-on-hover both work in the
scrollycode playground overlay (hovering shows type tooltips like
"type bool = false | true").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add jtw_client.ml that bridges x-ocaml's X_protocol with js_top_worker's
JSON-RPC protocol. This enables using js_top_worker as an alternative
backend for code evaluation, type checking, and completion.
The bridge translates:
- Eval requests to W.exec RPC calls
- Complete_prefix/Type_enclosing/All_errors to corresponding W.* calls
- Merlin position types (polymorphic variants) to js_top_worker's
msource_position (regular variants)
- js_top_worker result types back to Protocol/X_protocol response types
Also add backend.ml abstraction layer that dispatches between the built-in
x-ocaml worker and the js_top_worker backend based on configuration.
Add vendored mime_printer library required by js_top_worker-rpc.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New blog posts (monopam-madness, open-source-and-ai, weeknotes-2026-10),
notebook showcase with card layout and screenshots, Atom feed generator,
foundations notebook fixes, ONNX test improvements, widget interaction
tests, deploy script updates for oxcaml switch, and .gitignore for
build artifacts.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of requiring every .mld file to specify @x-ocaml.universe and
@x-ocaml.worker tags individually, configure the default universe path
once in dune-workspace (--config x-ocaml.universe=/_opam). The shell
emits <meta> tags from config values, and per-page @x-ocaml tags can
still override them.
Changes:
- dune-workspace: add --config x-ocaml.universe=/_opam to html_flags
- gen_rules.ml: pass --config to odoc html-generate for @site build
- odoc_jon_shell.ml: emit <meta> tags from x-ocaml.* config values
- odoc generator.ml: pass config to shell page_creator
- interactive_extension.ml: upsert meta tags (update existing or create)
- x_ocaml.ml: infer jtw backend from x-ocaml-universe meta tag
- Remove @x-ocaml.universe/@x-ocaml.worker from 14 .mld files using
the default /_opam universe
- deploy-site.sh: add dune install x-ocaml, chmod fix, widget-leaflet
- findlibish.ml: module detection fallback via jsoo runtime
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cppo preprocessing for merlin-js and x-ocaml workers to support
conditional compilation with OXCAML flag
- Guard day10 packages with enabled_if >= 5.3.0 since they need recent OCaml
- Remove fatal odoc warnings from dune-workspace (handled per-package now)
- Bump merlin-js dune lang to 3.17
- Add warning suppression flags where needed (-w -58, -w -67)
- Add interactive extension exercise pages (FOCS 2020/2024/2025, OxCaml
stack allocation)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add managed widget protocol (display_managed, command, register_adapter)
for external widget adapters like Leaflet maps
- Extract Leaflet map adapter into separate js_top_worker-widget-leaflet
library, loadable via #require
- Add widget rendering to x-ocaml web component (widget_render.ml) so
widgets work in .mld documentation pages
- Wire widget callbacks through OCaml client (js_top_worker_client_msg.ml)
- Complete the preloaded list in findlibish.ml to match all transitive
worker dependencies, preventing "file already exists" errors when
#require loads packages already compiled into the worker
- Add demo_widgets.mld and demo_map.mld documentation pages
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three features for x-ocaml interactive cells:
1. Worker busy indicator + stop/reset: When a cell is running (e.g. infinite
loop), the run button transforms into a spinning stop button. Clicking it
terminates the web worker, creates a fresh one, replays init messages, and
resets all cells to Not_run. Both builtin and jtw worker backends support
reset.
2. localStorage persistence: Exercise cells with data-id save their source
to localStorage (debounced 300ms). On reload, saved source is restored.
A small Reset button (bottom-left) appears when saved state exists,
allowing revert to the original HTML source.
3. Colab-style circular run/stop button: Replaces the old boxy text button
with a filled circle + white play triangle (CSS mask + ::after pseudo-
element). Running state shows a spinning arc with red accent and stop
square. Test cells get collapsible details with pass/fail/error indicators.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix sidebar kindBadge: map leaf-page→pg, module-type→MT, etc. (was
showing "L" for leaf-page entries)
- Stop escaping sidebar content HTML (entries contain <code> tags)
- Fix inline sidebar JSON: use Html.cdata_script instead of Html.txt
to prevent HTML-escaping inside <script> tags
- Add --xo-* CSS custom properties for x-ocaml cells in light/dark themes
- Fix support file registration: use 'opam var share' instead of
'opam var x-ocaml:share' (works without x-ocaml being an opam package)
- Suppress empty <li> from config-only extension tags (@x-ocaml.*)
- Add worker_url field to jtw opam findlib_index.json
- Refactor x-ocaml.js worker URL discovery to support both direct
worker_url and day10-style version/content_hash paths
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The inline script loader hardcoded ./_x-ocaml/x-ocaml.js relative to the
page, but support files live under odoc.support/ at the doc root. Switch
to Js_url which odoc resolves against support_uri (like odoc.css). The
backend config is now communicated via a <meta> tag instead of a script
attribute.
Also: add x-ocaml dependency on merlin-js, add odoc-interactive-extension
dependency on x-ocaml, and remove unused js_top_worker-rpc.message dep.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- findlibish.mli: use Js_top_worker.Impl.dynamic_cmis (RPC module removed)
- worker.ml: use Impl.dcs_url instead of Toplevel_api_gen.dcs_url
- x-ocaml/src/jtw_client: convert to cppo for OxCaml-only
ppx_template_generated field in Query_protocol.Compl
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Consolidate js_top_worker and odoc dual-compiler stanzas into single
library stanzas with cppo rules generating impl.ml from impl.cppo.ml
- Per-package findlib_index.json with relative universe paths (../dep)
and implicit stdlib dependency injection
- Add find_stdlib_dcs to Impl.S interface for stdlib CMI lookup via
findlib metadata instead of hardcoded URLs
- Replace jsoo Json.output/Json.unsafe_input with plain JSON.stringify/
JSON.parse for cross-jsoo-version compatibility (6.0.1+ox vs 6.2.0)
- Cross-origin worker support: set __global_rel_url in blob worker,
skip URL rewriting for absolute http(s) URLs
- Fix odoc doc comments and ocamlformat-ignore for cppo files
- Add demo docs, helper scripts, and x-ocaml package-lock.json
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a findlib_index.json contains a "compiler" field with version
and content_hash, x-ocaml now constructs the worker URL automatically.
This means .mld files only need @x-ocaml.universe — no separate
@x-ocaml.worker tag is required. The explicit x-ocaml-worker meta
tag still takes priority when present.
Uses a synchronous XHR pre-fetch of the findlib_index.json (~200 bytes)
before creating the worker, with browser JSON.parse for extraction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enable loading .cma.js files from a different origin (e.g., ocaml.org)
by working around Chrome's CORB which blocks cross-origin importScripts
for files with embedded binary CMI data.
worker.ml: detect cross-origin URLs in import_scripts and use
synchronous XHR + eval() instead of importScripts. Same-origin
URLs continue to use the standard path.
jtw_client.ml: create blob: URL wrapper for cross-origin worker.js
(browsers block cross-origin Worker construction), derive stdlib_dcs
URL from findlib_index base, switch to eval_stream for streaming
phrase-by-phrase output.
interactive_extension.ml: always load x-ocaml.js and worker.js from
local _x-ocaml/ path (same-origin), communicate universe URL via
<meta> tag. Set backend to "jtw" when a universe is configured.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add --copy-file flag to jtw opam/opam-all for including x-ocaml.js
and other assets in universe output
- Pass findlib_requires and findlib_index from meta tags through to
the JTW worker init, so @x-ocaml.requires packages are loaded
during setup
- x_ocaml.ml reads <meta name="x-ocaml-packages"> and
<meta name="x-ocaml-universe"> before creating the backend
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Add_cmis to X_protocol.request so pages can register external
package CMIs with the merlin worker. Page.create reads
<meta name="x-ocaml-packages" content="pkg1,pkg2,..."> and optional
<meta name="x-ocaml-cmis-url" content="./cmis/"> from the document
head. For each package, dynamic CMIs are registered so merlin can
provide completions, type-on-hover, and error checking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract page-level orchestration into a new Page module, separating
cell registry, test linking, message routing, and auto-run from the
WebComponent definition in x_ocaml.ml.
Key changes:
- Page module: cell registry, test linking (positional + data-for),
backend message routing, universe discovery stub, format config
- Cell: add ?merlin param, set_on_completed hook, has_completed,
string_of_mode, cell_for/cell_env accessors
- Editor: improved docstrings
- x_ocaml.ml: simplified to thin WebComponent + Page delegation
- Playwright browser tests: 17 assertions across 7 test scenarios
covering hidden/interactive/exercise/test modes, read-only state,
default mode, merlin disable, and full assessment chain
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add mode type and data attributes (data-id, data-for, data-env) to cells
- Hidden cells: no editor/UI, still execute in linked list chain
- Exercise cells: editable (default CodeMirror behaviour)
- Interactive/Test cells: read-only via EditorState.readOnly facet
- Read mode attribute from <x-ocaml mode="..."> elements
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add string option filename parameter to Complete_prefix, Type_enclosing,
and All_errors action variants. Thread through builtin worker config and
merlin_client query functions. When provided, Merlin uses the filename
extension to determine .ml vs .mli syntax.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three-layer architecture separating content, theme, and renderer:
Phase 1 — Scrollycode refactor:
- Strip ~1030 lines of embedded theme CSS from scrollycode_extension.ml
- Create scrollycode_css.ml with structural CSS using CSS custom properties
- Create scrollycode_themes.ml with three theme files (warm/dark/notebook)
registered as support files
- Simplify @scrolly tag: theme suffix now ignored (CSS concern, not content)
- Playground overlay styled via --xo-* custom properties on x-ocaml element
Phase 2 — Extra CSS support:
- Add --extra-css flag to odoc html-generate for injecting additional
<link> tags (used for per-page theme selection)
Phase 3 — Shell plugin system:
- Add Html_shell module with Shell interface and hashtable registry
- Register "default" shell in html_page.ml, "json" shell in
html_fragment_json.ml
- Replace hardcoded if/else in generator.ml with shell registry lookup
- Add --shell NAME flag (--as-json kept as backward-compat alias)
x-ocaml theming:
- Replace hardcoded colors in style.css with var(--xo-*, fallback)
covering editor, gutter, buttons, tooltips, and output areas
- CSS custom properties inherit through shadow DOM boundary, so
consumers theme x-ocaml with pure CSS — no JS injection needed
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add comprehensive JS stubs for OxCaml-specific primitives (domain TLS,
arch detection, blocking sync, basement/capsule) needed by the OxCaml
js_of_ocaml runtime
- Fix demo.js to load rpc_worker.bc.js (JSON-RPC) instead of the
non-RPC _opam/worker.js, fixing a protocol mismatch bug
- Fix exec RPC method never resolving: rename phrase_p parameter from
~name:"string" to unnamed, preventing rpclib from incorrectly treating
the phrase as a named parameter in the dispatch dict
- Remove unused cbort, zarith, bytesrw dependencies from opam and
dune-project
- Bump dune version in x-ocaml opam files to 3.21 for OxCaml support
- Update cram test expected output for current package list
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add support for building js_top_worker and odoc with both the standard
OCaml 5.4 compiler and the OxCaml 5.2.0+ox compiler using cppo
conditional compilation and dual dune stanzas.
js_top_worker changes:
- Bump dune-project to 3.21 for %{ocaml-config:ox} support
- Add dual library stanzas gated by (enabled_if %{ocaml-config:ox})
- Add cppo guards for OxCaml API differences:
- Compilation_unit.Name.t vs string for persistent loader
- Env.report_error ~level:0 (extra parameter)
- Language_extension.set_universe_and_enable_all (oxcaml-only)
- Unit_info.make ~for_pack_prefix (extra parameter)
- Typemod.type_implementation (extra Compilation_unit arg)
- Gate ppx_deriving_rpc with (not %{ocaml-config:ox})
odoc changes:
- Apply upstream oxcaml PR #1399 (art-w/upstream-oxcaml)
- Bump dune-project to 3.21
- Add dual stanzas in loader, model, xref2, odoc, syntax_highlighter
- Add cppo OXCAML guards for compiler API differences
- Support OxCaml features: modes, layouts, labeled tuples, iarray,
unboxed records, module type strengthening, polymorphic arguments,
call position arguments, Import_info.t, Compilation_unit.t
Verified end-to-end: scrollycode demos generate HTML and the
interactive playground evaluates OCaml code in the browser with
both compiler switches.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix client.ml absolute_url to handle root-relative paths (/ prefix)
using window.location.origin instead of page directory path
- Abstract merlin_ext.ml to use a post function closure instead of
concrete Client.t, decoupling from specific backend
- Update cell.ml/mli to accept eval/fmt/post function closures
instead of Client.t, and split init/start to avoid synchronous
response race condition with jtw backend
- Wire x_ocaml.ml to read backend attribute and dispatch through
Backend module (jtw or builtin)
- Add W.setup call after W.init in jtw_client to load stdlib
- Create rpc_worker.ml: full-featured JSON-RPC worker combining
the complete S module (findlibish, stdlib) with JSON-RPC protocol
Verified: code execution and Merlin type-on-hover both work in the
scrollycode playground overlay (hovering shows type tooltips like
"type bool = false | true").
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add jtw_client.ml that bridges x-ocaml's X_protocol with js_top_worker's
JSON-RPC protocol. This enables using js_top_worker as an alternative
backend for code evaluation, type checking, and completion.
The bridge translates:
- Eval requests to W.exec RPC calls
- Complete_prefix/Type_enclosing/All_errors to corresponding W.* calls
- Merlin position types (polymorphic variants) to js_top_worker's
msource_position (regular variants)
- js_top_worker result types back to Protocol/X_protocol response types
Also add backend.ml abstraction layer that dispatches between the built-in
x-ocaml worker and the js_top_worker backend based on configuration.
Add vendored mime_printer library required by js_top_worker-rpc.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>