Skip to content

About

A browser-based Joomla playground with selectable Joomla and PHP versions, automatic extension installation, and configurable startup commands.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

JoomEngine Playground

Build Joomla extensions with Joomla Component Builder (JCB) in your browser. JCB is the development engine at the heart of JoomEngine. JoomEngine's PHP-WASM int64 distribution, built on Sean Morris's runtime, and a real MariaDB WebAssembly database run the site. The playground assembles released 64-bit PHP builds, the MariaDB bridge, and a separately compiled native PDO extension into a static site. PHP requests and SQL execute in browser workers.

The deployment address is https://playground.joomengine.org/. The default deploy opens the JCB dashboard on Joomla 6 with PHP 8.4. JCB is also the default on Joomla 5; JCB + MCP remains an optional Joomla 6 deployment. Select Joomla only to start without additional extensions. Rocket is the compact, multilingual interface around the running Joomla site.

JoomEngine Code adds a lazy-loaded browser IDE for that same site: native editor groups, project files and language services, docked/floating/detached layouts, reviewed AI changes and PHP debugging of actual Joomla requests. See the user guide, current experience roadmap, and historical implementation checkpoints. Named AI API presets, custom/local endpoints and scoped context are implemented; the AI validation record distinguishes protocol tests from outstanding real-service browser checks. Local editing and debugging do not require AI credentials.

The DB action opens Adminer against the same running database. Code and DB alternate in the embedded workspace, with separate left/right/bottom, floating, full-width and detached layouts. Adminer loads on demand and adds about 435 KiB of staged PHP/UI assets (about 246 KiB gzipped), without another PHP or database engine.

Browser compatibility verifies isolation before starting the runtime and automatically tries a controlled require-corp fallback when normal isolation is unavailable. Both modes run without a relay. The restricted public-image relay is an optional facility for registered external images and remains unconfigured. Real-device mobile validation follows deployment.

For an agent-oriented introduction to configuring a site, working with JCB, testing extensions and exporting results, see the Playground agent guide.

Upstream foundations and credits

This project builds directly on the work of these maintainers and contributors:

  • Joomla provides the CMS and its installation, extension management, and console interfaces.
  • Joomla Component Builder is JoomEngine’s core development tool and default deployment.
  • PHP/phpdbg supplies PHP and its debugger; JoomEngine Code uses the int64 distribution's php-dbg-wasm runtime with a small, reproducibly compiled HTTP/debugging bridge.
  • MariaDB provides the database engine.
  • joomengine/php-wasm-int64 provides PHP 8.3–8.5 with native 64-bit PHP integers, matching extensions, and the configured headers used to build Playground's native adapters.
  • seanmorris/php-wasm — Sean Morris and the project’s contributors provide the PHP runtime, CGI implementation, filesystem, asynchronous JavaScript integration, and loadable extension support underlying JoomEngine's int64 distribution.
  • JoomEngine MariaDB WASM Bridge provides the database worker, persistence, host protocol, native PDO driver, and adapter for the upstream PHP runtime.
  • shyim/lite4mariadb makes the MariaDB engine available to the bridge as WebAssembly.
  • Microsoft VS Code and Monaco provide the editor and workbench foundations. CodinGame provides their browser integration. JoomEngine Code retains the exact shipped licenses, source notices and dependency inventory.
  • Adminer provides the database interface for browsing tables, inspecting schemas and running SQL through the active site's existing PHP and MariaDB runtimes.
  • emscripten-core/emscripten — The Emscripten maintainers and contributors provide the compiler toolchain and runtime facilities that make PHP, native extensions, and MariaDB available in WebAssembly.

Thank you to these communities for the engineering and maintenance this project relies on. Their licenses and notices remain with the distributed assets; see NOTICE.

Joomla also maintains an official Joomla Playground (source). JoomEngine Playground was developed independently and is not based on that project's codebase. It uses a different PHP runtime and database architecture, with its upstream foundations credited separately above.

What is assembled

The browser loads the released int64 php-cgi-wasm runtime and its matching extensions. A small pdo_mariadb_wasm module registers PDO’s mysql driver. Its asynchronous adapter passes database operations to the MariaDB bridge. The playground service worker routes site requests to a dedicated PHP worker and adds the isolation headers needed by the threaded MariaDB engine.

The native build compiles the PDO, cURL, Sodium and phpdbg HTTP/debugging bridges against the selected int64 release's configured PHP headers. Fileinfo is already included in that runtime and supplies MIME detection with its embedded magic database. cURL uses Sean Morris’s php-wasm-curl to connect PHP’s ext/curl to the host’s Fetch API. The implementation is pinned to 6085917954da9682c32ebcbea27a626d2308381b and loaded alongside the matching int64 PHP runtime. Sodium uses the official libsodium 1.0.22 release and Web Crypto for its random source. A checksum-verified JavaScript CGI adapter preserves binary request bodies, uses indexed input reads for large uploads, and waits for preloaded files before starting or restoring PHP. Playground uses the released int64 PHP WebAssembly binary unchanged. The distributed .so files are WebAssembly extensions for these specific upstream builds, not native Linux PHP modules.

The supported catalog is:

Joomla distribution Available PHP builds
5.4.10 8.3, 8.4, 8.5
6.2.0 8.3, 8.4, 8.5

Each build resolves the latest stable JoomEngine int64 release once. Its manifests provide the exact PHP patch versions, matching extension headers and source pins. The generated catalog records the selected versions; PHP release candidates and unpublished builds are not selected.

versions.json defines the supported PHP lines and default selection; the generated runtime manifest records their exact released builds.

Current and forward version selection

Choose Joomla, JCB and PHP, then launch. The selected Joomla and JCB packages are fetched automatically from the Playground's own static assets and installed inside the browser. Choosing a version records the choice; it does not open a ZIP download or upload dialog. Custom extension URLs remain subject to their host's browser access rules.

The selectors show Current stable first, Nightly builds next and Upcoming releases last. Joomla choices cover majors 5, 6 and 7: one latest stable per major, the current nightly for each active development line, and the newest alpha, beta or RC for each future release. Joomla 4 and historical releases are excluded. JCB uses the same current-and-forward policy for major 5 onwards and follows the selected Joomla major. Joomla 7 can use JCB 6 for forward testing while JCB 7 is unavailable; this pairing is experimental. A previously selected archive that falls outside the current list appears separately as Saved version. Reopening it preserves the installed site rather than upgrading it.

At build time, discovery follows Joomla's official next patch, next minor and next major XML lists to their details feeds and selects Full Package ZIPs for fresh installations. JCB discovery reads only its 5.x and 6.x XML manifests. One recent Joomla release request, limited to 100 records, supplies stable and published preview releases missing from the nightly feeds. Discovery does not enumerate JCB branches or tags or paginate through old releases.

The build verifies published SHA-256/SHA-512 checksums, fingerprints full packages without a published checksum, and writes immutable package paths alongside dist/assets/version-catalog.json. Its generatedAt field identifies when the catalog was built. The selectors refresh that published local catalog; they do not query upstream servers or fetch a newer nightly on their own. Pages rebuilds daily at 03:15 UTC and on changes to main, then publishes only after validation of that same artifact. A failed upstream refresh or validation leaves the previous deployed catalog and packages available. Use a new site to try a newly published nightly; retain a complete site export when the exact old build must remain portable.

Playground checks for a new published build on startup, when returning to the tab, and before launching. When a build changes, it refreshes this deployment’s cached catalogs and offers Reload Playground. Close the running site before reloading; saved sites, databases, local images and preferences are preserved.

Build and run locally

Use Node.js 26.12.1 as pinned in .node-version, npm, Git, Docker, Bash, curl and tar. Native compilation uses the Emscripten image pinned by the selected int64 release. This is the tested build runtime; Node.js 24.x has a known V8 shared-WASM lifecycle crash. JCB uses its original bundled spreadsheet dependencies. No local Composer build or replacement vendor tree is required.

Clone the playground, resolve the current stable int64 release, and compile the native adapters with its matching toolchain and configured headers:

git clone https://github.com/joomengine/playground.git
cd playground
npm ci --ignore-scripts
npm run prepare:php

mkdir -p external
git clone https://github.com/joomengine/mariadb-wasm-bridge.git external/bridge
bridge_ref=$(node --input-type=module -e "import p from './versions.json' with {type:'json'}; console.log(p.nativeDriver.sourceCommit)")
git -C external/bridge checkout --detach "$bridge_ref"

compiler_image=$(node --input-type=module -e "import {loadPhpRuntime} from './scripts/php-runtime.mjs'; console.log((await loadPhpRuntime()).upstream.emscriptenImage)")
docker run --rm -v "$PWD:/work" -w /work -e BRIDGE_SOURCE_DIR=external/bridge \
  "$compiler_image" node scripts/build-native.mjs

MARIADB_DRIVER_DIR=.cache/native npm run build
npm run build:deploys
npm run serve

Open http://127.0.0.1:4173/. The local server serves static files and supplies COOP/COEP headers. PORT and HOST can override its listen address. Build outputs are written to dist/; source downloads and compiled modules are cached under .cache/.

With the matching Emscripten compiler already activated, native compilation can also run directly with BRIDGE_SOURCE_DIR=external/bridge node scripts/build-native.mjs. Run npm run prepare:php at the start of a new build to select the latest stable release, then rebuild its native adapters. All later build steps use that same recorded selection. Bridge JavaScript and engine assets come from the verified MariaDB bridge release.

Build provenance

package-lock.json pins the npm packages and their integrity values. versions.json selects the supported PHP minors and stable int64 release policy, and pins the MariaDB release checksum, native and adapter source hashes, Joomla distributions and compatible runtime combinations. .cache/php-int64/resolved.json records the selected int64 release and archive hashes. Its verified manifests provide the exact PHP source commits, compiler image and ABI for the native build.

The build verifies every entry in the MariaDB bridge 0.1.8 release inventory and stages its runtime, PHP adapter, engine JavaScript and WebAssembly directly from that release. Native driver source hashes must match the same release. The PDO extension’s compiler, PHP version, source hashes, upstream revision, and binary hash must also match. Native cURL and Sodium modules retain their matching source inventories, compiler identities and licenses. The CGI JavaScript adapter records original and adjusted hashes. Each Joomla archive is verified before staging. A missing driver or mismatched input fails the build.

dist/assets/manifest.json records the selected runtimes, extension assets, preload files, source revisions, and dependency identities. Its bridge.release entry identifies the published release archive. Its complete inventory is retained under the bridge's versioned asset directory; copied runtime and engine assets retain their released hashes. dist/asset-inventory.json records the files, sizes, and SHA-256 values in the assembled site. Updating a dependency means updating its pins, rebuilding its matching native modules, and running the complete validation suite.

PHP HTTP requests

PHP’s curl_* functions and HTTP stream wrappers perform real HTTP requests through the Fetch integration. cURL supports request methods, headers, binary bodies, status codes, redirects, timeouts, and streaming response callbacks. The native extension is exercised on every supported PHP build, including the HTTP patterns used by JCB’s file and API helpers.

A small native HTTP stream adapter is compiled into the loadable cURL extension. It preserves file_get_contents(), fopen(), get_headers(), stream contexts, response-header metadata and caller-local $http_response_header, using the same browser transport. The upstream PHP binary remains unchanged. A version-independent JCB compatibility guard skips unavailable image-format identifiers instead of claiming support for decoders absent from the runtime. If JCB cannot cache a public image, its image helper can display the original HTTPS URL directly. A missing cache reference can use the existing file verified against its metadata checksum. These corrections use the installed component’s own metadata; no artwork copies or host lists are maintained.

Custom extension URLs entered in Rocket are passed to Joomla's normal console installer: extension:install --url=URL. Joomla handles the download, unpacking and installation. Custom template ZIPs use the same path. Installer errors remain visible while the site continues opening; required core packages must install successfully. PHP HTTP requests use the browser's Fetch transport.

Only HTTP and HTTPS are supported. Browser requests still follow CORS and mixed-content rules. The browser controls certificate validation, cookies, forbidden request headers, and connection behavior; options for disabling TLS verification cannot bypass browser security. Redirect responses are hidden from browser Fetch: enable following explicitly when a client needs redirects. PHP's cookie-file settings do not create a separate browser cookie store. HTTP proxies and Unix sockets are unsupported. Requests to PHP in the same playground instance cannot complete recursively while its worker is already executing a request; use a separate server or independent instance for HTTP service calls. See the upstream compatibility guide before relying on server-specific networking behavior.

Using Rocket

On normal entry, Playground selects the last successfully used saved site, or JCB when none exists, and shows a ten-second startup countdown. Stop countdown cancels automatic launch; Launch opens the staged target immediately. Opening configuration or manually selecting a saved site also cancels the countdown. Manual selections wait for Launch and leave the current site running. Use ?start=0 to load setup without a countdown; explicit deployment/share links keep their own configuration and review requirements. In Share, Immediate deployment adds immediate=1 to skip that countdown; leaving it unchecked preserves the normal startup, and start=0 still prevents automatic launch. The hint beneath Launch updates with your choices: a prepared fast start, a prepared base needing additional setup, or a fresh installation that takes longer.

The chevron opens one dashboard containing saved-site management, runtime configuration, site actions and appearance. Site and Admin, beside Deployment, navigate the existing preview without reinstalling Joomla or starting another runtime. Admin uses the normal Joomla authentication flow. The slim header scrolls with the page. The supplied pearl rocket identifies the favicon, Deployment, Launch and progress views. Activity remains below the site; About in the footer lists the technology repositories and distributed notices.

Appearance defaults to System, follows operating-system changes live, and can be overridden with Light or Dark. The choice is scoped to this tab session and survives reload; it synchronizes Code, dialogs, the assistant and detached editor windows. It does not restyle the embedded Joomla template.

The main JoomEngine Code action toggles the editor without discarding its buffers. Its compact header keeps layout/window controls available when action labels collapse at narrower editor widths. Accounts opens AI API settings; the robot-shaped AI Assistant uses the same isolated session connection. See the Code guide.

The main dashboard selects Joomla, JCB and PHP. Its deployment selector and the deployment editor show the same built-in and saved custom setups. Selecting one fills its fields; incompatible runtime choices are disabled. Deployments that open JCB require a compatible JCB version, while other deployments allow None.

The deployment editor configures packages, languages, the site name, administrator, login behavior, menus and a template. It can install a component from a public ZIP URL, make one of its frontend views the Home menu item, install a template, and set its parameters. Installed components, menu layouts and template styles can be discovered from the running site. See the deploy guide for the complete document format and advanced parameters.

Under Extension packages, paste a complete HTTP or HTTPS ZIP URL. Use Add another URL for more packages, or remove an unwanted row. The separate Advanced options control exposes the same packages as editable JSON objects with a url. User-supplied checksum fields are ignored; managed core packages retain their published checksums. Basic fields and advanced JSON stay synchronized for packages, console commands, menus, content and template parameters. Invalid JSON remains visible until corrected.

  • Save in the deployment editor keeps a named recipe in this browser and adds it to both deployment selectors. Editing a built-in saves a Custom copy; the original remains available.

  • Save as copy creates another custom recipe. Delete removes only a custom recipe, leaving existing saved sites intact.

  • Export configuration downloads the complete version 2 recipe, including administrator details. Import configuration adds it as a named custom deployment. Configuration JSON does not contain the site's files or database.

  • Use starts an independent deployment from the editor's configuration and prepares a reusable share link.

  • Apply to this site checkpoints the running site before installing new packages or applying configuration. If an operation fails, the recovery action restores that checkpoint as a separate site. Removing a package from the editor does not uninstall an already installed extension.

  • Keep this site stages the persistence choice for the next launch. Save saves the running site's files and database. Saving a temporary site copies its current state into persistent storage, including credentials, and transfers the open Code session and recoverable drafts to that saved identity.

  • Restart restarts PHP with the current settings while preserving the site, including a temporary site's files and database.

  • Close shuts down the workers and releases the site lock. Closing a temporary site discards its state after confirmation.

  • Reset deletes the running site's files and database after confirmation, or the staged saved key when no site is running. It is separate from saved-entry management.

  • Recover saved site opens storage without booting Joomla. Download a backup, then restore safe error settings if needed; the original configuration is kept privately. If MariaDB cannot start, recovery opens the saved PHP files read-only so they can be downloaded without changing either saved store. That recovery ZIP contains files and private settings, but no SQL database; it does not repair a failed database. Reset and launch provides an explicit fresh start from the failure screen.

  • Configure deployment → Use this deployment creates an independent site from the editor configuration. Save keeps the recipe for reuse; dashboard Launch opens the selected saved site. The current runtime stays open until the new launch completes its dirty-work checks.

  • Rename changes the selected saved entry's display label, preserving its storage key, Joomla title, files and database.

  • Delete saved site names and removes the selected saved entry, files, database and editor drafts after confirmation. An inactive entry is deleted without launching it. Locked or failed deletion retains its management entry so it can be retried.

  • Download exports the complete site, its files, or its SQL database.

  • Upload opens a complete site export ZIP as a new, independent saved site.

  • Hide controls in either the header or footer hides both bars, settings and activity together. Joomla keeps the same running iframe, current page and unsaved work. Small restore tabs occupy the top-left and bottom-left document boundaries and scroll away in the middle of a long page. Each reveals the controls and scrolls to its corresponding header or footer without restarting or transferring the site.

Persistence is enabled by default. Joomla files, session data, cookies and the MariaDB database are kept in IndexedDB. A site key identifies saved data on this origin. Returning normally to the domain stages the last saved site and restores its last safe in-site route when the startup countdown or Launch opens it. Route metadata excludes action/security parameters and credentials; a missing resumed page falls back to the initial route. Explicit URL or edited initial-page choices remain authoritative. Temporary sites do not replace the last saved-site preference.

The saved-site selector, PHP/Joomla controls and deploy choices stage changes; Launch validates them before closing the current runtime. Only one tab may own a saved site at a time. Applying a staged PHP choice preserves saved content. Changing the Joomla release or deploy selects a separate profile, rather than upgrading an existing installation. Saved metadata migrates without the previous 40-entry pruning, and display names remain separate from setup identity. MariaDB bridge 0.1.8 checkpoints InnoDB before flushing its filesystem to browser storage. Playground reserves the PHP request queue until both the site files and database finish saving, including during configuration changes and PHP restarts. A successful Save can therefore be reopened after a whole-page reload without using Close first. Checkpoint or storage errors remain visible save failures; they do not advance the saved-state indicator.

The interface opens the site before its first background checkpoint. Saving starts as soon as the runtime is idle, then repeats about a minute after each completed save. Saves run in the filesystem and database workers, keep the surrounding controls usable, and never overlap. Close waits for an active save and completes the first checkpoint if it has not started. Launch uses published prepared images or compatible images already cached locally; it does not delay first use to export a new reusable image. Saved sites still resume from their own files and database.

The credentials dialog shows the generated administrator login details, including when automatic login is disabled. Each fresh site receives new credentials; saved sites retain theirs. Credentials stay in private runtime metadata outside the webroot and share links. Saved custom recipes, full configuration JSON exports and complete site downloads retain the known sandbox administrator. Browser storage can be evicted or cleared and is not a backup. A save reports completion only after both stores flush; closing a tab cannot guarantee an unfinished save completes.

External packages must be public ZIP archives. Extension and template URLs accept HTTP or HTTPS. Prefer HTTPS for integrity in transit. HTTP package URLs remain subject to the browser's mixed-content rules. Managed packages are limited to 128 MiB and repository packages have verified pinned digests. Custom extension URLs use Joomla's installer directly; the wrapper ignores user-supplied checksum fields on that path. The URL must lead to a package ZIP.

Each extension, template or language ZIP installed by the deployment helper gets 180 seconds of PHP execution time and a 210-second host deadline. The allowance is applied only to that installer request: ordinary page requests and Joomla's administrator upload interface retain the selected PHP settings (60 seconds by default). Preset and manually supplied packages use the same installation policy. A timeout stops setup without replaying the installer or marking the site ready; the partially installed site requires recovery or a fresh deployment.

JavaScript callers of installExtension(runtime, bytes, options) can set executionTimeSeconds to an integer from 5 to 300. Its default is independent of phpSettings.max_execution_time, so an explicit smaller installation allowance is respected. Optional timeoutMs must allow at least 30 seconds beyond that PHP allowance and cannot exceed 600,000 milliseconds. Invalid or contradictory budgets are rejected before the package is written. Host deadlines start when the operation leaves the runtime queue, and a host timeout terminates the PHP worker in both browser and Node build runtimes. Raising only timeoutMs does not raise PHP's execution allowance.

