Skip to content

Add HTML backend support to playground#439

Open
aisipos wants to merge 7 commits into
spylang:mainfrom
aisipos:add-html-backend-support-to-playground
Open

Add HTML backend support to playground#439
aisipos wants to merge 7 commits into
spylang:mainfrom
aisipos:add-html-backend-support-to-playground

Conversation

@aisipos

@aisipos aisipos commented Apr 1, 2026

Copy link
Copy Markdown
Contributor

Fixes #425.

Add several features that allow for displaying the HTML backend output in the playground:

  • Add a dropdown selector to choose the backend between WASM and HTML:
image
  • Support being able to await the results of SpyTyper.spy_command. This was needed to know when the HTML output from the compiler was ready.
  • Support using SpyAst.js from the playground. The JS importing in the playground using Pyscript works differently than static HTML files. I implemented two solutions for this. I'm not really sold on either one, so I've left them both in the PR for review. The "relative" option is probably simpler, but the "wheel" option might be more useful for having access to assets from Pyscript itself.
    1. In 68d2d30 I added a "relative" option in addition to "cdn" and "inline" for SpyAst.js. This allows you in include it like so: <script src="spyast/spyast.js"></script>
    2. In 5600b6d included SpyAst.js into the Spy wheel, and statically include it in the generated html by reading it from the wheel in the Pyodide filesystem.
  • Support rendering the HTML backend output into the playground output area, automatically showing either the xterm output when WASM is chosen or the HTML when HTML is chosen:
image
  • Because both the HTML or standard WASM outputs can be large relative to the output size, include a maximize / restore button in the upper right of either the HTML or xterm output area:
image

You can test this locally via:

cd playground && make local && python -m http.server

@aisipos aisipos changed the title Add html backend support to playground Add HTML backend support to playground Apr 1, 2026
@aisipos aisipos requested review from JeffersGlass and antocuni April 1, 2026 06:30

@antocuni antocuni left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you @aisipos.

I have few minor comments:

  1. I think that --spyast-js=relative is good enough, but also including the js in the wheel it's a good idea, so we should keep both changes

  2. I think that "wasm backend" is misleading, because on the playground we never generate wasm (and even if we did, it would be through the "C" backend, we don't have any "wasm backend"). I think that the best is to label it as --format (like the CLI option), and the options should be "default", "spy", "ast" and "html" (--format=spy is valid only for redshift, I think).

  3. I think that "HTML" should be the default format for spy parse in the playground, but I'm happy to be convinced otherwise.

And one major comment: clicking on the HTML nodes doesn't seem to work.
If I click on any collapsible/expandable node, I get this in the console:

Uncaught SecurityError: Failed to execute 'replaceState' on 'History': A history state object with URL 'http://localhost:8000/#s0:4,6,9,11,14,17,18,20,22;s1:4,6,7,8,10,12,13,14,16,17,19,21' cannot be created in a document with origin 'http://localhost:8000' and URL 'about:srcdoc'.
    at _writePageHash (about:srcdoc:205:13)

I think that replaceState is used by spyast.js to make it possible to use the "back" button. If we can keep that behavior it would be awesome, else we might decide to just turn it off for the playground case.

@JeffersGlass

Copy link
Copy Markdown
Contributor

And one major comment: clicking on the HTML nodes doesn't seem to work.

One fix for this is to use an object instead of an iframe:

def _show_html_output(html_content: str) -> None: 
    ltk.find("#terminal").hide()
    ltk.find("#html-output").show()
    blob = ltk.window.Blob.new([html_content], ltk.to_js({"type" : 'text/html'}))
    url = ltk.window.URL.createObjectURL(blob)
    ltk.window.jQuery("#html-frame").prop("data", url)
         '<button class="maximize-btn">⤢</button>'
-        '<iframe id="html-frame" style="width:100%;height:600px;border:none"></iframe>'
+        '<object id="html-frame" type="text/html" style="width:100%;height:600px;border:none"></object>'
         "</div>"

In theory creating a blob and url is redundant, since you could just insert the HTML content directly inside the <object> tag. However, it seems embedding a whole document make it unreadable; you'd have to embed just the contents of the <body> tag. Creating a (relatively small) blog seems simpler than parsing/extracting the body tag contents.

@JeffersGlass

Copy link
Copy Markdown
Contributor

I think that "wasm backend" is misleading, because on the playground we never generate wasm (and even if we did, it would be through the "C" backend, we don't have any "wasm backend"). I think that the best is to label it as --format (like the CLI option), and the options should be "default", "spy", "ast" and "html" (--format=spy is valid only for redshift, I think).

I agree here from a UX perspective - the backend label is a little confusing.

One neat option in the playground would be to always have it run and dispay the results of --format html in addition to the terminal output, whenever a compatible command is run. That was users get the HTML visualization automatically when viewing parsed/redshifted results, without having to enable it specifically.

@JeffersGlass JeffersGlass added the playground Related to the SPy playground label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

playground Related to the SPy playground

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Integrate the HTML backend / AST visualzer in the playground

3 participants