Playground — Manual
Every Playground feature: three editors, SCSS with Dart Sass, live preview, assets, snippets, export/import, the PHP mode (php-wasm), and the limits.
Back to the overview: Playground · Open the tool: www.jpkc.com/tools/playground/
This manual documents the Playground in full: every editor, every toolbar button, the preview options, persistence, and the limits of the sandbox. The tool's interface is in English, so the button and label names are given here in their original English spelling — exactly what you'll see in the live interface.
Layout of the interface
From top to bottom, the interface has four parts:
- Toolbar (
pg-toolbar) — Run/Live, the PHP switch, Snippets, Export/Import, asset selection, panel toggles, and fullscreen. - Editor row — the three code panels HTML, CSS/SCSS, and JavaScript side by side.
- Divider (
pg-resizer) — a draggable bar you use to shift the height ratio between the editor row and the preview. - Preview (
pg-preview) — the rendered result in the<iframe>, or the HTML source view.
The three editors
Each panel is a standalone ACE editor (opens in a new tab) with syntax highlighting in the "Dracula" theme. Defaults: font size 13, tab width 2 (soft tabs), no line wrapping, no autocompletion. A change in any editor triggers two things: the auto-save after 1.2 seconds (see below) and — when Live is active — a new preview after 1.5 seconds.
HTML editor
The left panel (label HTML) holds your page's body content. What you write here lands in the <body> of the preview document — so you don't need a <!DOCTYPE>, <html>, or <head> scaffold; the Playground adds that itself. You can't pull in libraries from a CDN here, though: the tool page's Content Security Policy (CSP) also applies to the preview and blocks <script src="…"> and stylesheet <link> tags pointing to third-party servers (see Architecture, sandbox, and limits). What you can use are the libraries from the asset dropdown, your own inline code, and stylesheets from Google Fonts.
CSS / SCSS editor
The middle panel (label CSS) holds your styles, which the Playground writes into a <style> block in the preview's <head>. Use the SCSS switch on the right of the panel header to put the editor into SCSS mode — the label and the syntax highlighting then change to SCSS, and the content is compiled to CSS in the browser before every preview. Flipping the switch itself rebuilds the preview after 1.5 seconds, even with Live turned off.
Compilation is done by Dart Sass (opens in a new tab) (version 1.105) — the same module the Compiler uses. That means modern Sass features work: @use 'sass:math' with math.div(), or @use 'sass:color' with color.adjust() and color.scale(). The compiler is lazy-loaded on the first SCSS run; you'll briefly see "Loading SCSS compiler…". If loading fails, the Playground reports "Failed to load SCSS compiler." and tries again on the next run.
A few rules for SCSS mode:
- Output style: expanded (readably indented, not minified).
- Errors: a syntax error doesn't break the preview. You get the message
SCSS error (line N): …with the line number, and instead of your styles the preview contains a CSS comment/* SCSS Error – … */with the error text. - No warnings: because the code is recompiled on every keystroke, Dart Sass runs with a silent logger. You won't see deprecation warnings or the output of
@warnand@debughere — the Compiler shows them. - No files of your own: built-in modules (
sass:math,sass:color,sass:string, …) can be loaded with@use. Your own partials via@use 'file'or@importaren't available because the Playground has no filesystem — such lines end in an SCSS error.
JavaScript editor
The right panel (label JavaScript) holds your script. The Playground places your JS at the end of the <body>, so the DOM is already fully parsed when it runs and you can do without DOMContentLoaded. It wraps the code in a classic <script> with a try { … } catch block, and four things follow from that:
- Function declarations become global. A
function myFunction() {}is reachable from the whole document — which is why inline handlers likeonclick="myFunction()"in the HTML panel work. let,const, andclassstay inside the block. They only exist within thetryblock, so an inline handler in the HTML can't see them. For inline handlers, use function declarations or bind events withaddEventListenerin the JS.- No module code.
import,export, and top-levelawaitare syntax errors in this block. If you need ES modules, put your own<script type="module">in the HTML panel. - Errors on the first pass are caught. If your code throws while it loads, the preview doesn't go down; the message appears in the browser console with the
[Playground JS]prefix. Errors thrown later in event handlers or timers show up there as ordinary errors without the prefix. A syntax error keeps the script from starting at all and is logged without the prefix, too.
Per-panel actions
Each of the three panels has the same actions in its header:
- Font size — minus/plus change the editor font size for that panel (range 10–26, default 13); the current value sits in between.
- Copy — copies the panel's entire content to the clipboard.
- Download — downloads the content as a file (
playground.html,playground.cssor, in SCSS mode,playground.scss,playground.js; in PHP modeplayground.php). An empty panel reports "Editor is empty." - Clear (trash icon) — empties the panel without asking.
Execution: Live mode and Run
Two controls on the left of the toolbar govern how the preview updates:
- Run (green button,
Ctrl/Cmd+Enter) — rebuilds the preview immediately, regardless of Live mode. - Live (checkbox, on by default) — when active, the preview rebuilds automatically as you type, debounced: 1.5 seconds after your last keystroke. Turn Live off and only the Run button updates the preview while you type.
Two controls rebuild the preview regardless of Live: any change in the Assets dropdown (immediately) and the SCSS switch (after 1.5 seconds).
After each run an "Updated" status with the time appears in the preview header, briefly highlighted in green; the text stays until the next run (in PHP mode "Running PHP…" while the run is in progress, then "PHP run"; "PHP error" only appears if an aborted run had already produced output — otherwise "Running PHP…" stays).
The preview
The preview renders a complete HTML document the Playground assembles from your three editors: your HTML into the <body>, your (compiled) CSS into a <style> block, your JS at the end of the <body>. Closing </style> and </script> literals in your code are escaped in the process so they don't prematurely close the surrounding blocks.
Rendered Preview and HTML Source
On the right of the preview header you switch between two views:
- Rendered Preview (eye icon) — the rendered result in the
<iframe>. - HTML Source (code icon) — the complete generated HTML source of the preview document as text. Handy for seeing exactly what the Playground hands to the browser — including the injected assets.
Zoom
Minus/plus in the preview header zoom the preview in fixed steps between 25% and 200% (25, 33, 50, 67, 75, 100, 125, 150, 200%). Zoom only scales the display; the preview document itself still renders at full resolution. Useful to see a whole page at a glance or to enlarge details.
Open in a new tab
The arrow-icon button (Open preview in new tab) opens the current preview document in its own browser tab — where it runs as a normal page, without the sandbox restrictions of the embedded <iframe>. To do this, the Playground writes the document into a blank tab that belongs to the tool page's origin — so code in it has the same rights as the tool page itself, including access to its LocalStorage. The tool page's Content Security Policy still applies there too — scripts and stylesheets from third-party servers stay blocked in the new tab just as in the preview. If a popup blocker stops the tab, a note appears.
In PHP mode the button opens the last rendered result (not the PHP source, which a browser couldn't execute). If there is no result yet, the Playground says "Run PHP first, then open the result in a new tab."
Optional assets
The Assets dropdown (layers icon) injects common front-end libraries into the preview without you linking them yourself. A counter badge on the button shows how many are active. Available:
- Bootstrap CSS — the Bootstrap 5.3 stylesheet (in the
<head>). - Bootstrap JS — the Bootstrap 5.3 JS bundle including Popper (for components such as modals, dropdowns, tooltips).
- Bootstrap Icons — the Bootstrap Icons set (the shipped version is 1.13; the tooltip in the tool still says 1.11).
- jQuery — jQuery 4.0 (in the
<head>, so it's available to your JS). - Dark Mode — sets
data-bs-theme="dark"on the preview's<html>. This option is only selectable when Bootstrap CSS is active; turn Bootstrap CSS off and Dark Mode is disabled automatically.
The CSS assets go in as <link> in the <head>, the JS assets as <script> also in the <head> (jQuery before Bootstrap JS), so they're available once the body is parsed. The files come from the JPKCom server, not from a third-party CDN. Every change in the dropdown rebuilds the preview immediately. The asset selection is persisted and is part of snippets and exports.
Save and restore
Auto-save (LocalStorage)
The Playground continuously saves your state to your browser's LocalStorage — the editor content 1.2 seconds after your last input, settings immediately when you change them. It saves the HTML, CSS, and JS, the CSS mode (CSS/SCSS), the PHP mode, the asset selection, the panel visibility, the font sizes, and the zoom level. Come back later and your last state is there — with one exception: a panel that was empty when saved (say, after Clear) gets the demo content again on the next load; the Playground doesn't restore an empty state. On your very first visit (or after a reset), a small demo example sits in the editors.
Snippets (named slots)
Snippets (floppy-disk icon) opens the "Save & Load Snippets" dialog. Under "Save current snippet" you enter a name (up to 60 characters) and save with Save or Enter. You can keep up to eight snippets, each with HTML, CSS (in SCSS mode the SCSS source), JS, CSS mode, PHP mode, asset selection, and the save date. A name that's already taken overwrites the existing entry without asking; new snippets appear at the top of the list. Once the limit is reached, the Playground reports "Maximum 8 slots reached. Delete one first."
Under "Saved Snippets" each entry shows its name, date, and the character count per panel, plus the Load and Del buttons. Load replaces your current working state without asking, restores the CSS mode, PHP mode, and assets, and closes the dialog. Del deletes right away, also without asking. Snippets live in LocalStorage, too.
Reset
The reset button (circular arrow, Reset to defaults) — after a confirmation — resets all editors, the CSS mode, the assets, the panel visibility, the font sizes, and the zoom to their factory defaults, switches PHP mode off, returns to the Rendered Preview, and loads the demo example. Saved snippets are kept — reset only clears the current working state.
Export and import
Export HTML
Export HTML downloads the complete current state as a standalone .html file (playground.html) — a full document with your HTML, the (compiled) CSS, and your JS. The file also runs outside the Playground in any browser, without the tool page's Content Security Policy. It doesn't embed the active assets but links them by absolute URL from the JPKCom server — without a network connection, Bootstrap, the icons, and jQuery are missing. It additionally contains invisible markers (@@playground-…@@ comments and the asset selection as JSON) by which the Playground later recognizes it.
In SCSS mode, the file contains the compiled CSS — neither the SCSS source nor the CSS mode is exported. To keep the SCSS source, save it as a snippet or use the CSS panel's Download (playground.scss).
Import HTML
Import HTML reads a previously exported Playground file (.html) back in: the Playground finds the markers, extracts HTML, CSS, and JS back into the respective editors, restores the saved asset selection, and switches PHP mode on or off to match the flag in the file. The CSS mode stays as it currently is. A file without those markers is rejected with "No Playground markers found." — so only files exported from this Playground can be imported, not arbitrary HTML.
PHP mode (in-browser PHP)
The PHP switch on the left of the toolbar (next to Run/Live) turns the Playground into a full PHP editor. Switch it on and a real PHP 8.4 runs in the browser — via php-wasm (opens in a new tab), a WebAssembly port of PHP (Apache-2.0). There's no server; your code is sent nowhere.
What changes in PHP mode
Once the switch is on, the interface adapts:
- The HTML panel is now labelled HTML+PHP and switches its syntax highlighting to PHP. Here you write mixed HTML+PHP code, exactly like in a
.phpfile — literal text outside<?php … ?>is output, the PHP code in between is executed. - The Run button becomes Run PHP, and the Live checkbox disappears: in PHP mode there is no automatic preview as you type — you always rebuild deliberately with Run PHP (or
Ctrl/Cmd+Enter). Switch PHP mode off again and the checkbox comes back, but unticked — tick it again (or reload the page) to get the automatic preview back. - A new PHP Log button appears (see below).
Heads-up: a few actions run your code once even without a click on Run PHP — switching PHP mode on, loading the page while PHP mode is active, loading a PHP snippet, importing a PHP file, any change in the Assets dropdown, and the SCSS switch. Only typing never triggers a run.
The CSS and JavaScript panels stay as they are: the Playground wraps your styles and scripts around the PHP output just like in normal mode. You don't have to write anything special in your PHP code for that.
How the PHP preview is built
When you click Run PHP, the Playground executes the HTML+PHP code and takes its output (the HTML that PHP produces). From that it assembles — as in normal mode — a complete preview document: your CSS into a <style> block, your JS at the end of the body, the active assets into the <head>. If your PHP already outputs a complete HTML document (<!doctype>/<html>), the Playground splices styles, scripts, and assets into the right places; otherwise it treats the output as a body fragment. The result lands in the same sandboxed preview as ever.
Every run starts fresh: before executing, the Playground resets php-wasm's interpreter and virtual filesystem, so variables or files from the previous run are gone. While a run is in progress, the Run PHP button is disabled and a second trigger is ignored. If execution aborts with an exception after some output has already been produced, the preview shows that partial output with the status "PHP error". If there was no output yet — for instance because the PHP engine doesn't load — the previous preview stays unchanged. Either way, the message goes into the PHP Log, and an error notification "PHP: …" appears as well.
Run PHP instead of Live — and why
Unlike HTML/CSS/JS, PHP runs via WebAssembly on the browser's main thread, not in a background worker. That has a price: an actual PHP infinite loop (while (true)) would block the tab, because WebAssembly runs synchronously and can't be aborted from the outside. That's exactly why PHP mode replaces the live preview with the manual Run PHP button — you keep control over when code runs, and never accidentally start a running infinite loop just by typing.
PHP Log (error log)
To keep the preview free of error markup, PHP is configured so that errors are not written into the output but logged (display_errors=Off, log_errors=On, error_reporting=E_ALL). The PHP Log button shows the contents of that log in a dialog: all warnings, notices, fatals, and parse errors from the last run — plus your own error_log() calls, each with the correct line number. A red counter badge on the button shows how many lines the log holds. Copy in the dialog puts the log on your clipboard; with no entries, the dialog says "No errors, warnings or notices." If the output stays empty while the log has entries, the note "PHP produced no output — see PHP Log." points you there.
Loading and unloading
The PHP engine is large (around 13 MB of WebAssembly) and is therefore loaded only when you activate PHP mode — not when you open the page; you'll see the note "Loading PHP (php-wasm)… this downloads ~13 MB on first use." If loading fails, the Playground tries again on the next run. It remembers that PHP mode was on; after a reload it loads the engine automatically. Turn PHP off again and the Playground releases the engine.
Export, import, and snippets in PHP mode
The PHP state can be saved too, with a few specifics:
- Export HTML in PHP mode writes the raw HTML+PHP source into the file (
playground.php.html) and records that it's PHP. You can import this file again — but, unlike a normal export, it's not runnable as a finished page in the browser (it contains unexecuted PHP). - On import of such a file, the Playground recognizes the PHP marker and switches PHP mode back on automatically.
- Snippets store the PHP mode along with the rest; load a PHP snippet and the mode is active again.
- The download of the HTML+PHP panel saves as a
.phpfile accordingly.
Requirements and limits
- One-time download. On first activation around 13 MB is loaded — that needs an internet connection and a moment. After that the engine is in the browser cache.
- No server environment. PHP itself runs, but without a web server, without a database, and without filesystem access to your machine. The mode is meant for trying out PHP logic, functions, and snippets — not as a replacement for a real PHP environment.
- Infinite loops block the tab. See above — run suspect loops deliberately and under control with Run PHP.
Layout: panels, divider, fullscreen
- Panels — the
HTML,CSS,JStoggles (thePanels:group) hide or show individual editors. That lets you focus on CSS only, for example, and give the preview more room. With all three off, the editor row collapses entirely. The selection is saved. - Divider — the bar between editors and preview can be dragged up or down with the mouse to change the height ratio. The editor row stays at least 140 pixels tall, the preview at least 80 pixels. The divider can't be dragged by touch.
- Fullscreen — the fullscreen button (
F11) lays the Playground over the entire browser window (it's not the browser's own fullscreen);EscorF11again leaves the mode. Dialogs such as Snippets and PHP Log still appear on top in fullscreen. - Narrow screens — below 768 pixels wide, the three editors stack vertically instead of sitting side by side.
Keyboard shortcuts
Ctrl/Cmd+Enter— rebuild the preview (Run; in PHP mode Run PHP).F11— toggle fullscreen.Esc— exit fullscreen.
Architecture, sandbox, and limits
The Playground is purely client-side. Your code is not sent to a server; the preview is assembled in the browser and loaded into a sandbox <iframe>. The sandbox specifically allows allow-scripts, allow-forms, allow-modals, and allow-popups — enough for your JS, forms, prompt/alert, and popups to work — but not access to the host page. So the preview code can't reach the Playground or your data there. On top of that, the preview inherits the tool page's Content Security Policy; the list below covers what follows from that. The SCSS compilation also runs locally via the lazy-loaded Dart Sass.
A few limits follow from this that are worth knowing:
- Third-party scripts and stylesheets are blocked. The preview inherits the tool page's Content Security Policy — in the
<iframe>as well as in the new tab. So the browser won't load a<script src>or stylesheet<link>pointing to a third-party server (a CDN, say). Allowed are the libraries from the asset dropdown, inline<script>and<style>, stylesheets and fonts from Google Fonts, and images viahttps:.fetch()againsthttps:APIs is permitted but subject to CORS. The policy likewise blocks third-party pages embedded via<iframe>(a video embed, say), audio and video from third-party servers, fonts from third-party servers other than Google Fonts, and<object>/<embed>. - No
eval(), no forms to third-party addresses. The same policy blockseval()andnew Function(), and the preview may not submit forms to third-party addresses (form-action 'self'). An exported file that you open outside the Playground isn't subject to this policy. - Storage is browser- and device-bound. Auto-save and snippets live in LocalStorage. A different browser, a different device, private mode, or cleared browser data means your state isn't there — or is gone. For permanent keeping, use Export HTML.
- Eight snippet slots. No more than eight named snippets; export anything beyond that as a file.
- The "new tab" is not sandboxed. Code opened via
Open preview in new tabruns as a normal page in the tool page's origin, without the<iframe>restrictions but still under the Content Security Policy — useful for full-fledged testing, but don't open code there that you don't trust. - SCSS without files of your own and without warnings. Built-in Sass modules work, your own partials don't; warnings and
@debugoutput stay silent. - Export contains compiled CSS. SCSS source doesn't survive export and import — use snippets or the panel download for that.
- The JS panel is a classic script. No
import/export, andlet/constonly within their own block (see JavaScript editor). - Import only for Playground files. Only files produced by Export HTML (with markers) can be re-imported.
- PHP runs outside the sandbox. In PHP mode, PHP is executed via WebAssembly on the main thread (not in the
<iframe>); only its HTML output moves into the sandbox. A PHP infinite loop can therefore block the tab — more on that under PHP mode.
For the introduction and the audiences, see the overview page. Concrete runs are in the examples, strategy and pitfalls in the tips & tricks. You can try all of it directly in the tool.