Shared configurations with custom packages, commands or site content pause for review before launching. Installed code shares the playground origin and can access other sites saved on that origin; separate site keys are an organizational feature.

Startup commands are arrays of Joomla console arguments, executed in order after package installation and without a shell. For example:

[["cache:clean"]]

Use command names and arguments directly, without php, a script path or shell operators. A failed installation or command stops setup and reports its details. An interrupted initial installation must be reset before retrying. Reopening a completed site does not replay its original deployment commands.

A complete export contains site/, database.sql, database.ndjson for prepared-site import, export.json, and DEPLOYMENT.md. Its Joomla configuration uses portable paths and placeholder hosting database settings. Follow the included instructions to upload files, import SQL, and configure the destination database. Private runtime files, browser sessions, and generated caches are excluded. Complete site downloads include the runtime settings, opening page, and known sandbox administrator credentials in export.json. Upload restores the installed files and database, including subsequent edits, with those same credentials and opening page under a new saved-site identity. It does not rerun extension installation or deployment commands. Ordinary extension ZIPs and incomplete exports are rejected.

One SHA-256 content hash covers the exported site files and database, excluding export.json and export instructions. Upload reports Package validated. when the payload matches and rejects a mismatch before restoring the site. Older complete exports without a content hash remain importable and show a brief notice that validation is unavailable. Files-only ZIP and SQL-only downloads are also available. Tables, views, and simple triggers are supported. Stored routines, events, compound trigger bodies, system-versioned tables, cross-database references, and aliases or common table expressions matching the source database name stop export with an explicit error.

Interface and Joomla languages

Rocket starts in English. Its independent language selector offers English, Afrikaans, German, French, Italian, Spanish, Simplified Chinese, Dutch, Hebrew, Greek, Arabic, Portuguese, Russian, Japanese, Korean, Hindi, Bengali, Turkish, Indonesian and Ukrainian. Hebrew and Arabic use a right-to-left interface. Translated interface catalogs load on selection. The preference is saved locally; ?uiLanguage=af selects Afrikaans explicitly. This changes Rocket's controls, dialogs and footer, without changing Joomla or downloading a Joomla language pack. Technical details from PHP, Joomla and installed extensions retain their original messages in the activity log.

The dashboard's Joomla Language and the Deployment dialog's Site Languages use the same selected-version catalog. Focus or open either selector to browse tags and language names, or type to filter and enter a custom tag. Site Languages supports multiple removable selections. Script subtags such as sr-Latn-RS are accepted; a custom tag still needs a usable pinned or explicitly configured language package before launch. Entering a tag alone does not install an unavailable package.

Ordinary Joomla deployments use Joomla's English default. The multilingual heritage deploy installs Afrikaans, German, French, Italian, Spanish, Simplified Chinese, Dutch and English, with Afrikaans first and default. Selecting a multilingual deployment enables the corresponding content languages, language filtering, switcher and language-specific home pages.

Language packs are separate installable ZIPs fetched only for the selected Joomla languages; an English-only site downloads none. The build assembles deterministic packages from pinned official Joomla translation sources and serves verified ZIPs on the playground origin when direct package-host CORS would block browser installation. Translations are not embedded in PHP or eagerly preloaded. Exact source revisions, file hashes and license details are documented in the language package notes.

PHP configuration and capabilities

The PHP settings dialog changes the running PHP configuration and restarts its worker while preserving files and database. It verifies the effective values reported by PHP and attempts to restore the previous configuration if startup fails. The same phpSettings object works in deployment documents and repository deploys:

{
  "upload_max_filesize": "128M",
  "post_max_size": "160M",
  "max_execution_time": 60,
  "max_input_time": 60,
  "max_input_vars": 10000,
  "memory_limit": "512M"
}

These defaults cover JCB's published guidelines with extra POST, form-variable and memory headroom. POST size must exceed the upload limit, and PHP memory must leave at least 64 MiB above POST size. The editor validates bounded values rather than accepting arbitrary ini directives. Deploys can request different values; Service Directory allows 180 seconds for its large initial geographic-data import. A PHP memory limit is not a guarantee that a particular browser or device can allocate that much memory.

MariaDB uses a 128 MiB server packet limit and a 64 MiB initial InnoDB buffer pool. Transport bounds are 32 MiB per JSON request, 64 MiB per JSON response and 128 MiB of queued requests. These are operation limits, not a small total-database quota: base64 encoding, PHP memory and the database heap still constrain individual results. Exports transfer large values in bounded chunks and report destination packet limits. Database-limit controls in Rocket are deferred; the bridge already exposes bounded startup options and MariaDB's supported settings for future integration.

Runtime health checks require the real PDO MySQL bridge, cURL, fileinfo, Sodium, GD, Intl, mbstring, OpenSSL, DOM, SimpleXML, XML/reader/writer, JSON, ZIP and zlib extensions. Provisioning checks exercise image decoding, Unicode/XML, archives, cryptography, database access and uploads. GD supports JPEG, PNG and WebP; AVIF and XPM are not built into this runtime. The official Joomla Docker image is a setup reference, while browser limitations remain explicit below.

The Joomla 6 JCB + MCP deploy installs the unchanged MCP package and configures its native Joomla token-authenticated HTTP endpoint for clients in the same browser. Deployment verification exercises HTTP initialization, tool discovery and an action description. Executing actions that call Joomla's API again also requires nested PHP request support; discovery alone does not verify those operations. Native processes and stdio are outside this integration. See the MCP integration notes.

Embedding and URL configuration

Repository deploys define packages, language packs, content, and console commands. See the contributor guide and schemas to add another recipe. The default is jcb on both Joomla 5 and Joomla 6; blank installs Joomla alone. Deployment documents can also be composed entirely in the interface without changing this repository.

fresh=1 creates an independent site key and bypasses prepared snapshots. It does not erase another saved site. The flag is consumed after launch and the new key stays in the address for subsequent reloads. Use Reset to erase the current site explicitly.

The build stages verified packages on the same origin. For prebuild: true recipes, npm run build:deploys installs real Joomla, exports it, and imports the archive into a second runtime with new credentials before publishing it. Prepared copies match an exact Joomla release. JCB and the heritage demonstration are prepared for both catalog releases. Opening JCB restores the installed files and database instead of repeating its installer. New sites created from prepared images receive their own configured administrator; PHP settings and explicit extension, language, menu and template choices still apply. fresh=1 builds the original recipe instead.

Prepared JCB copies use the stable package releases pinned in deploys/jcb.json: currently JCB 5.2.0 and 6.2.0. To adopt a new stable release, update its versioned URL and SHA-256 in that recipe and the optional MCP recipe, update any applicable compatibility inputs, and rebuild. CI installs and independently restores the new copies before publishing them. Existing saved sites are preserved. A new deployment uses a prepared copy only when its exact Joomla/JCB selection matches that copy; other listed versions install automatically from their verified staged packages. Updating the prepared recipe and rebuilding remains necessary to publish a new prepared snapshot.

The interface recognizes these query parameters:

Parameter Meaning
deploy=jcb Choose a repository deploy; blank installs Joomla alone
joomla=5.4 Resolve a minor or exact version to a tested catalog release
php=8.5 Select the PHP minor whose patch version is pinned in the catalog
path=/administrator/ Initial page inside Joomla
toolbar=0 Hide the header and footer together, with edge tabs to restore them
persist=0 Use a temporary site
language=en-GB Select the Joomla language; another supported tag installs its pack
uiLanguage=af Select Rocket's interface language independently
name=Client%20demo Set the Joomla site name
login=no Start or reopen with the administrator logged out
fresh=1 Create an independent site from the recipe
key=example Reopen a saved site in this browser
extensions=[...] Additional objects containing url and optional sha256
commands=[["cache:clean"]] Additional Joomla console argument arrays
start=0 Show setup first; the default page offers a ten-second countdown
immediate=1 Skip the countdown for automatic deployment; start=0 still takes precedence
config=https://example.org/deploy.json Load a public deployment document, optionally verified with sha256

For a deployment hosted at /playground/, this same-origin iframe opens an administrator playground with the header and footer hidden:

<iframe
  src="/playground/?joomla=6.2.0&php=8.4&path=%2Fadministrator%2F&toolbar=0&start=1"
  title="Joomla Playground"
  allow="cross-origin-isolated"
  style="width:100%;height:800px;border:0"
></iframe>

The embedding page must also provide the isolation policy required by the browser. The iframe permission alone cannot make an unisolated parent page cross-origin isolated. Start with same-origin embedding and matching COOP/COEP headers. toolbar=0 starts with both bars hidden and the same restore tabs available. A raw site-preview URL still requires its owning playground tab. Share launches an independent installation from the same public deployment configuration; hiding controls keeps the current site running in its original tab.

Share includes the complete public deployment: Joomla/PHP versions, PHP settings, site name, packages, language selections, menus, template parameters, login choice and setup commands. Advanced configurations use an encoded #deploy= fragment. The Share dialog always exposes the link for manual copying if clipboard access is unavailable. Links are limited to 16 KiB; JSON documents to 1 MiB.

Share URLs use public version 1 documents and exclude administrator credentials and local site keys. Custom shares include their complete recipe, so the recipient does not need the sender's browser registry. Export configuration downloads a version 2 document with the deployment name, compatibility requirements, all setup fields and administrator details; Import configuration adds it to the custom deployment list. Public hosted configuration URLs use the same password-free format as shares. Neither format transfers saved files or database content; use a complete site download for that. The document schema and deploy guide describe the JSON format, menu/template fields and hosted configuration URLs.

JavaScript API

Import src/playground.mjs from the built deployment. Call prepareEnvironment() before collecting settings: on a host without isolation headers, its first invocation can require one page reload after the service worker takes control. The supplied interface performs that reload automatically.

The following complete module can be placed in a module script on a page at the root of the built deployment. It starts a temporary Joomla site, displays the administrator password, executes a PHP database query, and provides a close button:

import { createPlayground, prepareEnvironment } from './src/playground.mjs';

