Created
July 22, 2026 10:42
-
-
Save bgrgicak/a271c24c9d8a9e3eaa229335bac92cb4 to your computer and use it in GitHub Desktop.
WP Doom Block Playground blueprint mirror (responsive fix)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "$schema": "https://playground.wordpress.net/blueprint-schema.json", | |
| "preferredVersions": { | |
| "php": "8.3", | |
| "wp": "latest" | |
| }, | |
| "features": { | |
| "networking": true | |
| }, | |
| "landingPage": "/doom-block/", | |
| "meta": { | |
| "title": "Try WP Doom Block in Playground", | |
| "author": "Bero / Gil", | |
| "description": "Installs WP Doom Block and loads a page with the block already inserted." | |
| }, | |
| "steps": [ | |
| { | |
| "step": "installPlugin", | |
| "pluginData": { | |
| "resource": "literal:directory", | |
| "name": "wp-doom-block", | |
| "files": { | |
| "wp-doom-block.php": "<?php\n/**\n * Plugin Name: WP Doom Block\n * Description: Adds a Gutenberg block that embeds playable Doom in a post or page.\n * Version: 0.1.0\n * Requires at least: 6.5\n * Requires PHP: 8.0\n * Author: Gil / Hermes\n * License: GPL-2.0-or-later\n * License URI: https://www.gnu.org/licenses/gpl-2.0.html\n * Text Domain: wp-doom-block\n *\n * @package WPDoomBlock\n */\n\ndeclare(strict_types=1);\n\nif (! defined('ABSPATH')) {\n exit;\n}\n\nrequire_once __DIR__ . '/includes/render.php';\n\nfunction wp_doom_block_register(): void {\n $dir = __DIR__ . '/build';\n\n register_block_type(\n $dir,\n [\n 'render_callback' => 'wp_doom_block_render',\n ]\n );\n}\nadd_action('init', 'wp_doom_block_register');\n", | |
| "README.md": "# WP Doom Block\n\nA WordPress plugin that adds a Gutenberg block for embedding playable DOOM in a post or page.\n\n## Try it in WordPress Playground\n\n> ## [Launch the WP Doom Block demo in WordPress Playground](https://playground.wordpress.net/?blueprint-url=https%3A%2F%2Fgist.githubusercontent.com%2Fbgrgicak%2F0cdb0637bc50476daed943ed1b0b22a5%2Fraw%2Fdf4a297ae172eed59e44dfd379046afa54f6075d%2Ftry-wp-doom-block-in-playground.json)\n>\n> The source blueprint lives in `blueprints/try-wp-doom-block-in-playground.json` inside this repo.\n>\n> The repo is currently private, so the link above uses a tested public mirror of that blueprint for Playground to fetch.\n\n## Blueprints\n\n- `blueprints/try-wp-doom-block-in-playground.json` \u2014 self-contained demo blueprint for browser Playground links. It installs the plugin and opens a page with the DOOM block already inserted.\n- `blueprints/use-mounted-local-plugin-in-playground-cli.json` \u2014 local development blueprint for Playground CLI. It assumes the plugin is mounted from your working tree, activates it, and seeds the demo page content.\n\n## Development with WordPress Playground CLI\n\nUse the local-development blueprint when you want Playground to run your **mounted local plugin**, not the self-contained browser demo copy.\n\n### Prerequisites\n\n- Node.js 20.18+\n- `npm` / `npx`\n\n### Start a local Playground with the mounted plugin\n\nRun this from the plugin root:\n\n```bash\ncd /path/to/wp-doom-block\nnode -v\nnpx @wp-playground/cli@latest server \\\n --port=9400 \\\n --mount-before-install=\"$(pwd):/wordpress/wp-content/plugins/wp-doom-block\" \\\n --blueprint=./blueprints/use-mounted-local-plugin-in-playground-cli.json\n```\n\nWhy `--mount-before-install` matters:\n\n- the blueprint activates `wp-doom-block/wp-doom-block.php`\n- the plugin must already exist inside `/wordpress/wp-content/plugins/wp-doom-block`\n- mounting before install makes the plugin available when the blueprint runs\n\nOnce Playground boots, it should open `/doom-block/` with the DOOM block already inserted on the page.\n\n### Useful resets\n\nIf you want a fresh Playground state, rerun the same command. If you hit CLI issues, check the latest help output:\n\n```bash\nnpx @wp-playground/cli@latest server --help\nnpx @wp-playground/cli@latest run-blueprint --help\n```\n\n## Inspiration\n\nThis block was inspired by Rhys Wynne\u2019s work on bringing DOOM into WordPress and WordPress Playground.\n\n- Author: Rhys Wynne\n- Blog post: [Can WordPress run Doom? (of course it can, here's how)](https://dwinrhys.com/2024/05/08/can-wordpress-run-doom-of-course-it-can-heres-how/)\n- Related original plugin/repo: [rhyswynne/wpdoom](https://github.com/rhyswynne/wpdoom)\n\nThis plugin is a separate Gutenberg block implementation and does not reuse the original shortcode-based plugin architecture.\n\n## What this plugin does\n\n- Registers a Gutenberg block named `create-block/wp-doom-block`\n- Renders a start button that lazy-loads a DOOM iframe on the front end\n- Lets the editor configure the game URL, frame height, and button text\n\n## Local structure\n\n- `wp-doom-block.php` \u2014 plugin bootstrap and block registration\n- `includes/render.php` \u2014 server-side render helpers\n- `build/` \u2014 block metadata and compiled assets\n- `blueprints/` \u2014 Playground blueprints for browser demos and local CLI development\n- `tests/run.php` \u2014 lightweight verification script\n\n## Verification\n\nRun:\n\n```bash\nphp tests/run.php\n```\n\nExpected output:\n\n```text\nAll tests passed\n```\n", | |
| "includes": { | |
| "render.php": "<?php\n\ndeclare(strict_types=1);\n\nfunction wp_doom_block_escape_url(string $value): string {\n return function_exists('esc_url') ? esc_url($value) : htmlspecialchars($value, ENT_QUOTES, 'UTF-8');\n}\n\nfunction wp_doom_block_escape_attr(string $value): string {\n return function_exists('esc_attr') ? esc_attr($value) : htmlspecialchars($value, ENT_QUOTES, 'UTF-8');\n}\n\nfunction wp_doom_block_escape_html(string $value): string {\n return function_exists('esc_html') ? esc_html($value) : htmlspecialchars($value, ENT_QUOTES, 'UTF-8');\n}\n\nfunction wp_doom_block_render_markup(array $attributes, string $wrapperAttributes = ''): string {\n $defaults = [\n 'gameUrl' => 'https://js-dos.com/games/doom.exe.html',\n 'height' => 600,\n 'startButtonText' => 'Click to play DOOM',\n ];\n\n $attributes = array_merge($defaults, $attributes);\n\n $height = is_numeric($attributes['height']) ? max(240, (int) $attributes['height']) : 600;\n $gameUrl = wp_doom_block_escape_url((string) $attributes['gameUrl']);\n $buttonText = wp_doom_block_escape_html((string) $attributes['startButtonText']);\n $baseWidth = 800;\n\n $wrapperAttributes = trim($wrapperAttributes);\n if ($wrapperAttributes === '') {\n $wrapperAttributes = 'class=\"wp-block-create-block-wp-doom-block wp-doom-block\"';\n }\n\n return sprintf(\n '<div %1$s data-game-url=\"%2$s\">'\n . '<div class=\"wp-doom-block__shell\" style=\"--wp-doom-block-height:%3$dpx\" data-doom-shell>'\n . '<button type=\"button\" class=\"wp-doom-block__start-button\" data-doom-start>%4$s</button>'\n . '<div class=\"wp-doom-block__viewport\" data-doom-viewport hidden>'\n . '<iframe class=\"wp-doom-block__iframe\" title=\"DOOM\" loading=\"lazy\" allowfullscreen data-doom-frame data-src=\"%2$s\" data-base-width=\"%5$d\" data-base-height=\"%3$d\"></iframe>'\n . '</div>'\n . '</div>'\n . '</div>',\n $wrapperAttributes,\n $gameUrl,\n $height,\n $buttonText,\n $baseWidth\n );\n}\n\nfunction wp_doom_block_render(array $attributes, string $content = '', $block = null): string {\n $wrapperAttributes = function_exists('get_block_wrapper_attributes')\n ? get_block_wrapper_attributes([\n 'class' => 'wp-doom-block',\n ])\n : 'class=\"wp-block-create-block-wp-doom-block wp-doom-block\"';\n\n return wp_doom_block_render_markup($attributes, $wrapperAttributes);\n}\n" | |
| }, | |
| "build": { | |
| "block.json": "{\n \"$schema\": \"https://schemas.wp.org/trunk/block.json\",\n \"apiVersion\": 3,\n \"name\": \"create-block/wp-doom-block\",\n \"version\": \"0.1.0\",\n \"title\": \"DOOM\",\n \"category\": \"widgets\",\n \"icon\": \"games\",\n \"description\": \"Embed playable DOOM in a post or page.\",\n \"keywords\": [\"doom\", \"game\", \"retro\", \"embed\"],\n \"textdomain\": \"wp-doom-block\",\n \"attributes\": {\n \"gameUrl\": {\n \"type\": \"string\",\n \"default\": \"https://js-dos.com/games/doom.exe.html\"\n },\n \"height\": {\n \"type\": \"number\",\n \"default\": 600\n },\n \"startButtonText\": {\n \"type\": \"string\",\n \"default\": \"Click to play DOOM\"\n }\n },\n \"editorScript\": \"file:./index.js\",\n \"viewScript\": \"file:./view.js\",\n \"style\": \"file:./style.css\"\n}\n", | |
| "index.asset.php": "<?php\nreturn [\n 'dependencies' => [\n 'wp-blocks',\n 'wp-block-editor',\n 'wp-components',\n 'wp-element',\n 'wp-i18n',\n ],\n 'version' => '0.1.0',\n];\n", | |
| "index.js": "( function ( blocks, blockEditor, components, element, i18n ) {\n var el = element.createElement;\n var useBlockProps = blockEditor.useBlockProps;\n var InspectorControls = blockEditor.InspectorControls;\n var PanelBody = components.PanelBody;\n var RangeControl = components.RangeControl;\n var TextControl = components.TextControl;\n var __ = i18n.__;\n\n blocks.registerBlockType( 'create-block/wp-doom-block', {\n edit: function ( props ) {\n var attributes = props.attributes;\n var setAttributes = props.setAttributes;\n var blockProps = useBlockProps( {\n className: 'wp-doom-block-editor',\n } );\n\n return [\n el(\n InspectorControls,\n { key: 'inspector' },\n el(\n PanelBody,\n { title: __( 'DOOM settings', 'wp-doom-block' ), initialOpen: true },\n el( TextControl, {\n label: __( 'Game URL', 'wp-doom-block' ),\n value: attributes.gameUrl || 'https://js-dos.com/games/doom.exe.html',\n onChange: function ( value ) {\n setAttributes( { gameUrl: value } );\n },\n help: __( 'Swap in another js-dos compatible page if you want a different build.', 'wp-doom-block' ),\n } ),\n el( RangeControl, {\n label: __( 'Frame height', 'wp-doom-block' ),\n value: attributes.height || 600,\n onChange: function ( value ) {\n setAttributes( { height: value } );\n },\n min: 240,\n max: 1000,\n } ),\n el( TextControl, {\n label: __( 'Start button text', 'wp-doom-block' ),\n value: attributes.startButtonText || 'Click to play DOOM',\n onChange: function ( value ) {\n setAttributes( { startButtonText: value } );\n },\n } )\n )\n ),\n el(\n 'div',\n Object.assign( { key: 'preview' }, blockProps ),\n el( 'div', { className: 'wp-doom-block__shell', style: { minHeight: ( attributes.height || 600 ) + 'px' } },\n el( 'p', { className: 'wp-doom-block__eyebrow' }, __( 'Playable DOOM block', 'wp-doom-block' ) ),\n el( 'h3', null, 'DOOM' ),\n el( 'p', null, __( 'The front end renders a start button that lazy-loads the game iframe.', 'wp-doom-block' ) ),\n el( 'p', null, __( 'Source:', 'wp-doom-block' ) + ' ' + ( attributes.gameUrl || 'https://js-dos.com/games/doom.exe.html' ) ),\n el( 'button', { type: 'button', className: 'wp-doom-block__start-button', disabled: true }, attributes.startButtonText || 'Click to play DOOM' )\n )\n )\n ];\n },\n save: function () {\n return null;\n },\n } );\n} )( window.wp.blocks, window.wp.blockEditor, window.wp.components, window.wp.element, window.wp.i18n );\n", | |
| "style.css": ".wp-block-create-block-wp-doom-block,\n.wp-doom-block-editor {\n box-sizing: border-box;\n width: 100%;\n max-width: 100%;\n}\n\n.wp-block-create-block-wp-doom-block *,\n.wp-doom-block-editor * {\n box-sizing: border-box;\n}\n\n.wp-doom-block__shell {\n display: flex;\n width: 100%;\n max-width: 100%;\n min-height: var(--wp-doom-block-height, 600px);\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n gap: 1rem;\n padding: 1.5rem;\n border-radius: 16px;\n overflow: hidden;\n background: radial-gradient(circle at top, #2f2f2f 0%, #111 58%, #000 100%);\n color: #f7f0d0;\n box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08);\n}\n\n.wp-doom-block__eyebrow {\n margin: 0;\n font-size: 0.8rem;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #ffcc66;\n}\n\n.wp-doom-block__start-button {\n align-self: center;\n border: 0;\n border-radius: 999px;\n padding: 0.9rem 1.35rem;\n font-weight: 700;\n cursor: pointer;\n background: linear-gradient(180deg, #ff7b2f 0%, #c93c00 100%);\n color: #fff;\n}\n\n.wp-doom-block__start-button[disabled] {\n cursor: default;\n opacity: 1;\n}\n\n.wp-doom-block__viewport {\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n}\n\n.wp-doom-block__iframe {\n display: block;\n width: 800px;\n max-width: none;\n height: var(--wp-doom-block-height, 600px);\n border: 0;\n border-radius: 12px;\n background: #000;\n transform-origin: top left;\n}\n\n@media (max-width: 782px) {\n .wp-doom-block__shell {\n padding: 1rem;\n }\n}\n", | |
| "view.asset.php": "<?php\nreturn [\n 'dependencies' => [],\n 'version' => '0.1.0',\n];\n", | |
| "view.js": "function wpDoomBlockResize(shell) {\n if (!shell) {\n return;\n }\n\n var viewport = shell.querySelector('[data-doom-viewport]');\n var iframe = shell.querySelector('[data-doom-frame]');\n if (!viewport || !iframe) {\n return;\n }\n\n var baseWidth = parseInt(iframe.dataset.baseWidth || '800', 10);\n var baseHeight = parseInt(iframe.dataset.baseHeight || '600', 10);\n var availableWidth = viewport.clientWidth;\n\n if (!availableWidth || !baseWidth || !baseHeight) {\n return;\n }\n\n var scale = Math.min(1, availableWidth / baseWidth);\n\n iframe.style.width = baseWidth + 'px';\n iframe.style.height = baseHeight + 'px';\n iframe.style.transform = 'scale(' + scale + ')';\n\n viewport.style.height = baseHeight * scale + 'px';\n}\n\nfunction wpDoomBlockBind(shell) {\n if (!shell || shell.dataset.doomBound === 'true') {\n return;\n }\n\n shell.dataset.doomBound = 'true';\n\n var viewport = shell.querySelector('[data-doom-viewport]');\n var iframe = shell.querySelector('[data-doom-frame]');\n if (!viewport || !iframe) {\n return;\n }\n\n if (typeof ResizeObserver !== 'undefined') {\n var observer = new ResizeObserver(function () {\n wpDoomBlockResize(shell);\n });\n observer.observe(shell);\n observer.observe(viewport);\n } else {\n window.addEventListener('resize', function () {\n wpDoomBlockResize(shell);\n });\n }\n\n wpDoomBlockResize(shell);\n}\n\ndocument.querySelectorAll('[data-doom-shell]').forEach(wpDoomBlockBind);\n\ndocument.addEventListener('click', function (event) {\n var button = event.target.closest('[data-doom-start]');\n if (!button) {\n return;\n }\n\n var shell = button.closest('[data-doom-shell]');\n if (!shell) {\n return;\n }\n\n var viewport = shell.querySelector('[data-doom-viewport]');\n var iframe = shell.querySelector('[data-doom-frame]');\n if (!viewport || !iframe) {\n return;\n }\n\n if (!iframe.getAttribute('src')) {\n iframe.setAttribute('src', iframe.dataset.src || 'https://js-dos.com/games/doom.exe.html');\n }\n\n viewport.hidden = false;\n iframe.hidden = false;\n button.hidden = true;\n\n wpDoomBlockResize(shell);\n} );\n" | |
| } | |
| } | |
| }, | |
| "options": { | |
| "activate": true | |
| }, | |
| "ifAlreadyInstalled": "overwrite" | |
| }, | |
| { | |
| "step": "runPHP", | |
| "code": "<?php\nrequire '/wordpress/wp-load.php';\nupdate_option( 'blogname', 'WP Doom Block Demo' );\nupdate_option( 'blogdescription', 'Playable DOOM inside a Gutenberg block' );\nupdate_option( 'permalink_structure', '/%postname%/' );\n$page_id = wp_insert_post( [\n 'post_title' => 'DOOM Block Demo',\n 'post_name' => 'doom-block',\n 'post_status' => 'publish',\n 'post_type' => 'page',\n 'post_content' => '<!-- wp:create-block/wp-doom-block {\\\"height\\\":600,\\\"startButtonText\\\":\\\"Click to play DOOM\\\"} /-->'\n] );\nif ( is_wp_error( $page_id ) ) {\n throw new Exception( $page_id->get_error_message() );\n}\nupdate_option( 'show_on_front', 'page' );\nupdate_option( 'page_on_front', (int) $page_id );\nflush_rewrite_rules();" | |
| } | |
| ] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment