diff --git a/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx b/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx
index 70b21aa..5dcc0e5 100644
--- a/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx
+++ b/blog/2024-11-15-playing-with-fire/1-introduction/Gasket.jsx
@@ -1,7 +1,7 @@
// Hint: try increasing the iteration count
const iterations = 10000;
-// Hint: negating `x` and `y` also creates some interesting images
+// Hint: negating `x` and `y` creates some interesting images
const functions = [
(x, y) => [x / 2, y / 2],
(x, y) => [(x + 1) / 2, y / 2],
diff --git a/src/theme/Playground/index.tsx b/src/theme/Playground/index.tsx
new file mode 100644
index 0000000..bf2aa21
--- /dev/null
+++ b/src/theme/Playground/index.tsx
@@ -0,0 +1,135 @@
+import React from 'react';
+import clsx from 'clsx';
+import useIsBrowser from '@docusaurus/useIsBrowser';
+import {LiveProvider, LiveEditor, LiveError, LivePreview} from 'react-live';
+import Translate from '@docusaurus/Translate';
+import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import BrowserOnly from '@docusaurus/BrowserOnly';
+import {
+ ErrorBoundaryErrorMessageFallback,
+ usePrismTheme,
+} from '@docusaurus/theme-common';
+import ErrorBoundary from '@docusaurus/ErrorBoundary';
+
+import type {Props} from '@theme/Playground';
+import type {ThemeConfig} from '@docusaurus/theme-live-codeblock';
+
+import styles from './styles.module.css';
+
+function Header({children}: {children: React.ReactNode}) {
+ return
{children}
;
+}
+
+function LivePreviewLoader() {
+ // Is it worth improving/translating?
+ // eslint-disable-next-line @docusaurus/no-untranslated-text
+ return Loading...
;
+}
+
+function Preview() {
+ // No SSR for the live preview
+ // See https://github.com/facebook/docusaurus/issues/5747
+ return (
+ }>
+ {() => (
+ <>
+ (
+
+ )}>
+
+
+
+ >
+ )}
+
+ );
+}
+
+function ResultWithHeader() {
+ return (
+ <>
+
+ {/* https://github.com/facebook/docusaurus/issues/5747 */}
+
+ >
+ );
+}
+
+function ThemedLiveEditor() {
+ const isBrowser = useIsBrowser();
+ return (
+
+ );
+}
+
+function EditorWithHeader() {
+ return (
+ <>
+
+
+ >
+ );
+}
+
+// this should rather be a stable function
+// see https://github.com/facebook/docusaurus/issues/9630#issuecomment-1855682643
+const DEFAULT_TRANSFORM_CODE = (code: string) => `${code};`;
+
+export default function Playground({
+ children,
+ transformCode,
+ ...props
+}: Props): JSX.Element {
+ const {
+ siteConfig: {themeConfig},
+ } = useDocusaurusContext();
+ const {
+ liveCodeBlock: {playgroundPosition},
+ } = themeConfig as ThemeConfig;
+ const prismTheme = usePrismTheme();
+
+ const noInline = props.metastring?.includes('noInline') ?? false;
+
+ return (
+
+
+ {playgroundPosition === 'top' ? (
+ <>
+
+
+ >
+ ) : (
+ <>
+
+
+ >
+ )}
+
+
+ );
+}
diff --git a/src/theme/Playground/styles.module.css b/src/theme/Playground/styles.module.css
new file mode 100644
index 0000000..b9d8031
--- /dev/null
+++ b/src/theme/Playground/styles.module.css
@@ -0,0 +1,43 @@
+.playgroundContainer {
+ margin-bottom: var(--ifm-leading);
+ border-radius: var(--ifm-global-radius);
+ box-shadow: var(--ifm-global-shadow-lw);
+ overflow: hidden;
+}
+
+.playgroundHeader {
+ letter-spacing: 0.08rem;
+ padding: 0.75rem;
+ text-transform: uppercase;
+ font-weight: bold;
+ background: var(--ifm-color-emphasis-200);
+ color: var(--ifm-color-content);
+ font-size: var(--ifm-code-font-size);
+}
+
+.playgroundHeader:first-of-type {
+ background: var(--ifm-color-emphasis-600);
+ color: var(--ifm-color-content-inverse);
+}
+
+.playgroundEditor {
+ font: var(--ifm-code-font-size) / var(--ifm-pre-line-height)
+ var(--ifm-font-family-monospace) !important;
+ /* rtl:ignore */
+ direction: ltr;
+}
+
+.playgroundPreview {
+ padding: 1rem;
+ background-color: var(--ifm-pre-background);
+}
+
+/*
+Docusaurus global CSS applies a `border-radius` to `pre` that leads to a minor graphical issue
+where the "LIVE EDITOR" title bar and code block meet - https://github.com/facebook/docusaurus/issues/6032#issuecomment-2481803877
+
+This change disables the border radius so the edges properly join together
+ */
+.playgroundEditor > pre {
+ border-radius: 0;
+}
\ No newline at end of file