<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://web.dev/</id>
  <title>Thomas Nattestad on web.dev</title>
  <updated>2026-04-15T23:21:06Z</updated>
  <author>
    <name>Thomas Nattestad</name>
  </author>
  <link href="https://web.dev/authors/nattestad/feed.xml" rel="self"/>
  <link href="https://web.dev/"/>
  <icon>https://web-dev.imgix.net/image/admin/UyUsatSDE2wdnfy3KHzO.jpg?auto=format</icon>
  <logo>https://web.dev/images/shared/rss-banner.png</logo>
  <subtitle>Our latest news, updates, and stories by Thomas Nattestad.</subtitle>
  
  
  <entry>
    <title>Build in-browser WordPress experiences with WordPress Playground and WebAssembly</title>
    <link href="https://web.dev/wordpress-playground/"/>
    <updated>2023-04-12T00:00:00Z</updated>
    <id>https://web.dev/wordpress-playground/</id>
    <content type="html" mode="escaped">&lt;p&gt;When you first see &lt;a href=&quot;http://wasm.wordpress.net/&quot; rel=&quot;noopener&quot;&gt;WordPress Playground&lt;/a&gt;, it seems
like an ordinary site–maybe except for the colorful background. It&#39;s anything
but. What you&#39;re actually looking at is an entire WordPress tech stack,
including PHP and a database, running directly in your browser.&lt;/p&gt;
&lt;p&gt;In this post, Adam Zieliński (lead of WordPress Playground) and Thomas Nattestad
(Product Manager for V8) explore:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How WordPress Playground can help you as a WordPress developer.&lt;/li&gt;
&lt;li&gt;How it works under the hood.&lt;/li&gt;
&lt;li&gt;What it means for the future of WordPress.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;use-wordpress-without-installation,-embed-it-in-your-app,-and-even-control-it-with-javascript&quot;&gt;Use WordPress without installation, embed it in your app, and even control it with JavaScript &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#use-wordpress-without-installation,-embed-it-in-your-app,-and-even-control-it-with-javascript&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;You can use and customize the WordPress embedded at
&lt;a href=&quot;http://playground.wordpress.net/&quot; rel=&quot;noopener&quot;&gt;playground.wordpress.net&lt;/a&gt; for free. There&#39;s
no cloud infrastructure and support to pay for, because that site lives entirely
in your browser–no one else can visit it. It&#39;s also temporary. As soon as you
refresh the page, it&#39;s gone. You can get as many of these sites as you want for
prototyping, trying out plugins, and quickly exploring ideas.&lt;/p&gt;
&lt;p&gt;You can even use them to test your code in different environments using the
built-in PHP and WordPress version switcher:&lt;/p&gt;
&lt;img alt=&quot;phpinfo page.&quot; decoding=&quot;async&quot; height=&quot;699&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/tVA8iwBfR187eUUwCLAL.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;WordPress Playground is an entirely new way of using WordPress. Its full power,
however, is only unlocked by including it in your app. The easy way is to embed
WordPress Playground in an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; and configure it using the
&lt;a href=&quot;https://wordpress.github.io/wordpress-playground/pages/embedding-wordpress-playground-on-other-websites.html&quot; rel=&quot;noopener&quot;&gt;query parameters API&lt;/a&gt;.
That&#39;s what the &lt;a href=&quot;https://developer.wordpress.org/playground&quot; rel=&quot;noopener&quot;&gt;official showcase&lt;/a&gt;
does. When you select, for example, the
&lt;a href=&quot;https://wordpress.org/themes/pendant/&quot; rel=&quot;noopener&quot;&gt;Pendant theme&lt;/a&gt; and the
&lt;a href=&quot;https://wordpress.org/plugins/coblocks/&quot; rel=&quot;noopener&quot;&gt;Coblocks plugin&lt;/a&gt;, the embedded iframe
gets updated to point to
&lt;a href=&quot;https://playground.wordpress.net/?theme=pendant&amp;amp;plugin=coblocks&quot; rel=&quot;noopener&quot;&gt;https://playground.wordpress.net/?theme=pendant&amp;amp;plugin=coblocks&lt;/a&gt;.&lt;/p&gt;
&lt;img alt=&quot;WordPress Playground showcase.&quot; decoding=&quot;async&quot; height=&quot;740&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/lPMfWljMKZbMluoN4971.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;The iframe is an easy way of getting started, but it&#39;s also limited to just the
basic configuration option. If you need more than that, there is another, more
powerful API.&lt;/p&gt;
&lt;h3 id=&quot;the-wordpress-playground-javascript-client-enables-full-control-over-the-embedded-site&quot;&gt;The WordPress Playground JavaScript client enables full control over the embedded site &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#the-wordpress-playground-javascript-client-enables-full-control-over-the-embedded-site&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can control the entire WordPress site, including the filesystem and PHP,
using the full API available via the
&lt;a href=&quot;https://www.npmjs.com/package/@wp-playground/client&quot; rel=&quot;noopener&quot;&gt;@wp-playground/client&lt;/a&gt; npm
package. The following example shows to use it—check
&lt;a href=&quot;https://adamadam.blog/2023/04/12/interactive-intro-to-wordpress-playground-public-api/&quot; rel=&quot;noopener&quot;&gt;the interactive tutorial&lt;/a&gt;
for even more examples:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  connectPlayground&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  login&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  connectPlayground&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@wp-playground/client&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; client &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;connectPlayground&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;br /&gt;  document&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;getElementById&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;wp&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// An iframe&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;loadRemote&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;https://playground.wordpress.net/remote.html&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;isReady&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Login the user as admin and go to the post editor:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;login&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;admin&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;password&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;goTo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/wp-admin/post-new.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Run arbitrary PHP code:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; client&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;&amp;lt;?php echo &quot;Hi!&quot;; ?&gt;&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Install a plugin:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; plugin &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;fetchZipFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;installPlugin&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;client&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; plugin&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&quot;use-webassembly-php-even-without-wordpress&quot;&gt;Use WebAssembly PHP even without WordPress &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#use-webassembly-php-even-without-wordpress&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WordPress Playground is not a monolith. WebAssembly PHP is released
independently from WordPress and you can use it separately as well. For the web,
you may use the &lt;a href=&quot;https://www.npmjs.com/package/@php-wasm/web&quot; rel=&quot;noopener&quot;&gt;@php-wasm/web&lt;/a&gt; npm
package optimized for a low bundle size, and in Node.js you can lean
on &lt;a href=&quot;https://www.npmjs.com/package/@php-wasm/node&quot; rel=&quot;noopener&quot;&gt;@php-wasm/node&lt;/a&gt; which provides
more PHP extensions. Adam used the former to add interactive PHP snippets
to &lt;a href=&quot;https://adamadam.blog/2023/02/16/how-to-modify-html-in-a-php-wordpress-plugin-using-the-new-tag-processor-api/&quot; rel=&quot;noopener&quot;&gt;this WP_HTML_Tag_Processor tutorial&lt;/a&gt;.
Here&#39;s a sneak peek of how to use it:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-js&quot;&gt;&lt;code class=&quot;language-js&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PHP&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;@php-wasm/web&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; php &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;token constant&quot;&gt;PHP&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;8.0&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;requestHandler&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;    &lt;span class=&quot;token literal-property property&quot;&gt;documentRoot&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/www&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Create and run a script directly&lt;/span&gt;&lt;br /&gt;php&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;mkdirTree&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/www&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;php&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;writeFile&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&#39;/www/index.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token template-string&quot;&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&amp;lt;?php echo &quot;Hello &quot; . $_POST[&#39;name&#39;]; ?&gt;&lt;/span&gt;&lt;span class=&quot;token template-punctuation string&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;php&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;scriptPath&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/www/index.php&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;// Or use the familiar HTTP concepts:&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; response &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; php&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;POST&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;relativeUrl&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;/index.php&#39;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;  &lt;span class=&quot;token literal-property property&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token literal-property property&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&#39;John&#39;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;br /&gt;console&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;response&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;text&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;token comment&quot;&gt;// Hello John&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;At this point you must be thinking–&lt;em&gt;how does that even work?&lt;/em&gt; Great question!
Let&#39;s dive into the internals and find out. Buckle up!&lt;/p&gt;
&lt;h2 id=&quot;under-the-hood,-theres-webassembly-php,-a-sql-translator,-and-an-in-browser-server&quot;&gt;Under the hood, there&#39;s WebAssembly PHP, a SQL translator, and an in-browser server &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#under-the-hood,-theres-webassembly-php,-a-sql-translator,-and-an-in-browser-server&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;h3 id=&quot;php-runs-as-a-webassembly-binary&quot;&gt;PHP runs as a WebAssembly binary &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#php-runs-as-a-webassembly-binary&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PHP doesn&#39;t just work in the browser out of the box. WordPress Playground
developed a
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/blob/0d451c33936a8db5b7a158fa8aad288c19370a7d/packages/php-wasm/compile/Dockerfile&quot; rel=&quot;noopener&quot;&gt;dedicated pipeline&lt;/a&gt;
to build &lt;a href=&quot;https://github.com/php/php-src&quot; rel=&quot;noopener&quot;&gt;the PHP interpreter&lt;/a&gt; to WebAssembly
using &lt;a href=&quot;https://emscripten.org/docs/porting/networking.html&quot; rel=&quot;noopener&quot;&gt;Emscripten&lt;/a&gt;.
Building vanilla PHP isn&#39;t overly complex–it only takes
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/blob/0d451c33936a8db5b7a158fa8aad288c19370a7d/packages/php-wasm/compile/build-assets/php7.1.patch#L8-L9&quot; rel=&quot;noopener&quot;&gt;adjusting a function signature here&lt;/a&gt;,
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/blob/0d451c33936a8db5b7a158fa8aad288c19370a7d/packages/php-wasm/compile/Dockerfile#L495&quot; rel=&quot;noopener&quot;&gt;forcing a config variable there&lt;/a&gt;,
and applying
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/tree/0d451c33936a8db5b7a158fa8aad288c19370a7d/packages/php-wasm/compile/build-assets&quot; rel=&quot;noopener&quot;&gt;a few small patches&lt;/a&gt;.
Here&#39;s how you can build it yourself:&lt;/p&gt;
&lt;div&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;git&lt;/span&gt; clone https://github.com/WordPress/wordpress-playground&lt;br /&gt;&lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; wordpress-playground &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token comment&quot;&gt;# Below, you can replace &quot;8.2&quot; with any other valid PHP version number.&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;npm&lt;/span&gt; run recompile:php:web:8.2&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;However, vanilla PHP builds aren&#39;t very useful in the browser. As a server
software, PHP doesn&#39;t have a JavaScript API to pass the request body, upload
files, or populate the &lt;code&gt;php://stdin&lt;/code&gt; stream. WordPress Playground had to build
one from scratch. The WebAssembly binary comes with a
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/blob/0d451c33936a8db5b7a158fa8aad288c19370a7d/packages/php-wasm/compile/build-assets/php_wasm.c&quot; rel=&quot;noopener&quot;&gt;dedicated PHP API module&lt;/a&gt;
written in C and a
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground/blob/da38192af57a95699d8731c855b82ac0222df61b/packages/php-wasm/common/src/lib/php.ts&quot; rel=&quot;noopener&quot;&gt;JavaScript PHP class&lt;/a&gt; that
exposes methods like &lt;code&gt;writeFile()&lt;/code&gt; or &lt;code&gt;run()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Because every PHP version is just a static &lt;code&gt;.wasm&lt;/code&gt; file, the PHP version
switcher is actually pretty boring. It simply tells the browser to download, for
example, &lt;code&gt;php_7_3.wasm&lt;/code&gt; instead of, say, &lt;code&gt;php_8_2.wasm&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;database-is-supported-with-a-sql-translation-layer&quot;&gt;Database is supported with a SQL translation layer &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#database-is-supported-with-a-sql-translation-layer&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;WordPress requires MySQL. However, there isn&#39;t a WebAssembly version of MySQL
you could run in the browser. WordPress Playground therefore ships PHP with the
&lt;a href=&quot;https://www.php.net/manual/en/ref.pdo-sqlite.php&quot; rel=&quot;noopener&quot;&gt;native SQLite driver&lt;/a&gt; and
leans on SQLite.&lt;/p&gt;
&lt;p&gt;But how can WordPress run on a different database?&lt;/p&gt;
&lt;p&gt;Behind the scenes, the official
&lt;a href=&quot;https://github.com/WordPress/sqlite-database-integration&quot; rel=&quot;noopener&quot;&gt;SQLite Database Integration&lt;/a&gt;
plugin intercepts all MySQL queries and rewrites them in SQLite dialect. The 2.0
release ships
&lt;a href=&quot;https://github.com/WordPress/sqlite-database-integration/pull/9&quot; rel=&quot;noopener&quot;&gt;a new WordPress Playground-informed translation layer&lt;/a&gt;
that allows WordPress on SQLite to pass 99% of the WordPress unit test suite.&lt;/p&gt;
&lt;h3 id=&quot;the-web-server-lives-inside-the-browser&quot;&gt;The web server lives inside the browser &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#the-web-server-lives-inside-the-browser&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a regular WordPress, clicking on a link, say &lt;em&gt;Blog,&lt;/em&gt; would initiate an HTTP
request to the remote backend to fetch the &lt;code&gt;blog&lt;/code&gt; page. However, WordPress
Playground has no remote backend. It has a
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Service_Worker_API&quot; rel=&quot;noopener&quot;&gt;Service Worker&lt;/a&gt;
that intercepts all the outgoing requests and passes them to an in-browser PHP
instance running in a separate
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Web_Workers_API/Using_web_workers&quot; rel=&quot;noopener&quot;&gt;Web Worker&lt;/a&gt;.&lt;/p&gt;
&lt;img alt=&quot;Flow diagram starting with an iframe pointing at the resource wp-admin, calls to which are intercepted by the service worker, rendered in the worker thread, and ultimately translated to a WordPress response by the in-browser server.&quot; decoding=&quot;async&quot; height=&quot;675&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/EAYGDJ5cBGHFnQuFYjEw.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;h3 id=&quot;networking-is-supported-through-websockets&quot;&gt;Networking is supported through WebSockets &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#networking-is-supported-through-websockets&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When it comes to networking, WebAssembly programs are limited to calling
JavaScript APIs. It is a safety feature, but also presents a challenge. How do
you support low-level, synchronous networking code used by PHP with the
high-level asynchronous APIs available in JavaScript?&lt;/p&gt;
&lt;p&gt;For WordPress Playground, the answer involves a WebSocket to TCP socket proxy,
&lt;a href=&quot;https://emscripten.org/docs/porting/asyncify.html&quot; rel=&quot;noopener&quot;&gt;Asyncify&lt;/a&gt;, and patching deep
PHP internals like &lt;code&gt;php_select&lt;/code&gt;. It&#39;s complex, but there&#39;s a reward. The
Node.js-targeted PHP build can request web APIs, install composer packages, and
even connect to a MySQL server.&lt;/p&gt;
&lt;h2 id=&quot;wordpress-can-be-used-in-even-more-places-than-the-browser&quot;&gt;WordPress can be used in even more places than the browser &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#wordpress-can-be-used-in-even-more-places-than-the-browser&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Since WordPress can now run on WebAssembly, you could also run it in a Node.js
server—it&#39;s the same V8 engine! Of course with StackBlitz you can also run
Node.js directly in the browser, meaning that you could run WordPress and PHP
compiled to WebAssembly, executing in Node.js, which is also compiled to
WebAssembly running
&lt;a href=&quot;https://stackblitz.com/edit/node-zt3hpi?file=todo-list%2Fsrc%2Fedit.js&quot; rel=&quot;noopener&quot;&gt;in the browser&lt;/a&gt;.
WebAssembly is also exploding in popularity in the serverless space, and in the
future this could run on that infrastructure as well.&lt;/p&gt;
&lt;h2 id=&quot;the-future-may-bring-zero-setup,-interactive,-and-collaborative-wordpress-apps&quot;&gt;The future may bring zero-setup, interactive, and collaborative WordPress apps &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wordpress-playground/#the-future-may-bring-zero-setup,-interactive,-and-collaborative-wordpress-apps&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Imagine jumping straight into a code editor where you&#39;re free to just get
building right away, with all of the setup completed. You could even share a
simple link and start a multiplayer editing session, such as in Google Docs. And
when you&#39;re done, it would only take a single click to seamlessly deploy your
creations to a variety of hosting services–all without ever installing anything
locally!&lt;/p&gt;
&lt;p&gt;And that&#39;s just a glimpse! We may see interactive tutorials, live plugin demos,
staging sites, decentralized WordPress on edge servers, and even building
plugins on your phone.&lt;/p&gt;
&lt;p&gt;The future is exciting and you can be a part of it! Your ideas and contributions
are the oxygen of WordPress Playground. Visit
&lt;a href=&quot;https://github.com/WordPress/wordpress-playground&quot; rel=&quot;noopener&quot;&gt;the GitHub repository&lt;/a&gt;, say
hi in the #meta-playground
&lt;a href=&quot;https://make.wordpress.org/chat/&quot; rel=&quot;noopener&quot;&gt;WordPress.org Slack channel&lt;/a&gt;, and feel free
to contact Adam at &lt;a href=&quot;mailto:adam@adamziel.com&quot; rel=&quot;noopener&quot;&gt;adam@adamziel.com&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Adam Zieliński</name>
    </author><author>
      <name>Thomas Nattestad</name>
    </author>
  </entry>
  
  <entry>
    <title>New functionality for developers—brought to you by WebAssembly</title>
    <link href="https://web.dev/wasm-libraries/"/>
    <updated>2023-04-03T00:00:00Z</updated>
    <id>https://web.dev/wasm-libraries/</id>
    <content type="html" mode="escaped">&lt;p&gt;WebAssembly enables developers to bring new performant functionality to the web from other languages. Over the past few years developers have really taken advantage of the possibilities. This post showcases just a few of the shiny new tools that you can benefit from, thanks in part to WebAssembly.&lt;/p&gt;
&lt;h2 id=&quot;tools-and-libraries-you-can-use-now&quot;&gt;Tools and libraries you can use now &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#tools-and-libraries-you-can-use-now&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Without further ado, let&#39;s jump into the good stuff :D&lt;/p&gt;
&lt;h3 id=&quot;sqlite&quot;&gt;SQLite &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#sqlite&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This complete port of SQLite brings a lightweight, embedded, relational database management system into your hands. To learn more read this &lt;a href=&quot;https://developer.chrome.com/blog/sqlite-wasm-in-the-browser-backed-by-the-origin-private-file-system/&quot; rel=&quot;noopener&quot;&gt;blog post that showcases this incredible port and how to use it&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;ffmpegwasm&quot;&gt;FFmpeg.wasm &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#ffmpegwasm&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FFmpeg is a free and open-source software project consisting of a suite of libraries and programs for handling video, audio, and other multimedia files and streams. You can find &lt;a href=&quot;https://ffmpegwasm.netlify.app/&quot; rel=&quot;noopener&quot;&gt;a wasm compiled version here&lt;/a&gt; (&lt;a href=&quot;https://github.com/ffmpegwasm/ffmpeg.wasm&quot; rel=&quot;noopener&quot;&gt;github repo&lt;/a&gt;) that lets you do all of this functionality directly in the browser.&lt;/p&gt;
&lt;h3 id=&quot;universal-scene-description-usd&quot;&gt;Universal Scene Description (USD) &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#universal-scene-description-usd&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Universal Scene Description (USD) is a framework for 3D computer graphics data that focuses on collaboration, non-destructive editing, and enabling multiple views and opinions about graphics data. It&#39;s an industry standard supported by the likes of Pixar, Autodesk, Nvidia, and many more. It&#39;s still early days for their web support but &lt;a href=&quot;https://www.keanw.com/2022/02/autodesk-open-sources-web-based-usd-viewing-implementation.html&quot; rel=&quot;noopener&quot;&gt;Autodesk already open sourced a web based USD viewer&lt;/a&gt; which you can &lt;a href=&quot;https://github.com/autodesk-forks/USD/tree/hdJavaScript&quot; rel=&quot;noopener&quot;&gt;see here&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;canvaskit&quot;&gt;CanvasKit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#canvaskit&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://skia.org/docs/user/modules/canvaskit/&quot; rel=&quot;noopener&quot;&gt;CanvasKit&lt;/a&gt; is Skia, the rendering engine of Chrome and Android, compiled directly to WebAssembly. With it, you get simple JavaScript API access to practically all the power of the Skia rendering engine. The functionality includes complex rendering, text shaping, animation, inking, and more. Check out the &lt;a href=&quot;https://www.npmjs.com/package/canvaskit-wasm&quot; rel=&quot;noopener&quot;&gt;npm package&lt;/a&gt; and &lt;a href=&quot;https://skia.org/docs/user/modules/quickstart/&quot; rel=&quot;noopener&quot;&gt;quickstart guide&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;tensorflowjs&quot;&gt;TensorFlow.js &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#tensorflowjs&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.tensorflow.org/js&quot; rel=&quot;noopener&quot;&gt;TensorFlow.js&lt;/a&gt; brings the power of TensorFlow directly into the browser with a simple JavaScript API. Under the hood, it optimizes models both across the GPU and CPU (including SIMD optimizations) to maximize performance. You can see the &lt;a href=&quot;https://www.tensorflow.org/js/tutorials&quot; rel=&quot;noopener&quot;&gt;getting started guide&lt;/a&gt; or look at &lt;a href=&quot;https://www.tensorflow.org/js/demos&quot; rel=&quot;noopener&quot;&gt;some of their demos directly&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;opencv&quot;&gt;OpenCV &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#opencv&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;OpenCV is an industry standard of programming functions mainly for real-time computer vision. There is an &lt;a href=&quot;https://www.npmjs.com/package/opencv-wasm&quot; rel=&quot;noopener&quot;&gt;easy-to-use npm package here&lt;/a&gt;, and for Emscripten users there are also &lt;a href=&quot;https://docs.opencv.org/4.x/d4/da1/tutorial_js_setup.html&quot; rel=&quot;noopener&quot;&gt;detailed instructions for doing a full build&lt;/a&gt;. For a look at how SIMD and threads are improving performance of these workloads, you can watch &lt;a href=&quot;https://youtu.be/kZrl91SPSpc?t=688&quot; rel=&quot;noopener&quot;&gt;this section of the Modern WebAssembly Chrome Dev Summit talk&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;cocos&quot;&gt;Cocos &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#cocos&quot;&gt;#&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.cocos.com/en&quot; rel=&quot;noopener&quot;&gt;Cocos&lt;/a&gt; is a powerful and popular game engine that enables developers to build games with cross platform support and this now includes the web. It joins the long list of game engines that enable web export through wasm. To get started, jump into the Cocos editor and follow &lt;a href=&quot;https://docs.cocos.com/creator/2.3/manual/en/publish/publish-web.html&quot; rel=&quot;noopener&quot;&gt;these instructions&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/wasm-libraries/#conclusion&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In addition to these specific examples, there is much to be excited about in terms of &lt;a href=&quot;https://blog.chromium.org/2023/04/how-webassembly-is-accelerating-new-web.html&quot; rel=&quot;noopener&quot;&gt;WebAssembly&#39;s potential to change the pace of new web functionality&lt;/a&gt;. Chrome has even set up &lt;a href=&quot;https://developer.chrome.com/blog/advanced-web-apps-fund/&quot; rel=&quot;noopener&quot;&gt;the Advanced Web Apps Fund&lt;/a&gt; that can help developers fund their work to advance the web functionality available to all developers!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Hero image from &lt;a href=&quot;https://www.pexels.com/photo/low-angle-photography-of-library-1296000/&quot; rel=&quot;noopener&quot;&gt;Pexels&lt;/a&gt;, by &lt;a href=&quot;https://www.pexels.com/@ann-marie-kennon-547933/&quot; rel=&quot;noopener&quot;&gt;Ann Marie Kennon&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
</content>
    <author>
      <name>Thomas Nattestad</name>
    </author>
  </entry>
  
  <entry>
    <title>Photoshop&#39;s journey to the web</title>
    <link href="https://web.dev/ps-on-the-web/"/>
    <updated>2021-10-26T00:00:00Z</updated>
    <id>https://web.dev/ps-on-the-web/</id>
    <content type="html" mode="escaped">&lt;p&gt;Over the last three years, Chrome has been working to empower web applications that want to push the boundaries of what&#39;s possible in the browser. One such web application has been Photoshop. The idea of running software as complex as Photoshop directly in the browser would have been hard to imagine just a few years ago. However, by using various new web technologies, Adobe has now brought a public beta of Photoshop to the web.&lt;/p&gt;
&lt;div class=&quot;youtube&quot;&gt;  &lt;lite-youtube videoid=&quot;CF5zZZy0R9U&quot;&gt;  &lt;/lite-youtube&gt;&lt;/div&gt;
&lt;p&gt;(If you prefer watching over reading, this article is also available as a
&lt;a href=&quot;https://www.youtube.com/watch?v=CF5zZZy0R9U&quot; rel=&quot;noopener&quot;&gt;video&lt;/a&gt;.)&lt;/p&gt;
&lt;img alt=&quot;The Photoshop web app running in a browser with an image showing an elephant on the canvas and the &amp;#x27;selection tools&amp;#x27; menu item open.&quot; decoding=&quot;async&quot; height=&quot;500&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/kfFAUTzDHzvE3hXISyQO.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;In this post, we&#39;d like to share for the first time the details of how our collaboration is extending Photoshop to the web. You can use all the APIs Adobe used and more in your own apps as well. Be sure to check out our &lt;a href=&quot;https://web.dev/tags/capabilities/&quot;&gt;web capabilities related blog posts&lt;/a&gt; for inspiration and watch our &lt;a href=&quot;https://fugu-tracker.web.app/&quot; rel=&quot;noopener&quot;&gt;API tracker&lt;/a&gt; for the latest and greatest we&#39;re working on.&lt;/p&gt;
&lt;h2 id=&quot;why-photoshop-came-to-the-web&quot;&gt;Why Photoshop came to the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#why-photoshop-came-to-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;As the web has evolved, one thing that hasn&#39;t changed are the core advantages that websites and web apps offer over platform-specific applications. These advantages include many unique capabilities such as being linkable, ephemeral, and universal, but they boil down to enabling simple access, easy sharing, and great collaboration.&lt;/p&gt;
&lt;p&gt;The simple power of a URL is that anyone can click it and instantly access it. All you need is a browser. There is no need to install an application or worry about what operating system you are running on. For web applications, that means users can have access to the application and their documents and comments. This makes the web the ideal collaboration platform, something that is becoming more and more essential to creative and marketing teams.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.google.com/&quot; rel=&quot;noopener&quot;&gt;Google Docs&lt;/a&gt; was a pioneer of this simplified access. Most of us know how easy it is to start a document, send the link to someone, and immediately jump into not only the application, but the specific document or comment as well. Since then, a plethora of amazing applications, such as &lt;a href=&quot;https://www.youtube.com/watch?v=Nrm5G9A_dfs&quot; rel=&quot;noopener&quot;&gt;those we&#39;ve shown off in the past&lt;/a&gt;, have adopted this model and now Photoshop, too, will benefit.&lt;/p&gt;
&lt;h2 id=&quot;how-photoshop-came-to-the-web&quot;&gt;How Photoshop came to the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#how-photoshop-came-to-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The web started out as a platform only suited for documents, but has grown dramatically throughout its history. Early apps like &lt;a href=&quot;https://www.google.com/gmail/&quot; rel=&quot;noopener&quot;&gt;Gmail&lt;/a&gt; showed that more complex interactivity and applications were at least possible. Since then, we&#39;ve seen impressive co-development where web apps push the boundaries of what&#39;s possible, and browser vendors respond by further expanding web capabilities. The latest iteration of this virtuous loop is what has enabled Photoshop on the web.&lt;/p&gt;
&lt;p&gt;Adobe previously brought &lt;a href=&quot;https://spark.adobe.com/sp/&quot; rel=&quot;noopener&quot;&gt;Spark&lt;/a&gt; and &lt;a href=&quot;https://lightroom.adobe.com/&quot; rel=&quot;noopener&quot;&gt;Lightroom&lt;/a&gt; to the web and had been interested in bringing Photoshop to the web for many years. However, they were blocked by the performance limitations of JavaScript, the absence of a good compile target for their code, and the lack of web capabilities. Read on to learn what Chrome built in the browser to solve these problems.&lt;/p&gt;
&lt;h2 id=&quot;webassembly-porting-with-emscripten&quot;&gt;WebAssembly porting with Emscripten &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#webassembly-porting-with-emscripten&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;WebAssembly and its C++ toolchain &lt;a href=&quot;https://emscripten.org/&quot; rel=&quot;noopener&quot;&gt;Emscripten&lt;/a&gt; have been the key to unlocking Photoshop&#39;s ability to come to the web, as it meant that Adobe would not have to start from scratch, but could leverage their existing Photoshop codebase. WebAssembly is a portable binary instruction set shipping in all browsers that was designed as a compilation target for programming languages. This means that applications such as Photoshop that are written in C++ can be ported directly to the web without requiring a rewrite in JavaScript. To get started porting yourself, check out the full &lt;a href=&quot;https://emscripten.org/docs/index.html&quot; rel=&quot;noopener&quot;&gt;Emscripten documentation&lt;/a&gt;, or follow this &lt;a href=&quot;https://web.dev/emscripting-a-c-library/&quot;&gt;guided example of how to port a library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Emscripten is a fully-featured toolchain that not only helps you compile your C++ to Wasm, but provides a translation layer that turns POSIX API calls into web API calls and even converts OpenGL into WebGL. For example, you can port applications that reference the local filesystem and &lt;a href=&quot;https://emscripten.org/docs/porting/files/file_systems_overview.html#file-system-overview&quot; rel=&quot;noopener&quot;&gt;Emscripten will provide an emulated file system&lt;/a&gt; to maintain functionality.&lt;/p&gt;
&lt;p&gt;Emscripten has been capable of bringing most parts of Photoshop to the web for a while, but it wasn&#39;t necessarily fast enough. We have continually worked with Adobe to figure out where bottlenecks are and improve Emscripten. Photoshop depends upon multithreading. Bringing dynamic &lt;a href=&quot;https://emscripten.org/docs/porting/pthreads.html&quot; rel=&quot;noopener&quot;&gt;multithreading&lt;/a&gt; to WebAssembly was a critical requirement.&lt;/p&gt;
&lt;p&gt;Also, exception-based error handling is very common in C++, but wasn&#39;t well supported in Emscripten and WebAssembly. We have worked with the &lt;a href=&quot;https://www.w3.org/community/webassembly/&quot; rel=&quot;noopener&quot;&gt;WebAssembly Community Group&lt;/a&gt; in the W3C to improve the WebAssembly standard and the tooling around it to bring C++ exceptions to WebAssembly.&lt;/p&gt;
&lt;p&gt;Emscripten doesn&#39;t just work on large applications, but also lets you port libraries or smaller projects! For example, you can see &lt;a href=&quot;https://docs.opencv.org/3.4/d4/da1/tutorial_js_setup.html&quot; rel=&quot;noopener&quot;&gt;how you can compile the popular OpenCV library&lt;/a&gt; to the web through Emscripten.&lt;/p&gt;
&lt;p&gt;Lastly, WebAssembly offers advanced performance primitives such as &lt;a href=&quot;https://emscripten.org/docs/porting/simd.html&quot; rel=&quot;noopener&quot;&gt;SIMD instructions&lt;/a&gt; which dramatically improve your web app performance. For example, &lt;a href=&quot;https://halide-lang.org/&quot; rel=&quot;noopener&quot;&gt;Halide&lt;/a&gt; is essential to Adobe&#39;s performance, and here SIMD provides a 3–4× speedup on average and in some cases a 80–160× speedup.&lt;/p&gt;
&lt;h2 id=&quot;webassembly-debugging&quot;&gt;WebAssembly debugging &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#webassembly-debugging&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;No large project can be successfully completed without the appropriate tools for the job, and it&#39;s for this reason that the Chrome team developed full featured WebAssembly debugging support. It provides support for stepping through the source code, setting breakpoints and pausing on exceptions, variable inspection with rich type support, and even basic support for evaluation in the DevTools console!&lt;/p&gt;
&lt;img alt=&quot;WebAssembly debugging in DevTools showing breakpoints in the code so it can be stepped through.&quot; decoding=&quot;async&quot; height=&quot;325&quot; loading=&quot;lazy&quot; sizes=&quot;(min-width: 800px) 800px, calc(100vw - 48px)&quot; src=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&quot; srcset=&quot;https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=200 200w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=228 228w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=260 260w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=296 296w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=338 338w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=385 385w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=439 439w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=500 500w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=571 571w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=650 650w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=741 741w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=845 845w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=964 964w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=1098 1098w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=1252 1252w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=1428 1428w, https://web-dev.imgix.net/image/8WbTDNrhLsU0El80frMBGE4eMCD3/ZwSsG07jcIvFZOdid5yd.png?auto=format&amp;w=1600 1600w&quot; width=&quot;800&quot; /&gt;
&lt;p&gt;Be sure to check out the &lt;a href=&quot;https://developer.chrome.com/blog/wasm-debugging-2020/&quot; rel=&quot;noopener&quot;&gt;authoritative guide on how to utilize WebAssembly Debugging&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;high-performance-storage&quot;&gt;High performance storage &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#high-performance-storage&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Given how large Photoshop documents can be, a critical need for Photoshop is the ability to dynamically move data from on-disk to in-memory as the user pans around. On other platforms, this is accomplished usually through memory mapping via &lt;a href=&quot;https://en.wikipedia.org/wiki/Mmap&quot; rel=&quot;noopener&quot;&gt;&lt;code&gt;mmap&lt;/code&gt;&lt;/a&gt;, but this hasn&#39;t been performantly possible on the web—that is until origin private file system access handles were developed and implemented as an origin trial! You can read how to leverage this new API &lt;a href=&quot;https://web.dev/file-system-access/#accessing-files-optimized-for-performance-from-the-origin-private-file-system&quot;&gt;in the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id=&quot;p3-color-space-for-canvas&quot;&gt;P3 color space for canvas &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#p3-color-space-for-canvas&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Historically, colors on the web have been specified in the &lt;a href=&quot;https://en.wikipedia.org/wiki/SRGB&quot; rel=&quot;noopener&quot;&gt;sRGB&lt;/a&gt; color space, which is a standard from the mid-nineties, based on the capabilities of cathode-ray tube monitors. Cameras and monitors have come a long way in the intervening quarter-century, and many larger and more capable color spaces have been standardized. One of the most popular modern color spaces is &lt;a href=&quot;https://en.wikipedia.org/wiki/DCI-P3&quot; rel=&quot;noopener&quot;&gt;Display P3&lt;/a&gt;. Photoshop uses a &lt;a href=&quot;https://github.com/WICG/canvas-color-space/blob/main/CanvasColorSpaceProposal.md&quot; rel=&quot;noopener&quot;&gt;Display P3 Canvas&lt;/a&gt; to display images more accurately in the browser. In particular, images with bright whites, bright colors, and details in shadows will display as best as possible on modern displays that support Display P3 data.
The Display P3 Canvas API is being further built upon to enable &lt;a href=&quot;https://github.com/w3c/ColorWeb-CG/blob/master/hdr_html_canvas_element.md&quot; rel=&quot;noopener&quot;&gt;high dynamic range&lt;/a&gt; displays.&lt;/p&gt;
&lt;h2 id=&quot;web-components-and-lit&quot;&gt;Web Components and Lit &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#web-components-and-lit&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Photoshop is a famously large and feature-rich application, with hundreds of UI elements supporting dozens of workflows. The app is built by multiple teams using a variety of tools and development practices, but its disparate parts need to come together into a cohesive, high-performing whole.&lt;/p&gt;
&lt;p&gt;To meet this challenge, Adobe turned to &lt;a href=&quot;https://developer.mozilla.org/docs/Web/Web_Components&quot; rel=&quot;noopener&quot;&gt;Web Components&lt;/a&gt; and the &lt;a href=&quot;https://lit.dev/&quot; rel=&quot;noopener&quot;&gt;Lit library&lt;/a&gt;. Photoshop&#39;s UI elements come from Adobe&#39;s &lt;a href=&quot;https://opensource.adobe.com/spectrum-web-components/&quot; rel=&quot;noopener&quot;&gt;Spectrum Web Components&lt;/a&gt; library, a lightweight, performant implementation of the Adobe design system that works with any framework, or no framework at all.&lt;/p&gt;
&lt;p&gt;What&#39;s more, the entire Photoshop app is built using Lit-based Web Components. Leaning on the browser&#39;s built-in component model and Shadow DOM encapsulation, the team found it easy to cleanly integrate a few &amp;quot;islands&amp;quot; of React code provided by other Adobe teams.&lt;/p&gt;
&lt;h2 id=&quot;service-worker-caching-with-workbox&quot;&gt;Service worker caching with Workbox &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#service-worker-caching-with-workbox&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Service_Worker_API&quot; rel=&quot;noopener&quot;&gt;Service workers&lt;/a&gt; act as a programmable local proxy, intercepting network requests and responding with data from the network, long-lived caches, or a mixture of both.&lt;/p&gt;
&lt;p&gt;As part of the &lt;a href=&quot;https://v8.dev/&quot; rel=&quot;noopener&quot;&gt;V8&lt;/a&gt; team&#39;s efforts to improve performance, the first time a service worker responds with a cached WebAssembly response, Chrome generates and stores an optimized version of the code—even for multi-megabyte WebAssembly scripts, which are common in the Photoshop codebase. A similar precompilation takes place when &lt;a href=&quot;https://v8.dev/blog/code-caching-for-devs#use-service-worker-caches&quot; rel=&quot;noopener&quot;&gt;JavaScript is cached&lt;/a&gt; by a service worker during its &lt;a href=&quot;https://web.dev/service-worker-lifecycle/#install&quot;&gt;&lt;code&gt;install&lt;/code&gt; step&lt;/a&gt;. In both cases, Chrome is able to load and execute the optimized versions of cached scripts with minimal runtime overhead.&lt;/p&gt;
&lt;p&gt;Photoshop on the web takes advantage of this by deploying a service worker that precaches many of its JavaScript and WebAssembly scripts. Because the URLs for these scripts are generated at build time, and because the logic of keeping caches up to date can be complex, they turned to a set of libraries maintained by Google called &lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot; rel=&quot;noopener&quot;&gt;Workbox&lt;/a&gt; to generate their service worker as part of their build process.&lt;/p&gt;
&lt;p&gt;A Workbox-based service worker along with the V8 engine&#39;s script caching led to measurable performance improvements. The specific numbers vary based on the device executing the code, but the team estimates these optimizations decreased the time spent on code initialization by 75%.&lt;/p&gt;
&lt;h2 id=&quot;whats-next-for-adobe-on-the-web&quot;&gt;What&#39;s next for Adobe on the web &lt;a class=&quot;headline-link&quot; href=&quot;https://web.dev/ps-on-the-web/#whats-next-for-adobe-on-the-web&quot;&gt;#&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The launch of the Photoshop beta is just the beginning, and we&#39;ve got several performance and feature improvements already underway as Photoshop tracks towards their full launch after this beta. Adobe isn&#39;t stopping with Photoshop and plans to aggressively expand &lt;a href=&quot;https://www.adobe.com/creativecloud.html&quot; rel=&quot;noopener&quot;&gt;Creative Cloud&lt;/a&gt; to the web, making it a primary platform for both creative content creation and collaboration. This will enable millions of first-time creators to tell their story and benefit from innovative workflows on the web.&lt;/p&gt;
&lt;p&gt;As Adobe continues to push the boundaries of what&#39;s possible, the Chrome team will continue our collaboration to drive the web forward for Adobe and the vibrant web developer ecosystem in general. As other browsers also catch up on these modern browser capabilities, we&#39;re excited to see Adobe make their products available there as well. Stay tuned for future updates as we continue to push the web forward!&lt;/p&gt;
&lt;p&gt;You can learn more about accessing Photoshop on the web (beta) in the &lt;a href=&quot;https://helpx.adobe.com/photoshop/using/photoshop-web-faq.html&quot; rel=&quot;noopener&quot;&gt;Adobe Help Center&lt;/a&gt;.&lt;/p&gt;
</content>
    <author>
      <name>Thomas Nattestad</name>
    </author><author>
      <name>Nabeel Al-Shamma</name>
    </author>
  </entry>
</feed>