const output = document.createElement('pre');
const frame = document.createElement('iframe');
const closeButton = document.createElement('button');
closeButton.textContent = 'Close playground';
closeButton.disabled = true;
frame.title = 'Joomla';
frame.style.cssText = 'width:100%;height:700px;border:0';
document.body.append(output, closeButton, frame);

try {
  const environment = await prepareEnvironment();
  if (environment.reloadRequired) {
    location.reload();
  } else {
    const password = `Jp!${crypto.randomUUID()}`;
    const site = await createPlayground({
      phpVersion: '8.5',
      joomlaVersion: '6.2.0',
      siteName: 'API demonstration',
      initialPath: '/administrator/',
      persistence: false,
      storageKey: 'api-demo',
      autoLogin: true,
      admin: {
        name: 'Playground Administrator',
        username: 'admin',
        email: 'admin@example.test',
        password,
      },
      extensions: [],
      startupCommands: [],
    }, {
      onProgress: ({ message }) => { output.textContent = message; },
    });
    frame.src = site.url;
    const result = await site.runPhp(`<?php
      $db = new PDO('mysql:dbname=joomla;charset=utf8mb4', 'root', '');
      echo $db->query('SELECT VERSION()')->fetchColumn();
    `);
    output.textContent = `Administrator: admin\nPassword: ${password}\nMariaDB: ${result.text}`;
    closeButton.disabled = false;
    closeButton.addEventListener('click', async () => {
      closeButton.disabled = true;
      try {
        await site.close();
        frame.remove();
        output.textContent = 'Playground closed.';
      } catch (error) { output.textContent = error.message; }
    }, { once: true });
  }
} catch (error) {
  output.textContent = error.message;
}

createPlayground(config, { onProgress }) returns a handle only after Joomla provisioning completes:

Handle member Result
url, baseUrl Initial page and site root URLs
runtimeInfo Actual PHP version, loaded extensions, PDO drivers and effective ini settings
configuration A copy of the resolved current configuration
installation Joomla version, site name, and whether saved data was reopened
request(path, init) A standard Response for an internal site request
runPhp(source, { timeoutMs }) CGI result with status, headers, binary body, and decoded text
fs.mkdir(path) Create directories in the virtual filesystem
fs.writeFile(path, textOrBytes) Write a virtual file
fs.readFile(path) Read bytes; pass { encoding: 'utf8' } as the second argument for text
fs.readdir(path), fs.stat(path), fs.unlink(path) Inspect or remove virtual files
flush() Flush both stores
keep() Persist a temporary site's current state; returns its replacement handle
checkpoint() Create a private recovery snapshot, including administrator state
updatePhpSettings(settings, phpMinor?) Restart PHP, validate effective values and preserve site data
switchPhpVersion(phpMinor) Restart on another compatible pinned PHP build
discoverConfiguration() Discover installed components, frontend layouts, menus and templates
applyConfiguration(configuration) Apply additions and site settings with a recovery checkpoint
exportSite({ format }) Return { bytes, filename, mimeType, metadata }; format is bundle, files, or database
recovery Recovery metadata when opened with createPlayground(config, { recovery: true })
repairConfiguration() Back up configuration and restore safe Joomla debugging/error settings
exportRecoveryFiles() Download raw saved files, including private credentials and sessions; does not include SQL
close() Close the instance while keeping saved data
reset() Close the instance and delete its saved data

The dashboard's complete-site download calls exportSite({ format: 'bundle', includePlaygroundConfiguration: true }) to include the runtime configuration, opening page and known administrator in export.json. Internal prepared-image builds omit that option. Files-only and SQL-only exports do not include this restore metadata.

resetPlayground({ storageKey }), exported from the same module, erases a closed or partially installed saved site. Call it only after the user confirms deletion. Private checkpoints include authentication state: keep them local and do not use them as public deployment documents. The filesystem document root is /persist/www. runPhp executes through CGI; it is not a shell or an unrestricted host command interface.

Hosting and GitHub Pages

Serve the entire dist/ directory over HTTPS, or use localhost for development. Do not open index.html through file://. WebAssembly modules and other assets must remain at their generated relative paths. Serve .mjs as JavaScript and .wasm/.so as application/wasm.

A static host that supports response headers should supply:

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: credentialless

MariaDB requires SharedArrayBuffer, a secure context, and cross-origin isolation. The playground also requires service workers, IndexedDB, and Web Locks. GitHub Pages cannot configure these response headers directly, so the included service worker adds them to controlled responses and the interface reloads once to activate isolation. That worker also handles the PHP site routes; do not replace it with an unrelated isolation worker.

The credentialless policy allows ordinary public images, classic scripts, and stylesheets to load directly from their original hosts without requiring CORS or CORP response headers. These cross-origin no-cors requests omit cookies and other credentials. Fonts, JavaScript modules, and requests that read remote data still follow normal CORS rules; an explicit remote CORP restriction is respected. No extension-specific image URLs or artwork snapshots are maintained.

When credentialless cannot establish shared memory and worker support, startup automatically tries require-corp. Chromium and WebKit have passed automatic fallback and real PHP/MariaDB/Joomla startup checks; device names and screen size do not select a policy. See browser compatibility for the tested engines and remaining physical-device checks.

The Publish playground to Pages workflow runs on every push or merge to main, daily at 03:15 UTC to refresh the current and nightly packages, and can also be started manually on main. It validates first, then deploys that exact tested artifact through the github-pages environment. Scheduled runs use the same checks and installation gates as other releases. Upstream download failures or failed validation prevent deployment and leave the last published site intact.

Configure Pages with source GitHub Actions and custom domain playground.joomengine.org. The committed CNAME is copied into the build. Point the domain's DNS CNAME record to joomengine.github.io, then enable HTTPS in Pages once GitHub has provisioned its certificate. Repository environment approvals still apply.

Validation

Run source checks and helper tests after installing dependencies:

npm run check
npm test

After compiling the drivers, validate native PDO against the real upstream PHP and MariaDB packages:

(cd external/bridge && npm ci --ignore-scripts && npm run prepare:engine)
PHP_WASM_MODULE_ROOT="$PWD/node_modules" \
PHP_WASM_EXTENSION_DIR="$PWD/.cache/native" \
node --test external/bridge/native/tests/upstream.test.mjs
node --test test/fileinfo.integration.mjs test/curl.integration.mjs test/sodium.integration.mjs

Build the static site, install the browser engines, and run browser integration:

MARIADB_DRIVER_DIR=.cache/native npm run build
npx playwright install --with-deps chromium firefox
npm run test:provisioning
npm run build:deploys
npm run test:browser
node --test test/version-catalog.browser.mjs

The browser suite uses real PHP, native PDO, MariaDB, and Joomla. It exercises catalog combinations, administrator access, extension installation, configuration, persistence, temporary-site retention, restart, PHP settings, exports, sharing, live header/footer hide-and-restore controls, responsive layout and timeout recovery. The prepared JCB regression creates a Joomla record and changes its configuration file, then verifies both and administrator access after two Save → whole-page reload cycles without Close. Recovery checks verify that exporting files after a database startup failure leaves the saved file and database stores unchanged. PLAYGROUND_BROWSERS, PLAYGROUND_PHP_VERSIONS, PLAYGROUND_JOOMLA_VERSIONS and PLAYGROUND_SCENARIOS narrow local investigations.

CI runs source checks and unit tests first. Documentation-only pull requests skip native/browser jobs. Presentation-only changes run the default Joomla 6.2.0 / PHP 8.4 combination with deployment, lifecycle and Rocket checks. Runtime, deployment, configuration and unclassified changes run the full supported matrix, as do main and manual builds. Chromium and Firefox validate in parallel jobs against the same built artifact. Native/compiler caches require exact source and toolchain identities; downloads retain checksum validation. Provisioning uses bounded concurrency and browser scenarios fail promptly. Pages publishes only the exact artifact whose selected checks passed, and CI retains diagnostic output. A separate Chromium/Firefox version-catalog job installs the actual staged selection packages from that same candidate artifact and retains receipts in test-results/. Its success is required whenever a build is selected; it does not replace the existing runtime or interaction checks. Warm-cache presentation changes reuse already validated native extensions and skip the duplicate complete provisioning suite; runtime changes and native cache misses still execute those contracts.

An installed fixture extension must render its own nested image, stylesheet and script; a separate fixture verifies external resources alongside native database queries. Missing images, scripts, styles and fonts fail validation, with their URLs and browser diagnostics retained. A controlled cross-origin PHP read also verifies that a denied request reports its error promptly and leaves PHP and the database usable. The playground does not replace artwork or hide production errors.

Firefox 157 emits an empty-URL service-worker diagnostic for some successful native redirects, including a minimal Response.redirect() with no playground runtime. The browser suite reproduces that behavior independently, then records it separately only for verified Joomla form and language redirects with the same exact diagnostic. Receipts retain the complete messages and HTTP proof. Other console errors still fail validation, and production console output is not suppressed. The isolated reproduction is in test/firefox-redirect-probe.mjs.

Scope and limitations

This is a browser-local environment for trusted development and demonstrations. Installed extensions and PHP code run with access to that playground’s files and database. Keep independent applications in separate site keys; this is not a multi-tenant hosting boundary.

The bridge supports up to 32 independent PDO connections per MariaDB instance, uses PDO emulated prepares, and does not implement mysqli or remote database connections. Integer values within PHP’s integer range are returned as integers; larger integers and DECIMAL values remain exact strings. PDO::ATTR_STRINGIFY_FETCHES requests numeric strings explicitly. Files and database state are separate stores; they are not committed together as one transaction.

The verified JavaScript CGI adapter supports binary POST, PUT, PATCH and DELETE bodies, including large multipart uploads. It awaits preload completion before restoring a restarted runtime’s files. Request queues, source size, body size and execution time remain bounded. A recoverable PHP application error preserves its HTTP error response and files, resets abandoned database sessions, and prepares PHP for the next request without replaying uncertain writes. On a worker timeout, use the recovery controls or restart the instance.

Host processes, system executables, arbitrary socket services, and a production mail server are not supplied by this static playground. Extensions that require those facilities need a different environment. Installing an extension and passing runtime health checks does not prove every workflow of every Joomla extension is browser-compatible; exercise the particular component operations you plan to demonstrate. Browser storage, WebAssembly memory and CORS still apply.

About

A browser-based Joomla playground with selectable Joomla and PHP versions, automatic extension installation, and configurable startup commands.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages