<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feed.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Brian Birtles’ Blog</title><description>My journey from browser engineer to Web app starter-upperer in Tokyo.</description><link>https://birtles.blog/</link><lastBuildDate>Tue, 10 Mar 2026 00:11:59 GMT</lastBuildDate><language>en-au</language><image><url>https://birtles.blog/favicon-128x128.png</url><title>Brian Birtles’ Blog</title><link>https://birtles.blog/</link><width>128</width><height>128</height></image><item><title>Lessons learned switching to Rspack</title><link>https://birtles.blog/2024/08/14/lessons-learned-switching-to-rspack/</link><guid isPermaLink="true">https://birtles.blog/2024/08/14/lessons-learned-switching-to-rspack/</guid><description>NOTE: This post was published while Rspack’s latest version was v1.0.0-beta.4.
Some details are likely to change as Rspack approaches its 1.0 release.

Rspack is a Rust-based alternative to
Webpack that promises to be faster
and includes a few common conveniences too.
After a year of trying, I’ve finally finished converting my two largest Webpack
projects to Rspack.
Here are some of the things I learnt along the way.
</description><pubDate>Wed, 14 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;NOTE: This post was published while Rspack’s latest version was v1.0.0-beta.4.
Some details are likely to change as Rspack approaches its 1.0 release.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rspack.dev/&quot;&gt;Rspack&lt;/a&gt; is a Rust-based alternative to
&lt;a href=&quot;https://webpack.js.org/&quot;&gt;Webpack&lt;/a&gt; that promises to be faster
and includes a few common conveniences too.
After a year of trying, I’ve finally finished converting my two largest Webpack
projects to Rspack.
Here are some of the things I learnt along the way.&lt;/p&gt;

&lt;h2&gt;Why Rspack?&lt;/h2&gt;
&lt;p&gt;First, however, why choose Rspack?
For me it’s because I’m already using Webpack for my two largest projects
and Rspack offers a comparatively simple and low-risk upgrade
compared to other build tools.
The build times for these projects are also slow enough that speeding them up
could make a worthwhile difference to productivity and CI costs.&lt;/p&gt;
&lt;p&gt;But while we’re switching build tools, why not switch to
&lt;a href=&quot;https://vitejs.dev/&quot;&gt;Vite&lt;/a&gt;?
A lot of people have switched from Webpack to Vite and seem to love it.
The reasons I decided to go with Rspack for these particular projects are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coming from Webpack, it’s a much simpler and less risky upgrade path.&lt;/li&gt;
&lt;li&gt;From what I can tell, Vite’s on-demand file serving appears to shine in
SSR contexts like Next.js apps
but I’m using Webpack for an SPA
and a Web extension where this matters less.&lt;/li&gt;
&lt;li&gt;My experience with Vite so far
&lt;a href=&quot;https://birtles.blog/2023/10/02/rss-the-hard-way/&quot;&gt;hasn’t been great&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;I like to keep dev and prod builds as close as possible so I can confidently
test what I’m shipping.
Vite is weak in this area with its &lt;a href=&quot;https://esbuild.github.io/&quot;&gt;esbuild&lt;/a&gt;-based
dev mode and &lt;a href=&quot;https://rollupjs.org/&quot;&gt;Rollup&lt;/a&gt;-based prod builds.
In fact, I found the gap so large that I gave up implementing some features in
dev mode with Vite because it was too much effort to implement them twice.&lt;/li&gt;
&lt;li&gt;Rspack is apparently faster than Vite, at least in the areas that matter to
me.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Perhaps the biggest problem with Rspack is that, like Webpack, it’s not easy to
get started with and that appears to be why the Rspack team have also produced
&lt;a href=&quot;https://rsbuild.dev/&quot;&gt;Rsbuild&lt;/a&gt; as a more approachable layer on top of Rspack.&lt;/p&gt;
&lt;h2&gt;Lessons learned along the way&lt;/h2&gt;
&lt;p&gt;The steps involved in migrating from Webpack are covered in Rspack’s
&lt;a href=&quot;https://www.rspack.dev/guide/migration/webpack&quot;&gt;Webpack migration guide&lt;/a&gt;
so what follows are the things I learned that weren’t covered there
or that might not be obvious.&lt;/p&gt;
&lt;h3&gt;TypeScript&lt;/h3&gt;
&lt;p&gt;Rspack uses &lt;a href=&quot;https://swc.rs/&quot;&gt;SWC&lt;/a&gt; to transpile TypeScript which means
you no longer need &lt;a href=&quot;https://www.npmjs.com/package/ts-loader&quot;&gt;ts-loader&lt;/a&gt;.
However, after building with Rspack,
I noticed that the generated JS assets were a lot bigger than when using Webpack
and &lt;code&gt;ts-loader&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It turned out that a lot of boilerplate was being generated
for features like async iterators.
In the Webpack build &lt;code&gt;ts-loader&lt;/code&gt; was picking up my &lt;code&gt;tsconfig.json&lt;/code&gt;
which specified &lt;code&gt;&quot;target&quot;: &quot;es2020&quot;&lt;/code&gt;
so these features were not being downleveled.
In Rspack, however, SWC was downleveling them to ECMAScript 5.
The solution was to specify the
&lt;a href=&quot;https://swc.rs/docs/configuration/compilation#jsctarget&quot;&gt;&lt;code&gt;target&lt;/code&gt;&lt;/a&gt;
for SWC in the Rspack config.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const config = {
  module: {
    rules: [
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: {
          loader: &apos;builtin:swc-loader&apos;,
          /** @type {import(&apos;@rspack/core&apos;).SwcLoaderOptions} */
          options: {
            sourceMap: true,
            jsc: {
              parser: {
                syntax: &apos;typescript&apos;,
              },
              target: &apos;es2022&apos;,
            },
          },
        },
        type: &apos;javascript/auto&apos;,
      },
      // ... similarly for tsx files
    ],
  },
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I believe it’s also possible to achieve this by specifying browser versions using
the &lt;a href=&quot;https://swc.rs/docs/configuration/compilation#envtargets&quot;&gt;&lt;code&gt;env.targets&lt;/code&gt;&lt;/a&gt;
setting.&lt;/p&gt;
&lt;p&gt;Even after doing that, however, the JS assets generated by Rspack
were still larger but when
&lt;a href=&quot;https://www.rspack.dev/blog/announcing-1-0-alpha#outputs-optimization&quot;&gt;1.0 alpha enabled &lt;code&gt;optimization.concatenateModules&lt;/code&gt; by default&lt;/a&gt;
they fell to within 3% of their Webpack counterparts
and were sometimes fractionally smaller.&lt;/p&gt;
&lt;h4&gt;Type checking&lt;/h4&gt;
&lt;p&gt;One consequence of using SWC to transpile TypeScript
is that type checking is no longer performed.
You’ll need to
&lt;a href=&quot;https://www.rspack.dev/guide/tech/typescript#enable-isolatedmodules&quot;&gt;enable &lt;code&gt;isolatedModules&lt;/code&gt;&lt;/a&gt;
in your &lt;code&gt;tsconfig.json&lt;/code&gt; and work out when
and how you want to perform type checking.&lt;/p&gt;
&lt;p&gt;I opted to use
&lt;a href=&quot;https://github.com/TypeStrong/fork-ts-checker-webpack-plugin&quot;&gt;&lt;code&gt;fork-ts-checker-webpack-plugin&lt;/code&gt;&lt;/a&gt;
as
&lt;a href=&quot;https://www.rspack.dev/guide/tech/typescript#typecheck&quot;&gt;recommended by the official docs&lt;/a&gt;
but on reflection,
I wonder if that’s even necessary.
Assuming you have your editor set up to perform type checking
and you run &lt;code&gt;tsc&lt;/code&gt; in CI,
and perhaps as a pre-commit hook too
(e.g. using &lt;a href=&quot;https://github.com/gustavopch/tsc-files#readme&quot;&gt;&lt;code&gt;tsc-files&lt;/code&gt;&lt;/a&gt;),
then you might not even need to perform type checking on each build.&lt;/p&gt;
&lt;p&gt;Using Webpack I was ignoring certain TypeScript errors during development
so that they didn’t interrupt me while refactoring like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;use: {
  loader: &apos;ts-loader&apos;,
  options: env.ignoreUnused
    ? {
        ignoreDiagnostics: [
          6133 /* &amp;#x3C;variable&gt; is declared but its value is never read */,
          6192 /* All imports in import declaration are unused */,
        ],
      }
    : undefined,
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With Rspack,
if you’re performing type checking using &lt;code&gt;fork-ts-checker-webpack-plugin&lt;/code&gt;,
you can pass in similar options there instead:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;new ForkTsCheckerWebpackPlugin({
  issue: {
    exclude: env.ignoreUnused
      ? [
          // &amp;#x3C;variable&gt; is declared but its value is never read
          { code: &apos;TS6133&apos; },
          // All imports in import declaration are unused
          { code: &apos;TS6192&apos; },
        ]
      : [],
  },
}),
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;CSS&lt;/h3&gt;
&lt;p&gt;Although the migration guide mentions replacing
&lt;a href=&quot;https://github.com/webpack-contrib/mini-css-extract-plugin&quot;&gt;&lt;code&gt;mini-css-extract-plugin&lt;/code&gt;&lt;/a&gt;
with &lt;code&gt;rspack.CssExtractRspackPlugin&lt;/code&gt;,
the
&lt;a href=&quot;https://www.rspack.dev/plugins/rspack/css-extract-rspack-plugin&quot;&gt;documentation for &lt;code&gt;CssExtractRspackPlugin&lt;/code&gt; states&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If your project does not depend on css-loader, it is recommended to use the
built-in CSS solution
&lt;a href=&quot;https://rspack.dev/config/experiments#experimentscss&quot;&gt;experiments.css&lt;/a&gt;
of Rspack for better performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a result, for my Web app project,
I was able to update my CSS configuration from:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// rspack.config.js
const config = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          { loader: MiniCssExtractPlugin.loader },
          {
            loader: &apos;css-loader&apos;,
            options: {
              url: false,
              importLoaders: 1,
            },
          },
          {
            loader: &apos;postcss-loader&apos;,
          },
        ],
      },
      // ...
    ],
  },
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To just:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const config = {
  experiments: {
    css: true,
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [{ loader: &apos;postcss-loader&apos; }],
        type: &apos;css/auto&apos;,
      },
      // ...
    ],
  },
  // ...
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, I noticed my CSS assets were ~11% larger
than those generated from Webpack.
Comparing the output,
I discovered that the Rspack output was not performing some optimizations
like converting &lt;code&gt;rgba()&lt;/code&gt; colors to hex values.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.rspack.dev/config/optimization#optimizationminimizer&quot;&gt;By default&lt;/a&gt;
Rspack uses &lt;a href=&quot;https://lightningcss.dev/&quot;&gt;Lightning CSS&lt;/a&gt; to minimize CSS assets
and it turns out the features Lightning CSS uses
as part of its default settings are very conservative.
After adding some more recent values to the
&lt;a href=&quot;https://rspack.dev/plugins/rspack/lightning-css-minimizer-rspack-plugin#minimizeroptions&quot;&gt;&lt;code&gt;minimizerOptions.targets&lt;/code&gt; property&lt;/a&gt;
Rspack’s output was slightly smaller than Webpack’s:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;  optimization: {
    // ...
    minimizer: [
      new rspack.SwcJsMinimizerRspackPlugin({
        // ...
      }),
      new rspack.LightningCssMinimizerRspackPlugin({
        minimizerOptions: {
          targets: [
            &apos;last 2 Chrome versions&apos;,
            &apos;Firefox ESR&apos;,
            &apos;last 2 Safari versions&apos;,
          ],
        },
      }),
    ],
  },
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Update (2024-08-17): It looks like the Rspack team have taken note of this
and &lt;a href=&quot;https://github.com/web-infra-dev/rspack/pull/7579&quot;&gt;added default targets for Lightning CSS in beta
5&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Service workers&lt;/h3&gt;
&lt;p&gt;My app includes a Service Worker and relies on the
&lt;a href=&quot;https://developer.chrome.com/docs/workbox/modules/workbox-webpack-plugin#injectmanifest&quot;&gt;&lt;code&gt;InjectManifest&lt;/code&gt;&lt;/a&gt;
plugin from Google’s &lt;a href=&quot;https://developer.chrome.com/docs/workbox/&quot;&gt;Workbox&lt;/a&gt;
to trigger the generation of the Service Worker asset
and populate it with a precache manifest.
Unfortunately when I went to migrate my app,
this plugin &lt;a href=&quot;https://github.com/web-infra-dev/rspack/issues/4692&quot;&gt;wasn’t supported by Rspack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Rspack 1.0.0-alpha.0, however,
&lt;a href=&quot;https://www.rspack.dev/guide/features/web-workers#web-workers&quot;&gt;added native support for recognizing Service Workers&lt;/a&gt;
(and various kinds of worklets too).
It’s &lt;a href=&quot;https://www.rspack.dev/guide/features/web-workers#usage&quot;&gt;a little bit quirky&lt;/a&gt;
in that you need to pass a &lt;code&gt;URL&lt;/code&gt; object to &lt;code&gt;navigator.serviceWorker.register()&lt;/code&gt;
(not a string)
and you can’t pass a variable referring to a &lt;code&gt;URL&lt;/code&gt; object either.&lt;/p&gt;
&lt;p&gt;For example, the following would cause a chunk to be generated for the service worker at &lt;code&gt;sw.ts&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;const registrationPromise = navigator.serviceWorker.register(
  new URL(
    /* webpackChunkName: &quot;serviceworker&quot; */
    &apos;./sw.ts&apos;,
    import.meta.url
  )
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You also need to take care to ensure the service worker chunk ends up with a
fixed filename rather than one with a cache-busting hash in it:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// rspack.config.js
const config = {
  // ...
  output: {
    chunkFilename: (assetInfo) =&gt; {
      if (assetInfo.chunk?.name === &apos;serviceworker&apos;) {
        return &apos;[name].js&apos;;
      }
      return &apos;[name].[contenthash].js&apos;;
    },
  },
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, all that still won’t help with embedding a precache asset manifest
like &lt;code&gt;InjectManifest&lt;/code&gt; does.
I tried
&lt;a href=&quot;https://github.com/birchill/inject-manifest-plugin/#related-projects&quot;&gt;various alternatives&lt;/a&gt;
but none of them seemed to work with Rspack’s native service worker support
so I ended up
&lt;a href=&quot;https://github.com/birchill/inject-manifest-plugin&quot;&gt;writing my own&lt;/a&gt;
by extracting just the needed parts of Workbox’s &lt;code&gt;InjectManifest&lt;/code&gt; plugin
and adapting them to Rspack.&lt;/p&gt;
&lt;p&gt;Since then, Rspack
&lt;a href=&quot;https://github.com/web-infra-dev/rspack/issues/4692#issuecomment-2246785932&quot;&gt;have announced that Workbox is fully supported&lt;/a&gt;.
My package is smaller and seems to work better than Workbox
when making changes so I’ll stick with it for now
but I’m sure most people will be happy to continue using Workbox as-is.&lt;/p&gt;
&lt;p&gt;One quirk of the native Service Worker support, however, is that it appears to
run before dead code elimination.
As a result, if you are using
&lt;a href=&quot;https://www.rspack.dev/plugins/webpack/define-plugin&quot;&gt;build-time constants&lt;/a&gt;
to disable service worker registration like in the following code,
you may find the service worker asset is still generated
even though it’s not referenced anywhere.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;function registerServiceWorker() {
  if (!(&apos;serviceWorker&apos; in navigator) || !__ENABLE_SW__) {
    return Promise.resolve(null);
  }

  // The following code will be eliminated when __ENABLE_SW__
  // is falsy, but the sw.js asset will still be generated.
  const registrationPromise = navigator.serviceWorker.register(
    new URL(
      /* webpackChunkName: &quot;sw&quot; */
      &apos;./sw.ts&apos;,
      import.meta.url
    )
  );

  // ...

  return registrationPromise;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;React Cosmos&lt;/h3&gt;
&lt;p&gt;Perhaps the biggest hurdle in migrating to Rspack was getting
&lt;a href=&quot;https://reactcosmos.org/&quot;&gt;React Cosmos&lt;/a&gt; to play with it.
I’m a big fan of React Cosmos for developing and testing components because
I found that unlike &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt;
it doesn’t require a lot of additional development dependencies
but works with your existing bundler instead.&lt;/p&gt;
&lt;p&gt;Unfortunately React Cosmos does not include support for Rspack,
only Webpack, Vite, and a few others.
It includes instructions on
&lt;a href=&quot;https://reactcosmos.org/docs/getting-started/custom-bundler&quot;&gt;how to configure a custom bundler&lt;/a&gt;
but I figured, “How hard can it be to port the Webpack plugin to Rspack?”&lt;/p&gt;
&lt;p&gt;The answer, it turned out, was “quite hard”
mostly due to me insisting on building the plugin with
&lt;a href=&quot;https://tsup.egoist.dev/&quot;&gt;tsup&lt;/a&gt; and getting confused about
how each endpoint should be bundled.
A few weeks later, however,
&lt;a href=&quot;https://github.com/birchill/react-cosmos-plugin-rspack/&quot;&gt;&lt;code&gt;react-cosmos-plugin-rspack&lt;/code&gt;&lt;/a&gt;
was born offering a drop-in replacement for the Webpack plugin.&lt;/p&gt;
&lt;h3&gt;Knip&lt;/h3&gt;
&lt;p&gt;The final dependency requiring attention was &lt;a href=&quot;https://knip.dev/&quot;&gt;Knip&lt;/a&gt;.
Knip is a tool for detecting unused cruft—dependencies, exports, files,
etc.—in your project.
If it sees you are using Webpack, it will look up your Webpack config and
detect your project’s entrypoints, Webpack plugins etc.
and analyze your project accordingly.
Unfortunately, it &lt;a href=&quot;https://github.com/webpro-nl/knip/issues/483#issuecomment-2207426554&quot;&gt;didn’t know about Rspack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://birchill.co.jp/&quot;&gt;My company&lt;/a&gt; is a sponsor of Lars’ work on Knip
so I reached out to see if we could commission a Knip plugin for Rspack.
Lars jumped on it and
&lt;a href=&quot;https://github.com/webpro-nl/knip/issues/483#issuecomment-2227882616&quot;&gt;invited others to join in the crowdfunding&lt;/a&gt;
and a few days later &lt;a href=&quot;https://github.com/webpro-nl/knip/issues/483#issuecomment-2238566826&quot;&gt;it was complete&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a result, Knip detected that I no longer needed any of the following dependencies:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;clean-webpack-plugin&lt;/code&gt; (replaced by &lt;a href=&quot;https://www.rspack.dev/config/output#outputclean&quot;&gt;&lt;code&gt;output.clean&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;copy-webpack-plugin&lt;/code&gt; (replaced by &lt;a href=&quot;https://www.rspack.dev/plugins/rspack/copy-rspack-plugin&quot;&gt;&lt;code&gt;rspack.CopyRspackPlugin&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;css-loader&lt;/code&gt; (replaced by &lt;a href=&quot;https://www.rspack.dev/config/experiments#experimentscss&quot;&gt;&lt;code&gt;experiments.css&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mini-css-extract-plugin&lt;/code&gt; (replaced by &lt;a href=&quot;https://www.rspack.dev/config/experiments#experimentscss&quot;&gt;&lt;code&gt;experiments.css&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;react-cosmos-plugin-webpack&lt;/code&gt; (replaced by &lt;a href=&quot;https://github.com/birchill/react-cosmos-plugin-rspack&quot;&gt;&lt;code&gt;react-cosmos-plugin-rspack&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ts-loader&lt;/code&gt; (replaced by &lt;a href=&quot;https://www.rspack.dev/guide/features/builtin-swc-loader&quot;&gt;&lt;code&gt;builtin:swc-loader&lt;/code&gt;&lt;/a&gt; and &lt;a href=&quot;https://github.com/TypeStrong/fork-ts-checker-webpack-plugin&quot;&gt;&lt;code&gt;fork-ts-checker-webpack-plugin&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;webpack&lt;/code&gt;, &lt;code&gt;webpack-cli&lt;/code&gt; (duh)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;webpack-dev-server&lt;/code&gt; (built into &lt;code&gt;@rspack/cli&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;workbox-webpack-plugin&lt;/code&gt; (replaced by &lt;a href=&quot;https://github.com/birchill/inject-manifest-plugin/&quot;&gt;&lt;code&gt;@birchill/inject-manifest-plugin&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Command-line flags&lt;/h3&gt;
&lt;p&gt;Rspack CLI includes a built-in dev server but unfortunately,
the command-line flags differ from &lt;code&gt;webpack-dev-server&lt;/code&gt; in a few places,
notably missing options like &lt;code&gt;--port&lt;/code&gt; and &lt;code&gt;--hot&lt;/code&gt;/&lt;code&gt;--no-hot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To handle such cases I ended up using various &lt;code&gt;--env&lt;/code&gt; values
and checking them in &lt;code&gt;rspack.config.js&lt;/code&gt;’s
&lt;a href=&quot;https://rspack.dev/config/index#exporting-a-configuration-function&quot;&gt;configuration function&lt;/a&gt;.
This seems like a potentially unnecessary point of friction
that could be eased in a future release.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update (2024-09-05): This has been &lt;a href=&quot;https://github.com/web-infra-dev/rspack/pull/7710&quot;&gt;fixed in version
1.0.1&lt;/a&gt;!&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Rsdoctor&lt;/h3&gt;
&lt;p&gt;The Rspack team have helpfully created a plugin,
&lt;a href=&quot;https://rsdoctor.dev/&quot;&gt;Rsdoctor&lt;/a&gt; for analysing your bundle and its build times.
For what it’s worth,
I ended up with the following &lt;a href=&quot;https://rsdoctor.dev/guide/start/quick-start#rspack&quot;&gt;configuration&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;new RsdoctorRspackPlugin({
  disableTOSUpload: true,
  linter: {
    rules: {
      // Don&apos;t warn about using non ES5 features
      &apos;ecma-version-check&apos;: &apos;off&apos;,
    },
  },
  supports: { generateTileGraph: true },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What didn’t change&lt;/h2&gt;
&lt;p&gt;Apart from the above changes,
everything else appeared to work as-is including the following plugins:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/principalstudio/html-webpack-inject-preload&quot;&gt;html-webpack-inject-preload&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/jantimon/html-webpack-plugin&quot;&gt;html-webpack-plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://relative-ci.com/documentation/setup/agent/webpack-plugin&quot;&gt;Relative CI webpack plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://webpack.js.org/plugins/terser-webpack-plugin/&quot;&gt;terser-webpack-plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/hiikezoe/web-ext-webpack-plugin&quot;&gt;web-ext-webpack-plugin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/Marc-Andre-Rivet/webpack-preprocessor&quot;&gt;webpack-preprocessor&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/cqqccqc/webpack-utf8-bom&quot;&gt;webpack-utf8-bom&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also use the
&lt;a href=&quot;https://docs.bugsnag.com/build-integrations/webpack/&quot;&gt;Bugsnag Webpack plugins&lt;/a&gt;
but they only run on a new release so I haven’t had a chance to test them yet.&lt;/p&gt;
&lt;h2&gt;Results&lt;/h2&gt;
&lt;p&gt;So how much faster is Rspack after all?&lt;/p&gt;
&lt;p&gt;For my SPA project I saw the following results:&lt;/p&gt;
&lt;p&gt;| Environment  | Webpack | Rspack          | Rspack without type checking |
| ------------ | ------- | --------------- | ---------------------------- |
| Home laptop  | 19.1s   | 8.1s (-57.7%)   | 3.04s (-84.16%)              |
| Work desktop | 13.24s  | 5.57s (-57.94%) | 2.44s (-81.61%)              |&lt;/p&gt;
&lt;p&gt;Since type checking is performed in a separate process, most of the time
you’re only waiting on the build and the final column is what matters most.&lt;/p&gt;
&lt;p&gt;Furthermore, if I am reading the results of Rsdoctor correctly,
it seems that most of the compile time comes from &lt;code&gt;postcss-loader&lt;/code&gt;
so I hope that when
&lt;a href=&quot;https://tailwindcss.com/blog/tailwindcss-v4-alpha&quot;&gt;Tailwind 4&lt;/a&gt; is released
I can switch to using
&lt;a href=&quot;https://rspack.dev/guide/features/builtin-lightningcss-loader&quot;&gt;&lt;code&gt;builtin:lightningcss-loader&lt;/code&gt;&lt;/a&gt;
instead and see further improvements to the compile time.&lt;/p&gt;
&lt;p&gt;For my Web extension project, the improvements were even more significant, going
from 11.65s to 3.6s (69% faster) on my desktop computer even with type checking
enabled.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update (2024-09-05): The Rspack team have added a list of
&lt;a href=&quot;https://rspack.dev/guide/optimization/profile#performance-bottlenecks&quot;&gt;performance
bottlenecks&lt;/a&gt;.
In addition to &lt;code&gt;postcss-loader&lt;/code&gt; I am also using &lt;code&gt;html-webpack-plugin&lt;/code&gt; from that
list.
I currently need that in order to use &lt;code&gt;html-webpack-inject-preload&lt;/code&gt; (since
&lt;a href=&quot;https://github.com/principalstudio/html-webpack-inject-preload/blob/647ebcbaaf7ab7f319218a261d347056b2d451f8/src/main.ts#L69&quot;&gt;it checks for the &lt;code&gt;HtmlWebpackPlugin&lt;/code&gt; constructor
name&lt;/a&gt;).
If I can migrate that to work with
&lt;a href=&quot;https://rspack.dev/plugins/rspack/html-rspack-plugin&quot;&gt;&lt;code&gt;HtmlRspackPlugin&lt;/code&gt;&lt;/a&gt; it
might improve the build time further.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Looking forward&lt;/h2&gt;
&lt;p&gt;As Rspack is approaching 1.0,
we’ve had announcements for two more Rust-based build tools
(which also appear to have roots in China) in
&lt;a href=&quot;https://www.farmfe.org/&quot;&gt;Farm&lt;/a&gt; and
&lt;a href=&quot;https://makojs.dev/&quot;&gt;Mako&lt;/a&gt;.
Obviously there is also &lt;a href=&quot;https://turbo.build/pack&quot;&gt;Turbopack&lt;/a&gt;,
the Rust-based successor to Webpack,
and &lt;a href=&quot;https://rolldown.rs/&quot;&gt;Rolldown&lt;/a&gt;,
the Rust-based version of &lt;a href=&quot;https://rollupjs.org/&quot;&gt;Rollup&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It will be interesting to see which of these tools gets traction.
Personally I think Rspack has a good chance of succeeding because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Webpack is probably the most widely used build tool for apps today and Rspack
provides the simplest and lowest risk migration path from Webpack.
It’s easy to overlook this point but hopefully this post demonstrates how
even for a modestly complex app like mine,
migrating to a different build tool, even one that is largely compatible,
can be quite involved.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Webpack has a rich plugin ecosystem, most of which work in Rspack.
Many of the services I use like &lt;a href=&quot;https://relative-ci.com/&quot;&gt;Relative CI&lt;/a&gt; and
&lt;a href=&quot;https://www.bugsnag.com/&quot;&gt;Bugsnag&lt;/a&gt; provide a Webpack plugin but don’t
support any other build tools.
Other build tools will be at an initial disadvantage unless they offer
compatibility with Webpack’s plugin API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rspack is fast enough.
Other tools might end up being fractionally faster
(curiously both Mako and Farm claim to be marginally faster than &lt;em&gt;Rsbuild&lt;/em&gt;
but don’t show how they compare with &lt;em&gt;Rspack&lt;/em&gt;)
but if your build is already only 2~3 seconds,
even an order of magnitude faster
is not going to be a compelling enough reason to switch.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As Rspack approaches 1.0 I’m looking forward to seeing how it’s received
and where the team takes it from here.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2024/08/14/lessons-learned-switching-to-rspack/#comments</comments><category>Web apps</category></item><item><title>Weird things engineers believe about Web development</title><link>https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/</link><guid isPermaLink="true">https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/</guid><description>I wrote most of this post sometime in 2022 but I think it holds up alright
in 2024 so I decided to publish it for posterity.
I don’t really like doing posts like this—I’d much rather share some
innocuous learnings or tips but it turns out I have opinions too 😓
Sorry!

2024-02-21: I’ve added a few reflections at the end of the
post.

2024-04-27: Developpez.com has produced a French
translation of this post.

Since I quit Mozilla and went back to full-time Web development, I’ve discovered
a few surprises.
It turns out Web development is actually pretty hard, Web developers are
actually very smart, and some of these frameworks and techniques we mocked as
browser engineers aren’t so bad.
Oops.

At the same time, it turns out some Web developers have ideas about browsers and
the Web that, as a former browser engineer and standards editor, I’m a bit
dubious of.

Here are a few of the things that surprised me.
</description><pubDate>Sat, 06 Jan 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;I wrote most of this post sometime in 2022 but I think it holds up alright
in 2024 so I decided to publish it for posterity.
I don’t really like doing posts like this—I’d much rather share some
innocuous learnings or tips but it turns out I have opinions too&lt;/em&gt; 😓
&lt;em&gt;Sorry!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;2024-02-21&lt;/strong&gt;: I’ve added a few reflections at &lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#reflections-a-couple-of-months-later&quot;&gt;the end of the
post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;2024-04-27&lt;/strong&gt;: Developpez.com has produced a &lt;a href=&quot;https://web.developpez.com/actu/356070/Les-ingenieurs-croient-des-choses-etranges-sur-le-developpement-Web-par-Brian-Birtles/&quot;&gt;French
translation of this post&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Since I quit Mozilla and went back to full-time Web development, I’ve discovered
a few surprises.
It turns out Web development is actually pretty hard, Web developers are
actually very smart, and some of these frameworks and techniques we mocked as
browser engineers aren’t so bad.
Oops.&lt;/p&gt;
&lt;p&gt;At the same time, it turns out some Web developers have ideas about browsers and
the Web that, as a former browser engineer and standards editor, I’m a bit
dubious of.&lt;/p&gt;
&lt;p&gt;Here are a few of the things that surprised me.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#web-browser-engineers-know-web-development-really-well&quot;&gt;“Web browser engineers know Web development really well”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#the-people-who-make-web-specifications-know-web-development-really-well&quot;&gt;“The people who make Web specifications know Web development really well”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#web-developers-know-web-development-really-well&quot;&gt;“Web developers know Web development really well”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#browsers-arent-made-to-run-spas&quot;&gt;“Browsers aren’t made to run SPAs”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#mpas-will-replace-spas&quot;&gt;”MPAs will replace SPAs”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#all-sites-should-work-without-javascript&quot;&gt;“All sites should work without JavaScript”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#web-development-shouldnt-need-a-build-step&quot;&gt;“Web development shouldn’t need a build step”&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#my-blog-is-representative-of-web-development-at-large&quot;&gt;“My blog is representative of Web development at large”&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;“Web browser engineers know Web development really well”&lt;/h2&gt;
&lt;p&gt;It’s easy to imagine that Web browser engineers, who write the code that makes
up the Web platform, must know the Web inside-out like no-one else.&lt;/p&gt;
&lt;p&gt;The trouble is, writing Web browsers is hard.&lt;/p&gt;
&lt;p&gt;Most browser engineers focus on a particular area and know it really well with
only a superficial understanding of other areas.
Furthermore, browser platform engineers are writing C++ and Rust code all
day long with a smattering of very simple JavaScript test cases.
On top of that, they contribute to one massive respository where someone else
takes care of all the tooling.&lt;/p&gt;
&lt;p&gt;As a result, in their day jobs browser engineers are
not fighting webpack,
not trying to understand full-page TypeScript errors
(they’ve got C++ template errors to fill &lt;em&gt;that&lt;/em&gt; hole in their lives),
not trying to get Safari on iOS to behave like other browsers,
not struggling with CSS at scale,
not trying to evaluate if the latest SSR/SSG/island framework is worth
investing in,
not refactoring massive JS codebases for more optimal chunking,
not filing exasperated issues on GitHub because the latest version of one of
their dependencies broke their app,
not trying to get all their tools to agree on ESM vs CJS,
and not losing sleep over whether or not they chose the right state
management approach or if they should rewrite the entire thing for the tenth
time over.&lt;/p&gt;
&lt;p&gt;In short, they’re not doing Web development day in and day out so they know
much less about real-world Web development than Web developers probably
expect.&lt;/p&gt;
&lt;p&gt;Now the engineers working on browser &lt;em&gt;developer tools&lt;/em&gt; and the browser
&lt;em&gt;front-end&lt;/em&gt; often &lt;em&gt;are&lt;/em&gt; using JS day-to-day and certainly have more awareness of
the issues, but it’s still a few degrees removed from regular Web development.
For example, they only need to target a single browser engine’s platform
features, and often only a single browser version (being able to use the new
and shiny features without worrying about compatibility is &lt;em&gt;amazing&lt;/em&gt;), don’t
need to worry about bundle size, or servers, or being offline, or so many
other issues that make Web development hard.&lt;/p&gt;
&lt;p&gt;Obviously some browser engineers have hobby projects, but the constraints on
a hobby project are a world apart from being in a startup where you live or
die by the success of your Web app.&lt;/p&gt;
&lt;p&gt;I started my career in graphic design and Web development and even after
I started contributing to Firefox I worked at a Web development company in
Osaka for a time and produced some Web apps at Mozilla Japan too.
However, after I quit Mozilla and got back into Web development full-time
I was shocked at how much it had changed and how little I knew about it.&lt;/p&gt;
&lt;p&gt;My experience as a browser engineer has been incredibly useful in Web
development not least because I know where to look, who to ask, and where to file
bugs, but I’d be kidding myself if I said that being a browser engineer
automatically qualified me as a Web developer.&lt;/p&gt;
&lt;p&gt;During my time at Mozilla, the Firefox OS days were by far the most enjoyable.
We had internal teams building real-world mobile Web apps that we,
as the platform team, had to debug and make successful as our highest priority.
I saw how &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Element/transitionend_event&quot;&gt;&lt;code&gt;transitionend&lt;/code&gt;
events&lt;/a&gt;
could be unreliable and cause Web apps to be buggy and overly complicated and so
I proposed and implemented the
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Element/transitioncancel_event&quot;&gt;&lt;code&gt;transitioncancel&lt;/code&gt;
event&lt;/a&gt;
and Web Animations’ &lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/Animation/finished&quot;&gt;&lt;code&gt;Animation.finished&lt;/code&gt;
promise&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But even working side-by-side with Web developers could not prepare me for
actually &lt;em&gt;being&lt;/em&gt; a full-time Web developer again.
For the most part browser engineers just operate in a different world from Web
developers and might not be the Web developer superheroes we imagine them to be.&lt;/p&gt;
&lt;h2&gt;”The people who make Web specifications know Web development really well”&lt;/h2&gt;
&lt;p&gt;Ok, but surely the people working on Web &lt;em&gt;standards&lt;/em&gt; and &lt;em&gt;specifications&lt;/em&gt;
(who, it turns out, are mostly browser engineers) must be well-versed in Web
development, right?&lt;/p&gt;
&lt;p&gt;Back in 2012, &lt;a href=&quot;https://brendaneich.com/2012/02/community-prioritized-web-standards/&quot;&gt;Brendan Eich pointed
out&lt;/a&gt;
that, “Standards-making like law-making is definitely
&lt;a href=&quot;https://en.wikiquote.org/wiki/John_Godfrey_Saxe&quot;&gt;sausage-making&lt;/a&gt;” referring
to the following quote from John Godfrey Saxe:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Laws, like sausages, cease to inspire respect in proportion as we know how
they are made.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;As a Web developer, it’s easy to imagine a group of people, infinitely
wise about all things related to Web technology, making calm, rational
decisions based on the technical merits of each proposal balanced against
a thorough understanding of industry needs.&lt;/p&gt;
&lt;p&gt;That illusion typically won’t last your first working group meeting.
Despite the best of intentions, sometimes decisions get made based, at least in
part,
on one person’s charisma or forceful personality,
on who happens to be in the room at the time,
on how tired everyone is,
or, dare I suggest, maybe even
someone’s need to ship a feature in order to fill out their promotion packet.&lt;/p&gt;
&lt;p&gt;That sounds very cynical so let me make two clarifications.&lt;/p&gt;
&lt;p&gt;Firstly, the folks on these groups are well-meaning, wonderful people.
Furthermore, they are often aware of their limitations and try their best to
elicit Web developer feedback.
Unfortunately, I’ve yet to see a group do this very successfully.
There are Twitter/X polls, for example, but they tend to only be answered by the
Web developers on the bleeding edge and are easily skewed by &lt;em&gt;who&lt;/em&gt; spreads the
word about the poll.&lt;/p&gt;
&lt;p&gt;Secondly, I haven’t had much experience with WHATWG specs like HTML and
DOM where decisions appear to be made asynchronously (“any decisions made
during in-person meetings are to be considered non-binding”—&lt;a href=&quot;https://whatwg.org/working-mode#meetings&quot;&gt;WHATWG
meetings&lt;/a&gt;),
but my impression is that they seem to make better decisions.
Folks like Anne van Kesteren, Simon Pieters, and Domenic Denicola probably
know the Web better than anyone else on the planet.
But even that is not the same as knowing Web development.&lt;/p&gt;
&lt;h2&gt;”Web developers know Web development really well”&lt;/h2&gt;
&lt;p&gt;As a browser engineer it’s really satisfying to ship a new platform feature.
There are articles about it on Smashing Magazine and CSS tricks and Twitter/X
goes abuzz with the news.
It’s easy to think that now the whole world now knows about this great new
advance in the Web’s capabilities.&lt;/p&gt;
&lt;p&gt;At one point a few years ago, a few of us in Mozilla’s Japan team decided to
interview local Web developers in Tokyo to learn what developer tools
they would benefit from.&lt;/p&gt;
&lt;p&gt;The results were surprising.&lt;/p&gt;
&lt;p&gt;Many didn’t know about new CSS features that had shipped 10 years ago.
What’s more, even when we told them about them, they didn’t seem too excited.
They were doing just fine with jQuery and WordPress, thank you.&lt;/p&gt;
&lt;p&gt;Instead, they were having trouble with things like, “When I show clients
a site in responsive design mode, if the window doesn’t have a mockup of
an iPhone around it, clients can’t grasp that they are looking at a preview of
how the site will look on a smartphone. I really need that iPhone mockup.”&lt;/p&gt;
&lt;p&gt;As a browser engineer involved in developing new Web standards I was a little
disappointed but my lasting impression was of the constraints on these folks
who are making their living from shipping Web sites and Web apps.&lt;/p&gt;
&lt;p&gt;Unlike people working on browsers or well-funded Silicon Valley startups, many
of these people are working for little shops with considerable pressure to
deliver something quickly and then move onto the next project in order to pay
the bills.
They don’t have the luxury of spending a morning tinkering with upcoming
technologies and instead reach for tried and trusted solutions they have
experience with.&lt;/p&gt;
&lt;h2&gt;”Browsers aren’t made to run SPAs”&lt;/h2&gt;
&lt;p&gt;Another surprise from moving from browser development back to Web development
was some of the assertions about how browsers work.&lt;/p&gt;
&lt;p&gt;When I worked on animations, I was surprised at how many people believed that
some animations “run on the GPU” (the browser can offload some animations to
a separate process or thread that updates animations using the GPU to
composite or even paint each frame but it doesn’t offload them to the GPU
wholesale) but that was a fairly minor misunderstanding compared to some of
the other ones that get thrown around like, “browsers aren’t made to run
SPAs (single page applications)“.&lt;/p&gt;
&lt;p&gt;I believe the argument here is that originally browsers would load content off
the network, progressively laying it out and rendering it and have been
heavily optimized for this. Dynamic content came later and so has been less
heavily optimized.&lt;/p&gt;
&lt;p&gt;Having worked on a browser on and off for nearly two decades I’m not convinced
this is the case, or at least not anymore.&lt;/p&gt;
&lt;p&gt;After all, the Firefox front-end and developer tools are, in effect, SPAs.
The developer tools in particular are written using React and Redux and are in
every sense an SPA.&lt;/p&gt;
&lt;p&gt;To the argument that browsers are deficient at handling complex and long-lived
DOM trees with dynamic changes made via JavaScript, the browser itself stands
in contradiction to that claim.&lt;/p&gt;
&lt;p&gt;An argument could be made that &lt;em&gt;on mobile&lt;/em&gt; browsers aren’t optimized to run
SPAs.
After all, on Android, Firefox switched from an HTML rendered browser chrome
to a native browser chrome in order to improve performance.
I’m not in a position to comment on what the particular performance
constraints were that lead to that change, but &lt;a href=&quot;https://lucasr.org/2011/11/15/native-ui-for-firefox-on-android/&quot;&gt;a blog from that
time&lt;/a&gt;
suggests it was related to improving app startup time and panning and
scrolling performance, neither of which point to browsers being deficient at
handling SPAs compared to other architectures.&lt;/p&gt;
&lt;p&gt;“Ok, so maybe browsers can handle complex long-lived DOM trees with frequent
dynamic changes, but SPAs tend to have large JS bundles that are slow to
download and parse, blocking the initial render.”
That’s a fair argument, but it’s an argument for smaller render-blocking
initial bundles, which applies to equally to your average WordPress site,
not an argument that browsers are somehow unsuited to running SPAs.&lt;/p&gt;
&lt;h2&gt;”MPAs will replace SPAs”&lt;/h2&gt;
&lt;p&gt;While we’re talking about SPAs and “the one true way to write Web apps”,
a more recent variation on the “browsers can’t handle SPAs” take is, “MPAs
(multi-page applications) will replace SPAs”.&lt;/p&gt;
&lt;p&gt;I’m pretty excited about MPAs.
More specifically, as someone who is involved with a lot of animation specs,
I’m excited by the &lt;a href=&quot;https://drafts.csswg.org/css-view-transitions-1/&quot;&gt;view transitions
spec&lt;/a&gt; spec.
It’s something we wanted to do at Mozilla for a while, particularly during
the Firefox OS days, and made
a &lt;a href=&quot;https://www.chrislord.net/2015/04/24/web-navigation-transitions/&quot;&gt;proposal&lt;/a&gt;
to that end.
Kudos to Jake and others for finally making it happen.&lt;/p&gt;
&lt;p&gt;View transitions were originally implemented for SPAs but have been adapted
to work for MPAs and to the extent that they make multi-page sites more
enjoyable they are a very welcome addition.&lt;/p&gt;
&lt;p&gt;However, building on the “SPAs are bad” thinking, there seems to be a tendency
to assume that MPAs are the future and SPAs are on the way out.&lt;/p&gt;
&lt;p&gt;Unlike the earlier points in this post, my surprise at this take is not
based on my experience with working on browsers, but on my more recent
experience with working on Web apps.&lt;/p&gt;
&lt;p&gt;First though, what do we even mean by MPAs?&lt;/p&gt;
&lt;p&gt;My understanding is that whereas SPAs are characterized by having a long-lived
DOM tree or two that are frequently updated by script, MPAs primarily update
content by navigating to different HTML resources served from the network.
These don’t have to be topmost navigations—it could be by navigating an
&lt;code&gt;&amp;#x3C;iframe&gt;&lt;/code&gt;, for example.
Similarly, SPAs might use &lt;code&gt;&amp;#x3C;iframe&gt;&lt;/code&gt;s as a means of chunking but there’s a
difference in how content is typically updated.&lt;/p&gt;
&lt;p&gt;By this definition, Google Docs is an SPA since although each document is
served as a separate resource, most of the time you’re interacting with the one
document that is continually updated via JavaScript.
YouTube would probably be considered an MPA but it might actually be implemented
as an SPA in order to smooth out changes in content, intercepting navigations
and replacing the content via script—that is, until view transitions can help
with that.&lt;/p&gt;
&lt;p&gt;In either case, my surprise at the idea that MPAs will replace &lt;em&gt;all&lt;/em&gt; SPAs is
simple:
How would Figma or Photoshop for Web work as an MPA?
Or Slack, or Discord, or Google Maps?&lt;/p&gt;
&lt;p&gt;I’m currently working on an offline-first mobile Web app that stores data
locally and syncs to the server.
Wanting to be on the forefront of Web tech I investigated how we could
embrace MPAs.&lt;/p&gt;
&lt;p&gt;To keep a long story short, if we’re to retain our desired UX which has
independently navigable panels and our offline-first requirement, we &lt;em&gt;could&lt;/em&gt;
introduce some &lt;code&gt;&amp;#x3C;iframe&gt;&lt;/code&gt;s to partition out some of the functionality into
separate HTML requests (as opposed to separate script chunk requests)
and we could probably even pre-render some chunks sometimes.
The trouble is it would increase the complexity ten-fold
(two-way sync becomes three-way sync for a start) while providing no benefit to
customers whatsoever—instead it would almost certainly lead to more bugs,
more latency, and shipping features more slowly.&lt;/p&gt;
&lt;p&gt;Given that our app is not currently released I realise that’s a fairly weak
argument since no-one can look at the app and suggest a better approach so I’m
just asking you to trust me on this one.
I tried.
I really did.
It’s just not the right architecture for this particular app and I’m surprised
by the suggestion that &lt;em&gt;everything&lt;/em&gt; should be an MPA.&lt;/p&gt;
&lt;h2&gt;”All sites should work without JavaScript”&lt;/h2&gt;
&lt;p&gt;Continuing on our theme of Web development best practices, building a site
that works without JavaScript is an admirable goal.
Doing so probably means it degrades gracefully, has no JS blocking the initial
render, and works on a wide range of browsers.
But I’ve been surprised to see how often this becomes dogmatic:
“&lt;em&gt;all&lt;/em&gt; sites should work without JavaScript”.&lt;/p&gt;
&lt;p&gt;I guess it’s easy to come to this conclusion if &lt;em&gt;your&lt;/em&gt; site is able to work
without JavaScript (see &lt;a href=&quot;https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#my-blog-is-representative-of-web-development-at-large&quot;&gt;“My blog is representative of Web development at
large”&lt;/a&gt;)
but it feels a little myopic to me.&lt;/p&gt;
&lt;p&gt;I’ve mentioned Figma and Photoshop for Web before; it’s hard to imagine how
they could work without JavaScript. Likewise for a browser’s developer tools.
Or even &lt;a href=&quot;https://birtles.blog/2012/01/27/parapara-animation/&quot;&gt;Parapara Animation&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;Furthermore, although many advocates against JS are also concerned
about accessibility, JavaScript is often necessary in order to make an app
accessible.&lt;/p&gt;
&lt;p&gt;One thing the accessibility folks at Mozilla taught me about keyboard
navigation was that &lt;kbd&gt;Tab&lt;/kbd&gt; navigation should be fairly coarse.
That is, you use &lt;kbd&gt;Tab&lt;/kbd&gt; to navigate to the control group (e.g.
toolbar) and then use the arrow keys to move within that group.
That allows you to move around an app more quickly without having to
&lt;kbd&gt;Tab&lt;/kbd&gt; through every single control first.
WAI calls this a &lt;a href=&quot;https://www.w3.org/WAI/ARIA/apg/practices/keyboard-interface/#kbd_roving_tabindex&quot;&gt;“roving
tabindex”&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;However, in order to implement this kind of coarse-grained keyboard navigation
you’re going to need JavaScript.
If you want to make the arrow-key based navigation two-dimensional, you’re
going to need even more JavaScript.
Maybe one day we’ll fill that gap in the platform (looking at you,
&lt;a href=&quot;https://open-ui.org/components/focusgroup.explainer/&quot;&gt;focusgroup&lt;/a&gt;) but for now
you should feel no shame about using client-side JavaScript to make your app
accessible.&lt;/p&gt;
&lt;p&gt;Honestly, I think some sites should use &lt;em&gt;more&lt;/em&gt; JavaScript.&lt;/p&gt;
&lt;p&gt;As an example, the &lt;a href=&quot;https://www.11ty.dev/docs/&quot;&gt;Eleventy
documentation&lt;/a&gt; seems to avoid using client-side
JavaScript for the most part.
As Eleventy supports various templating languages it provides code samples in
each of the different languages.
Unfortunately, it doesn’t record which language you’ve selected so if your chosen
language is not the default one, you are forced to change tabs on &lt;em&gt;every
single&lt;/em&gt; code sample.
A little client-side JavaScript here would make the experience so much more
pleasant for users.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update (2024-01-11): It seem that Eleventy have taken this feedback
onboard and &lt;a href=&quot;https://twitter.com/eleven_ty/status/1745156260649959708&quot;&gt;fixed
this&lt;/a&gt;. Thank you!&lt;/em&gt; 🙏&lt;/p&gt;
&lt;h2&gt;“Web development shouldn’t need a build step”&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;While just about everything in this post is from 2022, while tidying it up
I couldn’t resist adding just one more recent idea that surprised me.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Our final stop on the Web development dogma train is a view that’s come up a few
times but still surprises me.
The most recent rendition I saw went something like, “we’re so blind and
stubborn that we’ve ended up with a hugely complex toolchain but we really
should be able to ship Web apps without a build step at all”.&lt;/p&gt;
&lt;p&gt;As someone who spent most of his career working with compiled languages the
desire to go without a build step is surprising.
The things compiler engineers do amaze me.
They are geniuses who layer clever optimization on top of clever optimization
transforming my very average code into something unrecognizable and insanely
fast.
If anything, I want more of that compiler magic in my Web development.&lt;/p&gt;
&lt;p&gt;Obviously JavaScript presents its own challenges since it can be very hard to
statically determine the side effects of a certain operation but I’m sure
there’s still more room to explore in optimizing JavaScript at compile time.&lt;/p&gt;
&lt;p&gt;Web developers seem to agree on optimizing image assets and pre-generating
static HTML pages where it makes sense, why is there resistance to optimizing
code assets too?
Why defer computation and I/O to runtime that can be done once at build time?
If nothing else, I have no desire to ship my megabyte-long comments cursing
iOS Safari to every user on every request.&lt;/p&gt;
&lt;p&gt;Maybe 2024 will be the year where client-side Rust/WASM frontend frameworks
start to get traction and if that’s the case, we’d better get used to
having a build step!&lt;/p&gt;
&lt;h2&gt;”My blog is representative of Web development at large”&lt;/h2&gt;
&lt;p&gt;A number of the points above could possibly be summarised as
“My blog is representative of Web development at large”.
That is, coming from browser engineer to Web developer, most of the notions
about Web development that have surprised me are the result of people
extrapolating their experience of the Web in a way that doesn’t overlap with
mine.&lt;/p&gt;
&lt;p&gt;Since I left Mozilla over four years ago, I’ve spent most of my time
working on a Web app.
I’ve also spent &lt;em&gt;way&lt;/em&gt; too long setting up this blog.
Surprisingly, with regards to tooling, architecture, or Web platform features
used, I’ve found almost no overlap between the two.
It’s almost as if blogs and apps exist in entirely disparate corners
of the Web development landscape.&lt;/p&gt;
&lt;p&gt;My app is a mass of TypeScript code, my blog uses almost no client-side
JavaScript.
My app is hugely complicated by two-directional data sync, my blog is
read-only.
My app uses webpack, Playwright E2E tests, a component framework, and a state
management library, my blog uses none of those.&lt;/p&gt;
&lt;p&gt;If you’re mostly engaged with one or the other, it’s easy to think that’s what
Web development looks like.
In truth, Web development is probably more diverse than any of us imagines.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There are other notions I’ve found surprising but the common theme in the
above is it’s easy to assume our experience of the Web is representative of
Web development in general.&lt;/p&gt;
&lt;p&gt;Moving from browser development back to Web development has been humbling
because it’s so much broader and deeper than I knew.
I have a much greater respect for Web developers, especially those at little Web
shops and startups that live or die by the success of their Web apps.&lt;/p&gt;
&lt;p&gt;If that’s you, I hope reading this post gives you confidence that even if
browser engineers, standards editors, and other Web developers insist on a
particular way of doing things, you know your constraints better than anyone
else and you’re probably doing things just fine.&lt;/p&gt;
&lt;h2&gt;Reflections a couple of months later&lt;/h2&gt;
&lt;p&gt;Since posting this article I’ve received some very useful feedback which I’ll
summarise below:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Some people pointed out that the background behind a lot of anti-JavaScript
and anti-SPA sentiment is a reaction to seeing static sites being rendered as
React SPAs which is a very poor fit. That was helpful context that I hadn’t
appreciated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Others clarified that the “no build step” argument is more about local
development and not about production assets. That makes a lot of sense and is
something I can appreciate.&lt;/p&gt;
&lt;p&gt;My point wasn’t to say you &lt;em&gt;should&lt;/em&gt; have a build step but simply to say that
coming from browser development I was surprised at the anti-build-step
sentiment because I’m used to compilers and I’d be interested in
seeing what more they can do for us.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Some people took issue with some of the later points because I failed to
clearly summarise my main contention. Here it is:&lt;/p&gt;
&lt;p&gt;I worked on browsers for over a decade and am still involved in Web
standards and browser development. &lt;em&gt;I love the platform and encourage
others to make full use of it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;My contention is with the absolute terms with which Web development best
practices are sometimes asserted.
Web development social media can be a fierce place—something I was sheltered
from when working on browsers.&lt;/p&gt;
&lt;p&gt;I’m certainly not trying to establish a new dogma but just to push back and
say that using JavaScript, writing an SPA, and having a build step is
sometimes the right choice and you shouldn’t feel bad about it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><comments>https://birtles.blog/2024/01/06/weird-things-engineers-believe-about-development/#comments</comments></item><item><title>Sharding Playwright tests by browser</title><link>https://birtles.blog/2023/12/17/sharding-playwright-tests-by-browser/</link><guid isPermaLink="true">https://birtles.blog/2023/12/17/sharding-playwright-tests-by-browser/</guid><description>2024-01-22: I’ve updated this to work with Playwright 1.41.

Last week started like every other week, meaning half a dozen projects
were broken by half a dozen incompatible dependency updates.
There were the usual suspects like
Lexical
but most noticeable was Playwright.
</description><pubDate>Sun, 17 Dec 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;strong&gt;2024-01-22:&lt;/strong&gt; I’ve updated this to work with Playwright 1.41.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Last week started like every other week, meaning half a dozen projects
were broken by half a dozen incompatible dependency updates.
There were the usual suspects like
&lt;a href=&quot;https://github.com/facebook/lexical/issues/5251&quot;&gt;Lexical&lt;/a&gt;
but most noticeable was &lt;a href=&quot;https://playwright.dev/&quot;&gt;Playwright&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Playwright had been more-or-less behaving up until 1.39, but
&lt;a href=&quot;https://github.com/microsoft/playwright/compare/v1.39.0...v1.40.0&quot;&gt;something in
1.40&lt;/a&gt;
was causing the WebKit tests to intermittently fail, a &lt;em&gt;lot&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Nothing in the &lt;a href=&quot;https://github.com/microsoft/playwright/compare/v1.39.0...v1.40.0&quot;&gt;commit
log&lt;/a&gt;
stood out except a few opaque &lt;code&gt;feat(webkit): roll to r1926&lt;/code&gt;-type commits
and there didn’t seem to be a pattern to the failures other than having to do
with text input and focus—which is basically all our tests.
So I decided to do the grown-up thing and collect some data.&lt;/p&gt;
&lt;h2&gt;Trying to be lazy&lt;/h2&gt;
&lt;p&gt;I asked ChatGPT for the simplest possible way to analyze the test data which
politely suggested I use Lambda to ingest data to DynamoDB or RDS coupled with
QuickSight, Angular and Flask and possibly Athena, ELK stack, DataDog and
Grafana.&lt;/p&gt;
&lt;p&gt;And this point I’m pretty sure ChatGPT was trolling me so instead I was forced to
use my own two fingers to query a search engine the old-fashioned way.
Fortunately that turned up the amazing &lt;a href=&quot;https://currents.dev/&quot;&gt;Currents&lt;/a&gt; which
was everything I was looking for and more.&lt;/p&gt;
&lt;p&gt;I spent a couple of hours setting it up “just right” and was thoroughly
impressed to see it live stream the test results.
Very nice work.&lt;/p&gt;
&lt;p&gt;The trouble came when I stepped into the office the next morning and got a mail
saying that while I was sleeping I’d hit the limit of the free tier.
I was about to to pull out my wallet until I calculated that for this little
project with its pitiful E2E test suite of only about 280 tests running on three
browser engines, it would cost about $500 per month to send all the test results
to &lt;a href=&quot;https://currents.dev&quot;&gt;Currents&lt;/a&gt;, or about 50 times as much as it costs to
actually run the tests 😬&lt;/p&gt;
&lt;p&gt;I suppose I could have tried to negotiate but I don’t think this AI was about
to give me a 98% price reduction.&lt;/p&gt;

&lt;video poster=&quot;https://birtles.blog/assets/currents-chatbot.png&quot;&gt;
&lt;source src=&quot;https://birtles.blog/assets/currents-chatbot.mp4&quot; type=&quot;video/mp4&quot;&gt;
&lt;p&gt;Looping screen capture of the Currents customer support chatbot.
    It features a 3D rendered head flicking backwards and forwards unnervingly
    and there&apos;s something odd like a metal plate attached to her head.&lt;/p&gt;
&lt;/video&gt;

&lt;p&gt;I backed out all my Currents setup but not all was lost.
In the process of setting it up, I’d been introduced to the magic of &lt;a href=&quot;https://playwright.dev/docs/test-sharding&quot;&gt;Playwright
test sharding&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Normally sharding splits your test runs up into roughly-equally sized
buckets that can be run in parallel but I wondered if you could split them up
by browser instead.
It turns out you can and it has a lot of advantages, but there are a few tricks
needed to get it to work.&lt;/p&gt;
&lt;h2&gt;Sharding by browser&lt;/h2&gt;
&lt;p&gt;Firstly, in our GitHub Actions workflow we set up a matrix based on the
different browsers we’re targeting:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;e2e:
  runs-on: ubuntu-latest
  name: E2E tests
  timeout-minutes: 20
  strategy:
    fail-fast: false
    matrix:
      browser: [chromium, firefox, webkit]
      include:
        - maxFailures: 10
        - maxFailures: 40
          browser: webkit
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This setup allows us to tweak the parameters used for each browser such as the
number of allowed failures or the number of workers, for example.&lt;/p&gt;
&lt;p&gt;Then we need to install Playwright but we can be a bit clever and only install
the dependencies needed for the browser we are running which will speed up CI
time even further.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;steps:
  - uses: actions/checkout@v4

  - uses: actions/setup-node@v4
    with:
      cache: yarn
      node-version: 18

  - name: Install
    run: yarn install

  # Playwright cache:
  #
  # Based on https://github.com/microsoft/playwright/issues/7249#issuecomment-1154603556
  #
  # Figures out the version of Playwright that&apos;s installed.
  #
  # The result is stored in steps.playwright-version.outputs.version
  - name: Get installed Playwright version
    id: playwright-version
    run: echo &quot;version=$(cat yarn.lock | grep &quot;^\&quot;@playwright\/test&quot; --after-context 1 | tail -n 1 | sed &apos;s/\s*version &quot;\([0-9.]\+\)&quot;/\1/&apos;)&quot; &gt;&gt; $GITHUB_OUTPUT

  # Attempt to restore the correct Playwright browser binaries based on the
  # currently installed version of Playwright (the browser binary versions
  # may change with Playwright versions).
  #
  # Note: Playwright&apos;s cache directory is hard coded because that&apos;s what it
  # says to do in the docs. There doesn&apos;t appear to be a command that prints
  # it out for us.
  - uses: actions/cache@v3
    id: playwright-cache
    with:
      path: &apos;~/.cache/ms-playwright&apos;
      key: &apos;${{ runner.os }}-playwright-${{ matrix.browser }}-${{ steps.playwright-version.outputs.version }}&apos;
      # As a fallback, if the Playwright version has changed, try use the
      # most recently cached version for this browser. There&apos;s a good
      # chance that the browser binary version hasn&apos;t been updated, so
      # Playwright can skip installing that in the next step.
      #
      # Note: When falling back to an old cache, `cache-hit` (used below)
      # will be `false`. This allows us to restore the potentially out of
      # date cache, but still let Playwright decide if it needs to download
      # new binaries or not.
      restore-keys: |
        ${{ runner.os }}-playwright-${{ matrix.browser }}-

  - name: Install Playwright with dependencies
    if: steps.playwright-cache.outputs.cache-hit != &apos;true&apos;
    run: npx playwright install --with-deps ${{ matrix.browser }}

  - name: Install Playwright&apos;s dependencies
    if: steps.playwright-cache.outputs.cache-hit == &apos;true&apos;
    run: npx playwright install-deps ${{ matrix.browser }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally we run the tests.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;- name: Run E2E tests
  run: yarn playwright test --project=${{ matrix.browser }} --max-failures ${{ matrix.maxFailures }} --workers 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With all that, our browsers run as separate tasks which means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CI run setup time is reduced since we only install the required dependencies
for one browser.&lt;/li&gt;
&lt;li&gt;You can adjust the run parameters separately by browser.&lt;/li&gt;
&lt;li&gt;You can potentially run different browsers on different hardware.&lt;/li&gt;
&lt;li&gt;You can tell at a glance &lt;em&gt;who&lt;/em&gt; you’re waiting on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s how it looks:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2023/12/17/sharding-playwright-tests-by-browser/tests-in-progress.png&quot; alt=&quot;Screenshot of GitHub pull request checks dialog with entries such as
&amp;#x22;Test / E2E tests (chromium)&amp;#x22; and &amp;#x22;Test / E2E tests (firefox)&amp;#x22;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Merging reports&lt;/h2&gt;
&lt;p&gt;One of the problems with sharding is that all your test results are sharded too.
Playwright, however, very conveniently provides &lt;a href=&quot;https://playwright.dev/docs/test-sharding#merge-reports-cli&quot;&gt;a
utility&lt;/a&gt; for
re-uniting them.&lt;/p&gt;
&lt;p&gt;The first step is to configure your tests to use the blob reporter.
So in &lt;code&gt;playwright.config.ts&lt;/code&gt; you might set your &lt;code&gt;reporter&lt;/code&gt; to something like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;reporter: process.env.CI ? [[&apos;github&apos;], [&apos;blob&apos;]] : &apos;list&apos;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;However, if we do that all the reports would have the same name and they’d
clobber each other when we tried to merge them.
When you shard using the regular &lt;code&gt;--shard 1/3&lt;/code&gt; approach Playwright
adjusts the name of the reports for you, but when you shard by browser you’re
on your own.&lt;/p&gt;
&lt;p&gt;Prior to Playwright 1.41 this was as simple as setting the
&lt;code&gt;PWTEST_BLOB_REPORT_NAME&lt;/code&gt; environment variable but 1.40 added a &lt;code&gt;fileName&lt;/code&gt;
option to the &lt;a href=&quot;https://playwright.dev/docs/test-reporters#blob-reporter&quot;&gt;blob
reporter&lt;/a&gt; which is a
little more cumbersome to use.&lt;/p&gt;
&lt;p&gt;First we need to stick our browser name in an environment variable.
For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-diff&quot;&gt; - name: Run E2E tests
   run: yarn playwright test --project=${{ matrix.browser }} --max-failures ${{ matrix.maxFailures }} --workers 2
+  env:
+    PWTEST_BOT_NAME: ${{ matrix.browser }}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, when we set up the reporter, we can pass that into the &lt;code&gt;fileName&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;reporter: process.env.CI
  ? [
      [&apos;github&apos;],
      [
        &apos;blob&apos;,
        {
          fileName: process.env.PWTEST_BOT_NAME
            ? `report-${process.env.PWTEST_BOT_NAME}.zip`
            : undefined,
        },
      ],
    ]
  : &apos;list&apos;,
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, once all shards are done, we upload the artifacts and merge them
together:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-yaml&quot;&gt;      - name: Upload any failure artifacts
        uses: actions/upload-artifact@v4
        if: always()
        with:
          # upload-artifact@v4 no longer permits overlapping artifact names so
          # we need to make the name unique
          name: blob-report-${{ matrix.browser }}
          path: blob-report
          retention-days: 1

  upload-reports:
    if: always()
    name: Upload Playwright reports
    needs: [e2e]
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          cache: yarn
          node-version: 18

      - name: Install
        run: yarn install

      - name: Download blob reports from GitHub Actions Artifacts
        uses: actions/download-artifact@v3
        with:
          path: all-blob-reports

      # download-artifact@v4 will download each artifact to a separate directory
      # based on the artifact name but merge-reports won&apos;t look into
      # subdirectories so we need to flatten the hierarchy.
      - name: Move reports into the same folder
        run: mv all-blob-reports/blob-report-*/*.zip all-blob-reports/

      - name: Merge into HTML Report
        run: npx playwright merge-reports --reporter html ./all-blob-reports

      - name: Upload HTML report
        uses: actions/upload-artifact@v4
        with:
          name: html-report-${{ github.run_attempt }}
          path: playwright-report
          retention-days: 14
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final report looks something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2023/12/17/sharding-playwright-tests-by-browser/playwright-report.png&quot; alt=&quot;Screenshot of HTML report showing various tests along with their state and
duration&quot;&gt;&lt;/p&gt;

&lt;p&gt;I suspect the reason it shows “webkit” and “chromium” twice next to each test
run is because it tags the results both by shard name and the engine (“project”
in Playwright terms) which happen to be the same in our case.&lt;/p&gt;
&lt;h2&gt;Back to debugging WebKit&lt;/h2&gt;
&lt;p&gt;I still haven’t worked out what’s going on with WebKit.
I’ve disabled half the tests from running on WebKit and it still takes four
times as long and fails ten times as often as Chrome and Firefox but working
that out is a subject for another blog or two.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2023/12/17/sharding-playwright-tests-by-browser/#comments</comments><category>Playwright</category><category>WebKit</category></item><item><title>In praise of WordPress</title><link>https://birtles.blog/2023/11/28/in-praise-of-wordpress/</link><guid isPermaLink="true">https://birtles.blog/2023/11/28/in-praise-of-wordpress/</guid><description>After over a year of fighting with Eleventy and then Astro to set up a this blog
just right I find myself needing to set up yet another blog,
this time for work.
I could just build on what I’ve got with Astro but I can’t help but wonder if
I would have been better off sticking with WordPress after all.
</description><pubDate>Tue, 28 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After over a year of fighting with Eleventy and then Astro to set up a this blog
&lt;em&gt;just right&lt;/em&gt; I find myself needing to set up yet another blog,
this time for work.
I could just build on what I’ve got with Astro but I can’t help but wonder if
I would have been better off sticking with WordPress after all.&lt;/p&gt;

&lt;p&gt;When I first got into Web development in the 90s I used to write little Visual
Basic programs to generate the HTML pages for the site.
It turns out spitting out HTML pages is easy enough that even before the
existence of GitHub and Node and every other part of a modern Web dev
toolchain, a high school kid could knock up a program to do it in their spare
time.&lt;/p&gt;
&lt;p&gt;So you’d think that with all the advances in Web tech in the last ~30 years,
generating a static site would be &lt;em&gt;amazing&lt;/em&gt; by now.
However, my lasting impression after struggling with Eleventy and Astro is just
how underwhelming it is.&lt;/p&gt;
&lt;p&gt;Even now, after months and months of tweaking and testing, my site still doesn’t
have a newsletter feature, the comments take about 10 minutes to show up, and I
just spent half a day trying to fix my one and only Netlify edge function
because I updated its dependencies and now it can’t figure out how to
dynamically load a WASM file forcing me to migrate the whole thing to AWS
instead.&lt;/p&gt;
&lt;p&gt;All this has made me appreciate just how great WordPress—where I used to
host this blog—was.&lt;/p&gt;
&lt;p&gt;With WordPress you get:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A WSYIWYG blog post editor&lt;/li&gt;
&lt;li&gt;Index pages by tag, day, month, year, etc. with pagination
(i.e. double-pagination, something which is particularly hard in Eleventy)&lt;/li&gt;
&lt;li&gt;Threaded comments with spam filtering and moderation features&lt;/li&gt;
&lt;li&gt;A login system so users can receive notification about replies via email&lt;/li&gt;
&lt;li&gt;Social images and metadata&lt;/li&gt;
&lt;li&gt;Draft blogs and instant previews&lt;/li&gt;
&lt;li&gt;An automatic newsletter system&lt;/li&gt;
&lt;li&gt;A search feature&lt;/li&gt;
&lt;li&gt;RSS feeds (by comparison, just look at how much trouble &lt;a href=&quot;https://birtles.blog/2023/10/02/rss-the-hard-way/&quot;&gt;setting up RSS in
Astro&lt;/a&gt; is)&lt;/li&gt;
&lt;li&gt;Media management, plugins, themes, commerce features and so on.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;WordPress has a reputation for being bloated—and WordPress sites certainly can
be—but if I’d spent half has much time optimizing a WordPress site as I
spent making this site, I’ll bet I could have made it fast enough that most
people would never notice.&lt;/p&gt;
&lt;p&gt;And I’ll bet WordPress experience is at least an order of magnitude more
marketable than Astro experience if I ever decide to go into consulting!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2023/11/28/in-praise-of-wordpress/#comments</comments><category>Blogging</category></item><item><title>RSS the hard way: Adventures with Astro Assets</title><link>https://birtles.blog/2023/10/02/rss-the-hard-way/</link><guid isPermaLink="true">https://birtles.blog/2023/10/02/rss-the-hard-way/</guid><description>2023-12-14: I’ve heavily updated this to work with Astro 4.0
but for posterity I’ve saved the old version in the Internet
Archive.

There’s something depressing about a blog about blogging.
I never wanted this to be one of those blogs.
But I’ve struggled so much with
Astro’s image feature
these past few weeks that I really hope it will benefit others
and amount to a bit more than one over-engineered RSS feed.
</description><pubDate>Mon, 02 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;&lt;strong&gt;2023-12-14:&lt;/strong&gt; I’ve heavily updated this to work with Astro 4.0
but for posterity I’ve &lt;a href=&quot;https://web.archive.org/web/20231214063201/https://birtles.blog/2023/10/02/rss-the-hard-way/&quot;&gt;saved the old version in the Internet
Archive&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There’s something depressing about a blog about blogging.
I never wanted this to be one of &lt;em&gt;those&lt;/em&gt; blogs.
But I’ve struggled so much with
&lt;a href=&quot;https://docs.astro.build/guides/images/&quot;&gt;Astro’s image feature&lt;/a&gt;
these past few weeks that I really hope it will benefit others
and amount to a bit more than one over-engineered RSS feed.&lt;/p&gt;

&lt;h2&gt;First step, “fixing” lazy loading&lt;/h2&gt;
&lt;p&gt;Before we get into RSS, I want to introduce Astro’s image feature by looking at
a simpler problem: lazy loading.&lt;/p&gt;
&lt;p&gt;Astro very helpfully lets you reference images from a Markdown file using
a relative path.
In other words, you can have a Markdown file
&lt;code&gt;src/content/posts/blog-a-log/index.md&lt;/code&gt; and write:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-markdown&quot;&gt;Look at this picture:
![Amazing picture](./picture.jpg)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Astro will find the picture at &lt;code&gt;src/content/posts/blog-a-log/picture.jpg&lt;/code&gt;,
copy it to your &lt;code&gt;dist/assets&lt;/code&gt; folder, generate a WebP version, then create an
&lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; tag in your generated HTML complete with &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; attributes
for reducing
&lt;a href=&quot;https://web.dev/cls/&quot;&gt;CLS&lt;/a&gt; badness.
That way your images can live happily alongside their corresponding Markdown
files.&lt;/p&gt;
&lt;p&gt;Awesome.&lt;/p&gt;
&lt;p&gt;But Astro &lt;em&gt;also&lt;/em&gt; takes the liberty of slapping
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/API/HTMLImageElement/loading&quot;&gt;&lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt;&lt;/a&gt;
on &lt;em&gt;every&lt;/em&gt; &lt;em&gt;single&lt;/em&gt; &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;That’s not awesome because:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;If the image is “above the fold” it will hurt your &lt;a href=&quot;https://web.dev/lcp/&quot;&gt;LCP&lt;/a&gt; score.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It can be distracting to read blogs with &lt;code&gt;loading=&quot;lazy&quot;&lt;/code&gt; since you can
see the images load as you scroll through the page.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It’s annoying when you enter a tunnel on the train and can no longer see the
images in the rest of the article.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;How can you fix it? According to &lt;a href=&quot;https://github.com/withastro/astro/issues/6611#issuecomment-1567533144&quot;&gt;the Astro issue
tracker&lt;/a&gt;,
you &lt;em&gt;can’t&lt;/em&gt; fix it from Markdown.
Instead you have to make your own image service.&lt;/p&gt;
&lt;p&gt;That sounds really hard but it turns out to be quite simple.&lt;/p&gt;
&lt;p&gt;For example, if you’re already &lt;a href=&quot;https://docs.astro.build/en/guides/assets/#using-sharp&quot;&gt;using the sharp image
service&lt;/a&gt;
you can wrap it like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import sharpImageService from &apos;astro/assets/services/sharp&apos;;

export const nonLazySharpServiceConfig = () =&gt; ({
  entrypoint: &apos;src/utils/non-lazy-sharp-service&apos;,
  config: {},
});

/**
 * A fork of the sharp image service that drops the loading=&quot;lazy&quot;
 * attribute from outputted image tags since it can hurt LCP scores (and is
 * generally annoying when scrolling the page).
 */
const nonLazySharpService = {
  validateOptions: sharpImageService.validateOptions,
  getURL: sharpImageService.getURL,
  parseURL: sharpImageService.parseURL,
  getHTMLAttributes: (options, serviceOptions) =&gt; {
    const result = sharpImageService.getHTMLAttributes(options, serviceOptions);
    delete result.loading;
    return result;
  },
  transform: sharpImageService.transform,
};

export default nonLazySharpService;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Drop that in, e.g. &lt;code&gt;src/utils/non-lazy-sharp-service.js&lt;/code&gt;, and include it in
&lt;code&gt;astro.config.js&lt;/code&gt; in place of &lt;code&gt;sharpImageService()&lt;/code&gt; and you’re done.
Eager loading all around.&lt;/p&gt;
&lt;p&gt;If you get errors like the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;No loader is configured for &quot;.node&quot; files: node_modules/sharp/build/Release/sharp-linux-x64.node
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;you’ll also need to exclude the sharp binary from the bundle by adding something
like the following to your vite config:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;  optimizeDeps: { exclude: [&apos;sharp&apos;] },
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The hard bit: RSS&lt;/h2&gt;
&lt;p&gt;Now onto the hard problem.
I had set up a pretty solid &lt;a href=&quot;https://birtles.blog/feed.xml&quot;&gt;RSS feed&lt;/a&gt; using &lt;a href=&quot;https://docs.astro.build/guides/rss/&quot;&gt;Astro’s RSS
feature&lt;/a&gt; because, if you’re setting up
a blog, apparently you should have an RSS feed.&lt;/p&gt;
&lt;p&gt;I’ve never used an RSS feed reader but I like the idea.
I decided to double-check &lt;a href=&quot;https://feedly.com/i/subscription/feed%2Fhttps%3A%2F%2Fbirtles.blog%2Ffeed.xml&quot;&gt;my awesome RSS feed with
Feedly&lt;/a&gt;
only to be devastated by the lack of pretty pictures.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2023/10/02/rss-the-hard-way/no-pictures.png&quot; alt=&quot;Screenshot of the Feedly post summary showing very vacant looking thumbnails&quot;&gt;&lt;/p&gt;

&lt;p&gt;Check out that follower count too.&lt;/p&gt;


&lt;p&gt;Inspecting the source of the RSS feed itself it turns out all the images were
still using the relative path from the source file, i.e. &lt;code&gt;./picture.jpg&lt;/code&gt; from
above.
So “all we need to do” is adjust those paths to the final resolved paths.
How card could it possibly be?
&lt;em&gt;(Spoiler: very very hard)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It turns out images in Astro go on quite the journey from being announced in
Markdown to finally appearing in HTML ready for showtime.&lt;/p&gt;
&lt;h3&gt;From Markdown to optimized HTML&lt;/h3&gt;
&lt;p&gt;Astro is built on &lt;a href=&quot;https://vitejs.dev/&quot;&gt;vite&lt;/a&gt;.
Before encountering this problem I’d been trying my hardest to &lt;em&gt;not&lt;/em&gt; know what
vite is so, if you’re like me, all you really need to know is vite is like
webpack but built on &lt;a href=&quot;https://rollupjs.org/&quot;&gt;rollup&lt;/a&gt;, which is also like
webpack.&lt;/p&gt;
&lt;p&gt;That last point is important because as you’re cruising the Astro source code
you’ll see things like &lt;code&gt;this.resolve()&lt;/code&gt; and will surely wonder where on earth
they’re defined.
It turns &lt;code&gt;this.resolve()&lt;/code&gt; and a whole lot of other functions attached to &lt;code&gt;this&lt;/code&gt;
are part of the &lt;a href=&quot;https://rollupjs.org/plugin-development/#plugin-context&quot;&gt;Rollup plugin
API&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With that background out of the way, the journey from Markdown image to
optimized HTML image goes something like this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Astro registers a vite plugin called
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/vite-plugin-markdown/index.ts&quot;&gt;&lt;code&gt;vite-plugin-markdown&lt;/code&gt;&lt;/a&gt;
which handles any &lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/core/constants.ts#L5-L12&quot;&gt;Markdown
files&lt;/a&gt;
it encounters.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;vite-plugin-markdown&lt;/code&gt; parses the Markdown using
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/markdown/remark/src/index.ts&quot;&gt;&lt;code&gt;@astrojs/markdown-remark&lt;/code&gt;&lt;/a&gt;
which basically wraps up the &lt;a href=&quot;https://github.com/remarkjs/remark&quot;&gt;&lt;code&gt;remark&lt;/code&gt;&lt;/a&gt;
library and configures a bunch of plugins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/markdown/remark/src/remark-collect-images.ts&quot;&gt;&lt;code&gt;remarkCollectImages&lt;/code&gt;&lt;/a&gt;
plugin extracts all the relative image paths that should be optimized and
stores them in the Markdown virtual file metadata.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After converting the Markdown to HTML another plugin,
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/markdown/remark/src/rehype-images.ts&quot;&gt;&lt;code&gt;rehypeImages&lt;/code&gt;&lt;/a&gt;,
looks for any &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt; elements whose &lt;code&gt;src&lt;/code&gt; matches one of the paths we
found in the previous step.
For any matching &lt;code&gt;&amp;#x3C;img&gt;&lt;/code&gt;s it drops the &lt;code&gt;src&lt;/code&gt; attribute and adds an
&lt;code&gt;__ASTRO_IMAGE__&lt;/code&gt; one in its place with the same value.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Back in &lt;code&gt;vite-plugin-markdown&lt;/code&gt; we read back all the image paths from the
third step and resolve them using &lt;a href=&quot;https://rollupjs.org/plugin-development/#this-resolve&quot;&gt;Rollup’s &lt;code&gt;resolve&lt;/code&gt;
API&lt;/a&gt;
turning &lt;code&gt;./picture.jpg&lt;/code&gt; into
&lt;code&gt;/home/me/blog/src/content/posts/blog-a-log/picture.jpg&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Finally, we export a big template string of TypeScript code in place of the
Markdown file that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Includes a map of image paths from the relative image paths to their fully
resolved paths.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Takes the HTML we generated previously and runs a regex on it to replace
all those &lt;code&gt;__ASTRO_IMAGE__&lt;/code&gt; attributes with the corresponding resolved path
from the map of image paths.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That’s the overview, but we glossed over a lot of details with regard to the
image path map in the second last bullet point.&lt;/p&gt;
&lt;p&gt;The template string to generate the map looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;return `
    import { getImage } from &quot;astro:assets&quot;;
    ${imagePaths
      .map(
        (entry) =&gt;
          `import Astro__${entry.safeName} from ${JSON.stringify(entry.raw)};`
      )
      .join(&apos;\n&apos;)}

    const images = async function() {
      return {
        ${imagePaths
          .map(
            (entry) =&gt;
              `&quot;${entry.raw}&quot;: await getImage({src: Astro__${entry.safeName}})`
          )
          .join(&apos;,\n&apos;)}
        }
      }
     //...
  `;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The mix of executed code and generated code here is a bit of a mind-bender but
there are two important points.&lt;/p&gt;
&lt;p&gt;Firstly, the
&lt;code&gt;import Astro__${entry.safeName} from ${JSON.stringify(entry.raw)};&lt;/code&gt;
part hides the fact that this is triggering yet &lt;em&gt;another&lt;/em&gt; vite plugin.
This time it’s the
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/assets/vite-plugin-assets.ts&quot;&gt;&lt;code&gt;vite-plugin-assets&lt;/code&gt;&lt;/a&gt;
plugin.&lt;/p&gt;
&lt;p&gt;By importing an image using ESM we arrive at the &lt;code&gt;astro:assets:esm&lt;/code&gt; section of
that plugin which calls
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/assets/utils/emitAsset.ts#L8&quot;&gt;&lt;code&gt;emitESMImage&lt;/code&gt;&lt;/a&gt;.
&lt;code&gt;emitESMImage&lt;/code&gt; emits the file using Rollup’s
&lt;a href=&quot;https://rollupjs.org/plugin-development/#this-emitfile&quot;&gt;emitFile&lt;/a&gt; API and
returns the image metadata like the &lt;code&gt;width&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; as well as a handle to
the image in the form &lt;code&gt;__ASTRO_ASSET_IMAGE__${handle}__&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In effect, this takes something like
&lt;code&gt;/home/me/blog/src/content/posts/blog-a-log/picture.jpg&lt;/code&gt; and returns a handle
like &lt;code&gt;_⁠_ASTRO_ASSET_IMAGE__6cf702f7__&lt;/code&gt; where &lt;code&gt;6cf702f7&lt;/code&gt; is the &lt;code&gt;referenceId&lt;/code&gt;
returned by &lt;code&gt;emitFile&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, in the
&lt;a href=&quot;https://rollupjs.org/plugin-development/#renderchunk&quot;&gt;&lt;code&gt;renderChunk&lt;/code&gt;&lt;/a&gt; hook of
the same plugin, it finds the &lt;code&gt;_⁠_ASTRO_ASSET_IMAGE__6cf702f7__&lt;/code&gt; handle,
extracts the &lt;code&gt;referenceId&lt;/code&gt; &lt;code&gt;6cf702f7&lt;/code&gt;, looks it up using Rollup’s
&lt;a href=&quot;https://rollupjs.org/plugin-development/#this-getfilename&quot;&gt;&lt;code&gt;this.getFileName&lt;/code&gt;&lt;/a&gt;
and gets back &lt;code&gt;assets/picture.b5a66e4a.jpg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Secondly, we pass the metadata returned from &lt;code&gt;emitESMImage&lt;/code&gt; including the
now-resolved &lt;code&gt;src&lt;/code&gt; (i.e. &lt;code&gt;assets/picture.b5a66e4a.jpg&lt;/code&gt;) along to
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/assets/internal.ts#L72&quot;&gt;&lt;code&gt;getImage&lt;/code&gt;&lt;/a&gt;.
&lt;code&gt;getImage&lt;/code&gt; calls our image service which calls
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/assets/vite-plugin-assets.ts#L84&quot;&gt;&lt;code&gt;addStaticImage&lt;/code&gt;&lt;/a&gt;
from &lt;code&gt;vite-plugin-assets&lt;/code&gt; to ensure that our WebP image gets generated.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;addStaticImage&lt;/code&gt; adds its own hash to the resulting file producing something
like &lt;code&gt;/assets/picture.b5a66e4a_13mnAp.webp&lt;/code&gt; which &lt;code&gt;getImage&lt;/code&gt; forwards on.&lt;/p&gt;
&lt;h3&gt;Getting the resolved path in our RSS feed&lt;/h3&gt;
&lt;p&gt;So, how do we get from &lt;code&gt;./picture.jpg&lt;/code&gt; to &lt;code&gt;/assets/picture.b5a66e4a_13mnAp.webp&lt;/code&gt;
in our RSS feed?&lt;/p&gt;
&lt;p&gt;Summarising the above, there are roughly four steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Get all the suitable relative images from the Markdown file (e.g.
&lt;code&gt;./picture.jpg&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resolve the absolute path on disk for each (e.g.
&lt;code&gt;/home/me/blog/src/content/posts/blog-a-log/picture.jpg&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Emit the file as part of our Rollup build producing, e.g.,
&lt;code&gt;assets/picture.b5a66e4a.jpg&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Get the path of the optimized version of the file (e.g.
&lt;code&gt;assets/picture.b5a66e4a_13mnAp.webp&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Pretty straightforward except step 3. Step 3 is trouble.&lt;/p&gt;
&lt;h4&gt;Step 1: Collecting the relative images&lt;/h4&gt;
&lt;p&gt;In order to include an HTML version of our posts in the RSS feed we need to
do our own Markdown processing.&lt;/p&gt;
&lt;p&gt;The
&lt;a href=&quot;https://docs.astro.build/en/guides/rss/#including-full-post-content&quot;&gt;Astro docs&lt;/a&gt;
suggest using
&lt;a href=&quot;https://github.com/markdown-it/markdown-it&quot;&gt;&lt;code&gt;markdown-it&lt;/code&gt;&lt;/a&gt; or similar for this.
I decided to use &lt;a href=&quot;https://github.com/remarkjs/remark&quot;&gt;&lt;code&gt;remark&lt;/code&gt;&lt;/a&gt; so that I can
re-use plugins between parsing Markdown for regular display and for generating
HTML previews.&lt;/p&gt;
&lt;p&gt;Doing that means we can re-use Astro’s remark plugin for extracting relative
images like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;import { remarkCollectImages } from &apos;@astrojs/markdown-remark&apos;;
// ...

// Using a singleton parser improves performance _dramatically_
const postParser = unified()
  .use(remarkParse)
  .use(remarkCollectImages)
  .use(remarkRehype)
  .use(rehypeSanitize)
  .use(rehypeStringify);

// When generating each RSSItem we do:
const content = await postParser.process({ path, value: post.body });
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note that although Remark will accept the markdown content (&lt;code&gt;post.body&lt;/code&gt;
above) by itself, we also need to pass the &lt;em&gt;path&lt;/em&gt; of the Markdown file too or
else &lt;code&gt;remarkCollectImages&lt;/code&gt; will &lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/markdown/remark/src/remark-collect-images.ts#L8&quot;&gt;skip it&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Step 2: Resolving the absolute path on disk&lt;/h4&gt;
&lt;p&gt;Astro resolves relative paths with the following code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;(await this.resolve(imagePath, id))?.id ??
  path.join(path.dirname(id), imagePath);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first part uses Rollup’s
&lt;a href=&quot;https://rollupjs.org/plugin-development/#this-resolve&quot;&gt;this.resolve&lt;/a&gt;
which ends up running any plugins registered for the &lt;code&gt;resolveId&lt;/code&gt; hook.&lt;/p&gt;
&lt;p&gt;In Astro’s case, that includes the &lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/vite-plugin-config-alias/index.ts#L63&quot;&gt;&lt;code&gt;configAliasVitePlugin&lt;/code&gt;
plugin&lt;/a&gt;
which picks up your &lt;code&gt;tsconfig.json&lt;/code&gt; and applies any aliases from the
&lt;a href=&quot;https://www.typescriptlang.org/tsconfig#paths&quot;&gt;&lt;code&gt;paths&lt;/code&gt; section&lt;/a&gt;
but fortunately Astro 3
&lt;a href=&quot;https://github.com/withastro/astro/commit/2484dc4080e5cd84b9a53648a1de426d7c907be2&quot;&gt;dropped&lt;/a&gt;
the alias it added there so we can ignore that plugin.&lt;/p&gt;
&lt;p&gt;Instead, we can just add another plugin that operates
on the HTML—a &lt;a href=&quot;https://github.com/rehypejs/rehype&quot;&gt;rehype&lt;/a&gt; plugin—that picks
up the extracted image references and locates them on disk like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export function rehypeAstroImages(options) {
  return async function (tree, file) {
    if (
      !file.path ||
      !(file.data.imagePaths instanceof Set) ||
      !file.data.imagePaths?.size
    ) {
      return;
    }

    const imageNodes = [];
    const imagesToResolve = new Map();
    visit(tree, (node) =&gt; {
      if (
        node.type !== &apos;element&apos; ||
        node.tagName !== &apos;img&apos; ||
        typeof node.properties?.src !== &apos;string&apos; ||
        !node.properties?.src ||
        !file.data.imagePaths.has(node.properties.src)
      ) {
        return;
      }

      if (imagesToResolve.has(node.properties.src)) {
        imageNodes.push(node);
        return;
      }

      const absolutePath = path.resolve(
        path.dirname(file.path),
        node.properties.src
      );

      if (!fs.existsSync(absolutePath)) {
        return;
      }

      imageNodes.push(node);
      imagesToResolve.set(node.properties.src, absolutePath);
    });

    // ... to be continued
  };
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 3: Getting the path to the asset produced by Rollup&lt;/h4&gt;
&lt;p&gt;This is where it gets hard.
It seems like we could just call
&lt;a href=&quot;https://rollupjs.org/plugin-development/#this-emitfile&quot;&gt;&lt;code&gt;this.emitFile&lt;/code&gt;&lt;/a&gt;, grab
the &lt;code&gt;referenceId&lt;/code&gt; then look it up with
&lt;a href=&quot;https://rollupjs.org/plugin-development/#this-getfilename&quot;&gt;&lt;code&gt;this.getFileName&lt;/code&gt;&lt;/a&gt;.
But that requires having a Rollup plugin context to work with.&lt;/p&gt;
&lt;p&gt;Many parts of the Astro codebase do this sort of thing.
&lt;code&gt;emitESMImage&lt;/code&gt; itself takes &lt;code&gt;this.emitFile&lt;/code&gt; as an argument.
Many other places take a plugin context as an argument.
But where do we get a plugin context from in the middle of generating our RSS?&lt;/p&gt;
&lt;p&gt;This is where I get stuck and I hope someone reading this blog can tell
me an easy way to do this.
I fear the &lt;em&gt;right&lt;/em&gt; way might involve creating yet another vite plugin and
exporting TypeScript template strings and other messy business so for now I’ve
implemented the hacky way: shadow what Rollup does very poorly and hope it’s
enough.&lt;/p&gt;
&lt;p&gt;Specifically, we want to shadow how Rollup goes from &lt;code&gt;&amp;#x3C;absolute path&gt;/picture.jpg&lt;/code&gt; to &lt;code&gt;assets/picture.&amp;#x3C;hash&gt;.jpg&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;First the hash. Rollup has a function
&lt;a href=&quot;https://github.com/rollup/rollup/blob/v4.2.0/src/utils/crypto.ts#L4&quot;&gt;&lt;code&gt;getXxhash&lt;/code&gt;&lt;/a&gt;
which calls into
&lt;a href=&quot;https://github.com/rollup/rollup/blob/v4.2.0/rust/xxhash/src/lib.rs&quot;&gt;&lt;code&gt;xxhashBase64Url&lt;/code&gt;&lt;/a&gt;
that boils down to the following Rust code:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-rust&quot;&gt;use base64::{engine::general_purpose, Engine as _};
use xxhash_rust::xxh3::xxh3_128;

pub fn xxhash_base64_url(input: &amp;#x26;[u8]) -&gt; String {
  let hash = xxh3_128(input).to_le_bytes();
  general_purpose::URL_SAFE_NO_PAD.encode(hash)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It’s using the XXH3_128 variant of the &lt;a href=&quot;https://xxhash.com/&quot;&gt;xxHash&lt;/a&gt; algorithm
and encoding into base64.
Unfortunately none of the Node implementations of xxHash I could find support
the 128-bit variant but fortunately Rollup publishes a WASM version of its
binaries under
&lt;a href=&quot;https://www.npmjs.com/package/@rollup/wasm-node&quot;&gt;@rollup/wasm-node&lt;/a&gt;.
As a result we can install &lt;code&gt;@rollup/wasm-node&lt;/code&gt; and import the hashing function
as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { xxhashBase64Url } from &apos;@rollup/wasm-node/dist/wasm-node/bindings_wasm.js&apos;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That will generate a rather long hash but Rollup only uses a part of it
in the filename.
In fact, the filename generation is quite involved…&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-ts&quot;&gt;function generateAssetFileName(
  name: string | undefined,
  source: string | Uint8Array,
  sourceHash: string,
  outputOptions: NormalizedOutputOptions,
  bundle: OutputBundleWithPlaceholders
): string {
  const emittedName = outputOptions.sanitizeFileName(name || &apos;asset&apos;);
  return makeUnique(
    renderNamePattern(
      typeof outputOptions.assetFileNames === &apos;function&apos;
        ? outputOptions.assetFileNames({ name, source, type: &apos;asset&apos; })
        : outputOptions.assetFileNames,
      &apos;output.assetFileNames&apos;,
      {
        ext: () =&gt; extname(emittedName).slice(1),
        extname: () =&gt; extname(emittedName),
        hash: (size) =&gt;
          sourceHash.slice(0, Math.max(0, size || defaultHashSize)),
        name: () =&gt;
          emittedName.slice(
            0,
            Math.max(0, emittedName.length - extname(emittedName).length)
          ),
      }
    ),
    bundle
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Looking at the important bits here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rollup/rollup/blob/v4.2.0/src/utils/sanitizeFileName.ts#L6&quot;&gt;&lt;code&gt;sanitizeFileName&lt;/code&gt;&lt;/a&gt;
is only dealing with drive letters and things so hopefully we can ignore that
👍&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rollup/rollup/blob/v4.2.0/src/utils/renderNamePattern.ts#L40&quot;&gt;&lt;code&gt;makeUnique&lt;/code&gt;&lt;/a&gt;
ensures the filename doesn’t clash but since we’re including a bit of hash in
the filename hopefully we’re ok 🤞&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/rollup/rollup/blob/v4.2.0/src/utils/renderNamePattern.ts#L7&quot;&gt;&lt;code&gt;renderNamePattern&lt;/code&gt;&lt;/a&gt; is problematic.
It implements the asset format defined by
&lt;a href=&quot;https://rollupjs.org/configuration-options/#output-assetfilenames&quot;&gt;&lt;code&gt;output.assetFileNames&lt;/code&gt;&lt;/a&gt;
which we’re likely to want to override 😬&lt;/p&gt;
&lt;p&gt;In fact, my Astro config already does:&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;export default defineConfig({
  // ...
  vite: {
    build: {
      rollupOptions: {
        output: {
          assetFileNames: (assetInfo) =&gt; {
            if (assetInfo.name === &apos;style.css&apos;) {
              return &apos;css/styles.[hash][extname]&apos;;
            }
            return &apos;assets/[name].[hash][extname]&apos;;
          },
        },
      },
    },
  },
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, unfortunately, as far as I can tell Astro doesn’t provide any easy way to
access configuration values and as &lt;a href=&quot;https://flaviocopes.com/astro-access-configuration/&quot;&gt;someone else
discovered&lt;/a&gt;, simplying
importing &lt;code&gt;astro.config.js&lt;/code&gt; no longer works either.&lt;/p&gt;
&lt;p&gt;You &lt;em&gt;can&lt;/em&gt; access the config using an
&lt;a href=&quot;https://docs.astro.build/en/reference/integrations-reference/&quot;&gt;integration&lt;/a&gt;
but if you try loading the same integration when generating RSS you’ll be
disappointed to learn that it’s executing in a different context so you
can’t share the config you gleaned from the integration API.&lt;/p&gt;
&lt;p&gt;At this point, the simplest thing is just to move the vite config to a separate
file, &lt;code&gt;vite.config.js&lt;/code&gt; so it can be imported separately from both
&lt;code&gt;astro.config.js&lt;/code&gt; and our rehype plugin.&lt;/p&gt;
&lt;p&gt;With our &lt;code&gt;output.assetFileNames&lt;/code&gt; option finally available, we can proceed to
fork Rollup’s &lt;code&gt;generateAssetFileName&lt;/code&gt; into just the parts we need.
We don’t need most of the validation code since presumably that’s going to be
run when we generate the &lt;em&gt;actual&lt;/em&gt; asset.&lt;/p&gt;
&lt;p&gt;Putting it altogether we have something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import * as fs from &apos;node:fs&apos;;
import * as path from &apos;node:path&apos;;
import { xxhashBase64Url } from &apos;@rollup/wasm-node/dist/wasm-node/bindings_wasm.js&apos;;

/**
 * @param {string} absolutePath
 * @param {Buffer} data
 * @param {string=} assetsDir
 * @param {ViteConfig=} viteConfig
 */
function getImageAssetFileName(absolutePath, data, assetsDir, viteConfig) {
  const source = new Uint8Array(data);
  const sourceHash = getImageHash(source);

  if (Array.isArray(viteConfig?.build?.rollupOptions?.output)) {
    throw new Error(&quot;We don&apos;t know how to handle multiple output options 😬&quot;);
  }

  // Defaults to _astro
  //
  // https://docs.astro.build/en/reference/configuration-reference/#buildassets
  assetsDir = assetsDir || &apos;_astro&apos;;

  // Defaults to `${settings.config.build.assets}/[name].[hash][extname]`
  //
  // https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/core/build/static-build.ts#L208C22-L208C78
  const assetFileNames =
    viteConfig?.build?.rollupOptions?.output?.assetFileNames ||
    `${assetsDir}/[name].[hash][extname]`;

  return generateAssetFileName(
    path.basename(absolutePath),
    source,
    sourceHash,
    assetFileNames
  );
}

function getImageHash(imageSource) {
  return xxhashBase64Url(imageSource).slice(0, 8);
}

function generateAssetFileName(name, source, sourceHash, assetFileNames) {
  const defaultHashSize = 8;

  return renderNamePattern(
    typeof assetFileNames === &apos;function&apos;
      ? assetFileNames({ name, source, type: &apos;asset&apos; })
      : assetFileNames,
    {
      ext: () =&gt; path.extname(name).slice(1),
      extname: () =&gt; path.extname(name),
      hash: (size) =&gt; sourceHash.slice(0, Math.max(0, size || defaultHashSize)),
      name: () =&gt;
        name.slice(0, Math.max(0, name.length - path.extname(name).length)),
    }
  );
}

function renderNamePattern(pattern, replacements) {
  return pattern.replace(/\[(\w+)(:\d+)?]/g, (_match, type, size) =&gt;
    replacements[type](size &amp;#x26;&amp;#x26; Number.parseInt(size.slice(1)))
  );
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Step 4: Getting the path to the optimized asset&lt;/h4&gt;
&lt;p&gt;Now that we have the asset name that Rollup is (hopefully) going to produce,
getting the path to the optimized asset is easy since Astro helpfully provides
the
&lt;a href=&quot;https://docs.astro.build/en/guides/images/#generating-images-with-getimage&quot;&gt;&lt;code&gt;getImage&lt;/code&gt;
function&lt;/a&gt;
for this.&lt;/p&gt;
&lt;p&gt;Continuing our rehype plugin, we can resolve the references as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;import { getImage } from &apos;astro:assets&apos;;
import { imageMetadata } from &apos;astro/assets/utils&apos;;

// ...

const imagePromises = [];
for (const [relativePath, absolutePath] of imagesToResolve.entries()) {
  imagePromises.push(
    fs.promises
      .readFile(absolutePath)
      .then(
        (buffer) =&gt;
          /** @type Promise&amp;#x3C;[ImageMetadata, Buffer]&gt; */
          new Promise((resolve) =&gt; {
            imageMetadata(buffer).then((meta) =&gt; {
              resolve([meta, buffer]);
            });
          })
      )
      .then(([meta, buffer]) =&gt; {
        if (!meta) {
          throw new Error(`Failed to get metadata for image ${relativePath}`);
        }

        const fileUrl = url.pathToFileURL(absolutePath);
        fileUrl.searchParams.append(&apos;origWidth&apos;, meta.width.toString());
        fileUrl.searchParams.append(&apos;origHeight&apos;, meta.height.toString());
        fileUrl.searchParams.append(&apos;origFormat&apos;, meta.format);
        const assetPath =
          &apos;/@fs&apos; +
          absolutize(url.fileURLToPath(fileUrl) + fileUrl.search).replace(
            /\\/g,
            &apos;/&apos;
          );

        return getImage({ src: { ...meta, src: assetPath } });
      })
      .then((image) =&gt; [
        relativePath,
        { src: image.src, attributes: image.attributes },
      ])
  );
}

// Process the result
const resolvedImages = new Map();
for (const result of await Promise.allSettled(imagePromises)) {
  if (result.status === &apos;fulfilled&apos;) {
    resolvedImages.set(...result.value);
  } else {
    console.warn(&apos;Failed to resolve image&apos;, result.reason);
  }
}

for (const node of imageNodes) {
  const imageDetails = resolvedImages.get(node.properties.src);
  if (imageDetails) {
    const { src: resolvedSrc, attributes } = imageDetails;
    if (options.rootUrl) {
      node.properties.src = new URL(resolvedSrc, options.rootUrl).toString();
    } else {
      node.properties.src = absolutize(resolvedSrc);
    }
    node.properties.width = attributes.width;
    node.properties.height = attributes.height;
  }
}

function absolutize(path) {
  return !path.startsWith(&apos;/&apos;) ? `/${path}` : path;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;Epilogue: Ship it!&lt;/h4&gt;
&lt;p&gt;We did it! Having finally tamed Astro Assets I thought it was time I unleashed
my abomination on the world as a brand new drop-in package.
I spent half a day setting up the repo and npm package “just right”, popped into
into my blog and fired up a build only to get…&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error [ERR_UNSUPPORTED_ESM_URL_SCHEME]: Only URLs with a scheme
in: file and data are supported by the default ESM loader.
Received protocol &apos;astro:&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It turns out all these fancy vite plugins and virtual modules in Astro aren’t
applied to code under &lt;code&gt;node_modules&lt;/code&gt;?
I tried to brute force my way past the first error but next it was
&lt;a href=&quot;https://github.com/withastro/astro/blob/astro%404.0.3/packages/astro/src/assets/internal.ts#L55-L58&quot;&gt;&lt;code&gt;virtual:image-service&lt;/code&gt;&lt;/a&gt;
that was not reachable.&lt;/p&gt;
&lt;p&gt;I tried to persuade Rollup to do its thing for my module too but with no luck.&lt;/p&gt;
&lt;p&gt;By this point I have to conclude that all this code is just not the Astro way to
do things.
The correct approach probably involves a bundle of vite plugins writing
Typescript template string incantations but I’ve spent &lt;em&gt;way&lt;/em&gt; too much
on this problem by now so in lieu of an npm package I have &lt;a href=&quot;https://gist.github.com/birtles/28d5bfb1e1fa0d62b3e96ac640a2bc8c&quot;&gt;a
gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I look forward to someone reviewing my code and telling me all the places I did
it wrong!&lt;/p&gt;
&lt;p&gt;Unfortunately, it looks like
&lt;a href=&quot;https://feedly.com/i/subscription/feed%2Fhttps%3A%2F%2Fbirtles.blog%2Ffeed.xml&quot;&gt;Feedly&lt;/a&gt;
only ever fetches a post once so it doesn’t
matter that I fixed my old posts—Feedly users will see the original broken
version for eternity 😅&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2023/10/02/rss-the-hard-way/#comments</comments><category>Astro</category></item><item><title>Sponsoring Open Source as a Japanese Company</title><link>https://birtles.blog/2023/09/09/sponsoring-open-source-as-a-japanese-company/</link><guid isPermaLink="true">https://birtles.blog/2023/09/09/sponsoring-open-source-as-a-japanese-company/</guid><description>Six years since my last post, I thought I’d get back into blogging.
I plan to write about Web apps and things but I’d also like to talk a bit
about running a company in Japan since there’s not a lot of good information
on that in English.

Today, I want to share some notes about sponsoring Open Source through GitHub
as a Japanese company.
</description><pubDate>Sat, 09 Sep 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Six years since my last post, I thought I’d get back into blogging.
I plan to write about Web apps and things but I’d also like to talk a bit
about running a company in Japan since there’s not a lot of good information
on that in English.&lt;/p&gt;
&lt;p&gt;Today, I want to share some notes about sponsoring Open Source through GitHub
as a Japanese company.&lt;/p&gt;

&lt;p&gt;A few years ago I started using &lt;a href=&quot;https://reactcosmos.org/&quot;&gt;React cosmos&lt;/a&gt; for
iterating on UI components.
I was previously using &lt;a href=&quot;https://storybook.js.org/&quot;&gt;Storybook&lt;/a&gt; but it required
babel, a separate webpack file, and a lot of configuration and maintenance.
React Cosmos just worked and does everything I need.&lt;/p&gt;
&lt;p&gt;Since my company is benefitting from &lt;a href=&quot;https://twitter.com/skidding&quot;&gt;Ovidiu’s&lt;/a&gt;
hard work, when I saw he was developing the next major version I figured it was
only right to &lt;a href=&quot;https://github.com/sponsors/skidding&quot;&gt;support him&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;But how does a Japanese business account for GitHub sponsorships?&lt;/p&gt;
&lt;p&gt;It turns out &lt;a href=&quot;https://kazamori.jp/blogs/2021/01/09/github-sponsors/&quot;&gt;others have already asked this
question&lt;/a&gt; and the options
generally given are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Entertainment expenses (交際費)&lt;/li&gt;
&lt;li&gt;Donation (寄付金)&lt;/li&gt;
&lt;li&gt;Advertising/publicity (広告宣伝費)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So which one should you use?&lt;/p&gt;
&lt;h2&gt;Entertainment expenses&lt;/h2&gt;
&lt;p&gt;The idea with entertainment expenses is that if sponsoring a client’s event,
for example, helps you to maintain a good relationship with them,
you could call that an entertainment expense.
(“Entertainment” here being “entertaining” clients to win their favour,
not going to the movies, or watching ice blocks melt in the kitchen sink.)&lt;/p&gt;
&lt;p&gt;That seems like a stretch in my case.
Ovidiu is a swell bloke, but he’s not a client.&lt;/p&gt;
&lt;h2&gt;Donation&lt;/h2&gt;
&lt;p&gt;A donation would seem like the obvious choice but it’s tricky.&lt;/p&gt;
&lt;p&gt;Firstly, the upper limit on tax-deductible donations is pitifully low.
The formula is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;（資本金の額および資本準備金の額の合計額または出資金の額） ×当期の月数を12で割った数×1,000分の2.5＋所得の金額×100分の2.5〕×4分の1＝〔損金算入限度額〕&lt;/p&gt;
&lt;p&gt;Source: &lt;a href=&quot;https://www.nta.go.jp/taxes/shiraberu/taxanswer/hojin/5281.htm&quot;&gt;https://www.nta.go.jp/taxes/shiraberu/taxanswer/hojin/5281.htm&lt;/a&gt;&lt;br&gt;
Better still, see the
&lt;a href=&quot;https://www.nta.go.jp/taxes/tetsuzuki/shinsei/annai/hojin/shinkoku/itiran2023/pdf/14(02).pdf&quot;&gt;別表十四（二）&lt;/a&gt; PDF&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;i.e. &lt;math&gt;
&lt;mi&gt;Deductible limit&lt;/mi&gt;
&lt;mo&gt;=&lt;/mo&gt;
&lt;mo&gt;(&lt;/mo&gt;
&lt;mi&gt;Capital&lt;/mi&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mi&gt;No. of months this financial term&lt;/mi&gt;
&lt;mn&gt;12&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;2.5&lt;/mn&gt;
&lt;mn&gt;1,000&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;+&lt;/mo&gt;
&lt;mi&gt;Taxable income&lt;/mi&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;2.5&lt;/mn&gt;
&lt;mn&gt;100&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;)&lt;/mo&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;1&lt;/mn&gt;
&lt;mn&gt;4&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;/math&gt;&lt;/p&gt;
&lt;p&gt;So let’s plug some numbers in. Let’s assume a small company with 10M JPY in
capital making a solid 10M JPY each year.
The most you can write off as tax-deductible donations is:&lt;/p&gt;
&lt;math&gt;
&lt;mo&gt;(&lt;/mo&gt;
&lt;mn&gt;10,000,000&lt;/mn&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;12&lt;/mn&gt;
&lt;mn&gt;12&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;2.5&lt;/mn&gt;
&lt;mn&gt;1,000&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;+&lt;/mo&gt;
&lt;mn&gt;10,000,000&lt;/mn&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;2.5&lt;/mn&gt;
&lt;mn&gt;100&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;)&lt;/mo&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;1&lt;/mn&gt;
&lt;mn&gt;4&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;=&lt;/mo&gt;
&lt;mo&gt;(&lt;/mo&gt;
&lt;mn&gt;25,000&lt;/mn&gt;
&lt;mo&gt;+&lt;/mo&gt;
&lt;mn&gt;250,000&lt;/mn&gt;
&lt;mo&gt;)&lt;/mo&gt;
&lt;mo&gt;×&lt;/mo&gt;
&lt;mfrac&gt;
&lt;mn&gt;1&lt;/mn&gt;
&lt;mn&gt;4&lt;/mn&gt;
&lt;/mfrac&gt;
&lt;mo&gt;=&lt;/mo&gt;
&lt;mn&gt;68,750&lt;/mn&gt;
&lt;/math&gt;
&lt;p&gt;Putting that in &lt;em&gt;very&lt;/em&gt; rough dollar terms, a company making a profit of 100k USD
could only deduct less than 7k in donations.&lt;/p&gt;
&lt;p&gt;There are a couple of brackets, e.g. one for recognized charities
(特定公益増進法人) and one for general donations (一般の寄附金) but even putting
those together, the deductible limit is very low compared to other countries and
really doesn’t encourage Japanese companies to be generous.&lt;/p&gt;
&lt;p&gt;Secondly, the tax office indicates that gifts that are directly related to the
execution of your business should &lt;em&gt;not&lt;/em&gt; be donations:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;金銭その他の資産または経済的利益の贈与または無償の供与であっても、
&lt;strong&gt;法人の事業遂行と直接関係のある&lt;/strong&gt;と認められる広告宣伝および見本品の費用
その他これらに類する費用並びに交際費、接待費および福利厚生費とされるものは、
&lt;strong&gt;寄附金から除かれます&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nta.go.jp/taxes/shiraberu/taxanswer/hojin/5281.htm&quot;&gt;https://www.nta.go.jp/taxes/shiraberu/taxanswer/hojin/5281.htm&lt;/a&gt; (Emphasis
added)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Advertising&lt;/h2&gt;
&lt;p&gt;That leaves us with advertising.
When you sponsor someone through GitHub sponsors your organisation logo shows up
on the project homepage and you get a little “Sponsor” badge on your
organisation’s page too.
With any luck, the project will spotlight their sponsors in different ways as
well.
All of this could be reasonably expected to highlight your company, bringing it
fame and great prestige.&lt;/p&gt;
&lt;p&gt;In any case, my tax accountant agreed advertising was justified in this case
which probably counts for more than anything else I’ve written in this post.&lt;/p&gt;
&lt;h3&gt;”Don’t let your left hand know what your right hand is doing”?&lt;/h3&gt;
&lt;p&gt;Some people might feel a bit awkward about advertising their contributions,
however.
In perhaps the most famous speech ever given, Jesus warned against “practicing
your righteousness before other people to be seen by them” (&lt;a href=&quot;https://www.biblegateway.com/passage/?search=Matthew+6&amp;#x26;version=ESV&quot;&gt;Matt
6:1-18&lt;/a&gt;)
particularly when it comes to giving to charity, praying, and fasting.&lt;/p&gt;
&lt;p&gt;I think we often feel a bit skeptical when we see companies promoting
their charitable donations and wonder, “Is that a genuine donation or just a
marketing ploy? Can companies be genuine anyway?”&lt;/p&gt;
&lt;p&gt;In any case, surely contributing to Open Source is not a charitable donation or
act of righteousness but just a cost of doing business.
Provided the project itself (or GitHub) is doing the advertising it needn’t
be awkward self-promotion either.&lt;/p&gt;
&lt;h2&gt;Are there other options?&lt;/h2&gt;
&lt;p&gt;Some GitHub sponsorship plans promise benefits like dedicated support and
development advice.
I wonder if it would be possible to account for these as commission fees
(支払手数料), outsourcing (業務委託 or 外注費), or compensation (支払報酬)?
Who knows?
A tax accountant would but I’ve troubled my tax accountant enough recently with
my woeful bookkeeping to bother him again.&lt;/p&gt;
&lt;h2&gt;Implications for Open Source developers&lt;/h2&gt;
&lt;p&gt;I have no idea if any of this applies outside Japan, but in the very unlikely
case that you are working on Open Source and would like Japanese companies to
support you, the obvious implication is &lt;strong&gt;promote your sponsors&lt;/strong&gt;.
It makes it easier for them to justify the cost and probably lifts the image of
your project at the same time.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2023/09/09/sponsoring-open-source-as-a-japanese-company/#comments</comments><category>Business in Japan</category></item><item><title>Web animation in 2017</title><link>https://birtles.blog/2017/01/10/web-animation-in-2017/</link><guid isPermaLink="true">https://birtles.blog/2017/01/10/web-animation-in-2017/</guid><description>Happy new year! As promised I thought I’d share a few of the Web animation
things I’m looking forward to in 2017. I’m terrible at predicting the future (I
used to be a believer in BeOS and VRML) so this is mostly based on what is
already in motion.
</description><pubDate>Tue, 10 Jan 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Happy new year! As promised I thought I’d share a few of the Web animation
things I’m looking forward to in 2017. I’m terrible at predicting the future (I
used to be a believer in BeOS and VRML) so this is mostly based on what is
already in motion.&lt;/p&gt;

&lt;p&gt;Specs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/css-transitions/&quot;&gt;CSS transitions&lt;/a&gt; – this should
move to CR status soon.
Part of that involves splitting off a separate &lt;strong&gt;Timing Functions&lt;/strong&gt; spec.
That separate spec would give us:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Level 1:&lt;/em&gt; An additional &lt;code&gt;frames()&lt;/code&gt; timing function to do what step-end and
step-start should have done in the first place.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Level 2:&lt;/em&gt; Low-level syntax for export of complex timing functions
(multi-segment béziers?), spring timing functions, script-defined timing
functions, and perhaps even timing functions that affect the duration of
animations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.csswg.org/css-animations/&quot;&gt;CSS animations&lt;/a&gt; – this too should
move to CR soon. All that is
really missing is some clarification about the
liveness of values and some text about how &lt;code&gt;@keyframes&lt;/code&gt; rules cascade. Then we
can start work on new things in level 2 like
&lt;a href=&quot;https://drafts.csswg.org/css-animations-2/#animation-composition&quot;&gt;animation-composition&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://w3c.github.io/web-animations/&quot;&gt;Web animations&lt;/a&gt; – this too is
approaching CR and I hope we
can ship (most of) the remainder of the API in the first half of this year in
Firefox and Chrome. For that we still need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Add a &lt;code&gt;FillAnimation&lt;/code&gt; concept to allow browsers to compact finished but
filling animations so they don’t keep consuming memory. This is a bit hard,
but seems do-able.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/w3c/web-animations/issues/168&quot;&gt;Simplify the timing
interfaces&lt;/a&gt; to use fewer
live objects and make the interface consistent with keyframe interfaces.
I hope this will simplify the implementation for Edge and Safari too.&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;compositeBefore&lt;/code&gt; and &lt;code&gt;compositeAfter&lt;/code&gt; methods to control how
animations combine and overlap.&lt;/li&gt;
&lt;li&gt;Replace &lt;code&gt;SharedKeyframeList&lt;/code&gt; with
&lt;a href=&quot;https://drafts.css-houdini.org/css-typed-om/#stylepropertymap&quot;&gt;StylePropertyMaps&lt;/a&gt;
from Houdini.&lt;/li&gt;
&lt;li&gt;Integrate &lt;a href=&quot;https://github.com/w3c/web-animations/issues/148&quot;&gt;a few
tweaks&lt;/a&gt; to making
specifying keyframes more flexible.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’m looking forward to shipping additive animation soon since it helps with
a lot of use cases, but it really needs &lt;code&gt;FillAnimation&lt;/code&gt; first.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;getAnimations&lt;/code&gt; is also exciting—being able to inspect and manipulate CSS
animations and transitions from the same API—but probably won’t ship until
the second half of the year when we have the mapping between CSS and Web
Animations clearly specified.&lt;/p&gt;
&lt;p&gt;Being able to ship the
&lt;a href=&quot;https://w3c.github.io/web-animations/#dom-animation-finished&quot;&gt;&lt;code&gt;finished&lt;/code&gt;&lt;/a&gt;
and &lt;a href=&quot;https://w3c.github.io/web-animations/#dom-animation-ready&quot;&gt;&lt;code&gt;ready&lt;/code&gt;&lt;/a&gt;
promise would be great but was blocked on cancelable promises being realized
and now it’s not clear what will happen there.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://wicg.github.io/scroll-animations/&quot;&gt;Scroll-driven animations&lt;/a&gt; – This
is going to take quite a bit of work to get right, but hopefully within this
year we can start shipping parts of it so you can create hidey bars and
parallax effects that run smoothly on the compositor.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/WICG/animation-worklet&quot;&gt;AnimationWorklet&lt;/a&gt; – This is also
going to take time to make sure it plays well with the other animation pieces
in the platform but fortunately the Chrome folks pushing it have been very
responsive to feedback and admirable in their willingness to rethink ideas.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At Mozilla, apart from editing and implementing the above specs, some of the
bigger animation items I anticipate this year include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Making our current animation features work with &lt;a href=&quot;https://wiki.mozilla.org/Quantum#Quantum_CSS&quot;&gt;Quantum
CSS&lt;/a&gt;,
i.e. Servo’s style engine. This involves a lot of tricky plumbing but it
means Firefox gets faster and Servo gets more spec compliant.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://drafts.fxtf.org/motion-1/&quot;&gt;CSS offset&lt;/a&gt; (aka CSS motion). We’ve been
putting this off for a while as the spec stabilizes but I hope this year we
will actually do it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Promoting various SVG attributes to properties. Tackling this and the
previous item would significantly narrow the gap between CSS and SVG’s (SMIL)
animation features and let us simplify the SMIL code a lot.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Animation of &lt;a href=&quot;https://drafts.css-houdini.org/css-properties-values-api-1/#animation-behavior-of-custom-properties&quot;&gt;CSS custom
properties&lt;/a&gt;.
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1273706&quot;&gt;There are patches
written&lt;/a&gt; but they need
some work before they land.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;DevTools. We have plenty of ideas here but most of all we want to make our
animation DevTools the place to go not just to debug all the above features,
but also to author for them!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If any of those items sound interesting to you, please &lt;a href=&quot;https://wiki.mozilla.org/Contribute&quot;&gt;get
involved&lt;/a&gt;!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2017/01/10/web-animation-in-2017/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>MozAnime in 2016</title><link>https://birtles.blog/2016/12/27/mozanime-in-2016/</link><guid isPermaLink="true">https://birtles.blog/2016/12/27/mozanime-in-2016/</guid><description>MozAnime is the informal name we use to cover all the work on animation-related
features at Mozilla. We’re based in Tokyo, Tochigi, Taipei, Toronto, and…
somewhere in France that probably, hopefully, starts with a ‘t’ as well.

I can’t wait to tell you all the things I’m looking forward to next year, but in
this post I want to share some of the highlights from the MozAnime crew in 2016.
</description><pubDate>Tue, 27 Dec 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;MozAnime is the informal name we use to cover all the work on animation-related
features at Mozilla. We’re based in Tokyo, Tochigi, Taipei, Toronto, and…
somewhere in France that probably, hopefully, starts with a ‘t’ as well.&lt;/p&gt;
&lt;p&gt;I can’t wait to tell you all the things I’m looking forward to next year, but in
this post I want to share some of the highlights from the MozAnime crew in 2016.&lt;/p&gt;

&lt;h2&gt;Shipped &lt;code&gt;Element.animate&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Five years since I first proposed Web Animations we finally shipped some of it!
We worked together with the Chrome team to make sure we have an interoperable
feature set (something
&lt;a href=&quot;https://github.com/w3c/web-platform-tests/&quot;&gt;web-platform-tests&lt;/a&gt; helped with
a lot!) and thanks to their work on
a &lt;a href=&quot;https://github.com/web-animations/web-animations-js&quot;&gt;polyfill&lt;/a&gt;, authors can
now write cross-browser animations that in many cases will run in a separate
thread. See the &lt;a href=&quot;https://hacks.mozilla.org/2016/08/animating-like-you-just-dont-care-with-element-animate/&quot;&gt;hacks
article&lt;/a&gt;
for more details.&lt;/p&gt;

&lt;video poster=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/jank-example-poster.png&quot;&gt;
  &lt;source src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/jank-example.webm&quot; type=&quot;video/webm&quot;&gt;
  &lt;source src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/jank-example.mp4&quot; type=&quot;video/mp4&quot;&gt;
&lt;/video&gt;

&lt;p&gt;Performance of regular JavaScript animation vs &lt;code&gt;Element.animate()&lt;/code&gt;&lt;/p&gt;


&lt;h2&gt;Finished&lt;sup&gt;*&lt;/sup&gt; Web Animations&lt;/h2&gt;
&lt;p&gt;Of course, &lt;code&gt;Element.animate&lt;/code&gt; is only the tip of the iceberg. Web Animations has
a lot more to offer such as being able to modify and query animations—even
CSS-defined animations—on the fly and make independent animations that morph
together. We finally landed the last pieces of that API last weekend.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/areweanimatedyet.gif&quot; alt=&quot;Progress of Web Animations implementation status throughout 2016&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;sup&gt;*&lt;/sup&gt;Technically, however, it’s not actually finished. We haven’t done
&lt;code&gt;SharedKeyframeList&lt;/code&gt; because that part of the spec is likely to change. In fact,
there are a few parts of the spec that will change so we’ll need to do a bit
more work on those before we’re ready to ship. More on that next time.
Nevertheless, it’s a significant milestone and as far as I can tell we’re the
first browser to get there although Chrome is coming along too.&lt;/p&gt;
&lt;h2&gt;Improved Animation DevTools&lt;/h2&gt;
&lt;p&gt;We launched our &lt;a href=&quot;https://hacks.mozilla.org/2015/11/developer-edition-44-creative-tools-and-more/&quot;&gt;first animation DevTools in
2015&lt;/a&gt;
but this year we deepened the collaboration between platform work and DevTools
producing some new features like:&lt;/p&gt;
&lt;h3&gt;Animations on pseudo-elements&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/pseudo-elem.png&quot; alt=&quot;Animation inspector showing a throb animaion running on the pseudo element&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Platform performance information&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/perf-warning.png&quot; alt=&quot;DevTools showing an explanation for why animation of the transform property could not be optimized.&quot;&gt;&lt;/p&gt;
&lt;p&gt;This was initially implemented by an intern who did a great job. This is
incredibly useful—if you’re debugging animation performance please give it
a try! You can find &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Tools/Page_Inspector/How_to/Work_with_animations#Further_information_about_animation_compositing&quot;&gt;more details on
MDN&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Richer timing display&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/timing-display.png&quot; alt=&quot;DevTools showing different easing effects applied to two animations&quot;&gt;&lt;/p&gt;
&lt;p&gt;This is just the start of making the animation inspector much more useful. See
&lt;a href=&quot;https://hacks.mozilla.org/2016/11/visualize-animations-easing-in-devtools/&quot;&gt;Patrick’s hacks
article&lt;/a&gt;
for all the details of this first step. Because of the close integration of
platform and DevTools work, these tools also handle the obscure edge cases that
might not be apparent to a casual user of animation features (like large
negative end delays that overlap start delays). There is a lot more work to do
here but the next piece is already up for review and there is more on the way.&lt;/p&gt;
&lt;p&gt;(And just in case you’re wondering what an excessively large end delay looks
like, it’s something like this.)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/12/27/mozanime-in-2016/massive-end-delay.png&quot; alt=&quot;DevTools when viewing an animation with a negative end delay larger than its active duration&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Proposed scroll-linked animations and started implementation&lt;/h2&gt;
&lt;p&gt;At W3C TPAC this year we proposed a &lt;a href=&quot;https://wicg.github.io/scroll-animations/&quot;&gt;spec for scroll-linked
animations&lt;/a&gt; based on a previous
proposal by Apple. There was strong support for pursuing this and Google have
been actively involved too, giving great feedback. We have &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1321428&quot;&gt;an initial
implementation&lt;/a&gt; due to
land any day now but it will be preffed-off initially since there is still a lot
of spec discussion that needs to happen.&lt;/p&gt;
&lt;h2&gt;Specced and implemented new transition events&lt;/h2&gt;
&lt;p&gt;Our experience with Firefox OS helped us realize how difficult it can be to work
with transitions. Sometimes they don’t fire (e.g. you set a property to its
existing value), and sometimes they get cancelled (e.g. you “re-rendered” a part
of the DOM and blew away the elements that were transitioning), so if you’re
waiting for transitionend you could be waiting a long time.&lt;/p&gt;
&lt;p&gt;So we specced
&lt;strong&gt;&lt;a href=&quot;https://drafts.csswg.org/css-transitions/#transitionrun&quot;&gt;transitionrun&lt;/a&gt;&lt;/strong&gt;
(for when the transition is created),
&lt;strong&gt;&lt;a href=&quot;https://drafts.csswg.org/css-transitions/#transitionstart&quot;&gt;transitionstart&lt;/a&gt;&lt;/strong&gt;
(for when the transition finishes its delay—mostly since Edge already had this),
and
&lt;strong&gt;&lt;a href=&quot;https://drafts.csswg.org/css-transitions/#transitioncancel&quot;&gt;transitioncancel&lt;/a&gt;&lt;/strong&gt;
(for when the transition is dropped without reaching the end). They’re
implemented in the latest Nightly edition of Firefox (53) and we’ll implement
a similar
&lt;strong&gt;&lt;a href=&quot;https://drafts.csswg.org/css-animations/#eventdef-animationevent-animationcancel&quot;&gt;animationcancel&lt;/a&gt;&lt;/strong&gt;
event for CSS animations
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1302648&quot;&gt;soon&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What’s coming up in 2017?&lt;/h2&gt;
&lt;p&gt;That’s enough for one post but I’ll follow up early in the new year with what we
hope to do in Mozilla-land in 2017 as well as some of the other
animation-related developments I’m looking forward to in the wider Web
landscape.&lt;/p&gt;
&lt;p&gt;Thank you to the many people who contributed, not only to Mozilla but also to
many fantastic people at Google and Microsoft in particular whom I had the
pleasure of working with this year. Happy new year!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2016/12/27/mozanime-in-2016/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Gecko insiders</title><link>https://birtles.blog/2016/04/01/gecko-insiders/</link><guid isPermaLink="true">https://birtles.blog/2016/04/01/gecko-insiders/</guid><description>At Mozilla Japan, we’ve been doing a series of monthly events called “Gecko
inside” where we discuss details
of hacking on Gecko in the hope of helping each other learn and helping new
contributors to get started.

Last weekend we held a special “write a patch” day where we gathered a group of
long-time contributors to mentor first-time contributors through the process of
setting up a build environment, writing a patch, and getting it reviewed and
landed.
</description><pubDate>Fri, 01 Apr 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;At Mozilla Japan, we’ve been doing a series of monthly events called &lt;a href=&quot;https://twitter.com/search?q=%23geckoinside&quot;&gt;“Gecko
inside”&lt;/a&gt; where we discuss details
of hacking on Gecko in the hope of helping each other learn and helping new
contributors to get started.&lt;/p&gt;
&lt;p&gt;Last weekend we held a special “write a patch” day where we gathered a group of
long-time contributors to mentor first-time contributors through the process of
setting up a build environment, writing a patch, and getting it reviewed and
landed.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/04/01/gecko-insiders/gecko-inside.jpg&quot; alt=&quot;Gecko inside&quot;&gt;&lt;/p&gt;
&lt;p&gt;We fixed &lt;a href=&quot;https://bugzilla.mozilla.org/buglist.cgi?quicksearch=1244640%2C%201259898%2C%201244642%2C%201257067%2C%201259675%2C%201259659%2C%201259673%2C%201259676%2C%201259655%2C%201258820%2C%201259883&amp;#x26;list_id=12942272&quot;&gt;nearly a dozen
bugs&lt;/a&gt;
on the day and if you were hanging around on &lt;code&gt;#developers&lt;/code&gt; about that time, you
might have been surprised at the stream of Japanese names ticking by.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/04/01/gecko-insiders/lots-of-japanese-commits.png&quot; alt=&quot;Lots of Japanese commits&quot;&gt;&lt;/p&gt;

&lt;p&gt;It was a fun event with veterans and first-time contributors alike asking if we
could do it again.&lt;/p&gt;
&lt;h2&gt;Gecko internals&lt;/h2&gt;
&lt;p&gt;In keeping with the topic of new contributors, we were recently very pleased to
have Ryo Motozawa join us for an internship during his university’s winter
break. Ryo came to us with more curiosity than experience but quickly found his
way around &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1226047&quot;&gt;implementing&lt;/a&gt;
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1244586&quot;&gt;WebIDL&lt;/a&gt;
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1244641&quot;&gt;interfaces&lt;/a&gt;, &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1244635&quot;&gt;animation
timing features&lt;/a&gt;, and
a number of &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1253494&quot;&gt;DevTools
features&lt;/a&gt; including
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1254408&quot;&gt;exposing detailed animation performance
information&lt;/a&gt; (due to land
any day now!) using an &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1196114&quot;&gt;interface Hiro recently
built&lt;/a&gt;—all in just
2 months! Nice work Ryo!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/04/01/gecko-insiders/ryo.png&quot; alt=&quot;Screenshot of detailed animation performance view where a tooltip indicates that a transform animation is not able to be run async&quot;&gt;&lt;/p&gt;

&lt;p&gt;(And, before you mention it, there’s already &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1255683&quot;&gt;a bug to fix the text in that
tooltip&lt;/a&gt;!)&lt;/p&gt;
&lt;h2&gt;Gecko geeks&lt;/h2&gt;
&lt;p&gt;Some of the other notable things we’ve been plugging away at here in Japan include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Clearing out the
&lt;a href=&quot;https://bugzilla.mozilla.org/showdependencygraph.cgi?id=1245000&quot;&gt;blockers&lt;/a&gt;
from &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1245000&quot;&gt;shipping
Element.animate()&lt;/a&gt; which
should be ready for Firefox 48.&lt;/li&gt;
&lt;li&gt;Steadily &lt;a href=&quot;https://birtles.github.io/areweanimatedyet/&quot;&gt;filling in the rest of the Web Animations
API&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Fixing a long-standing issue with keyboard shortcut keys not working when
plugins are active. Masayuki has done some heroic refactoring here and it
should already be working on Nightly builds for Mac with just &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1257759&quot;&gt;a bit more work
to go for Windows&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Also, while far from a Japan-only effort, another animation-related feature I should mention is that thanks to platform work from Boris Chiou and Daisuke Akatsuka, and DevTools work from Patrick Brosset, the animation inspector now finally works with animations on pseudo-elements!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/04/01/gecko-insiders/pseudo.png&quot; alt=&quot;Screenshot of the animation inspector showing animations on pseudo-elements&quot;&gt;&lt;/p&gt;

&lt;p&gt;They’re just a few of the things we’re excited about at the moment. Oh, and this
view!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2016/04/01/gecko-insiders/sakura.jpg&quot; alt=&quot;Cherry blossoms line a road near Tokyo Midtown&quot;&gt;&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2016/04/01/gecko-insiders/#comments</comments><category>Archive</category><category>Mozilla</category></item><item><title>Mozilla Japan engineering is quite hot right now</title><link>https://birtles.blog/2015/08/06/mozilla-japan-engineering-is-quite-hot-right-now/</link><guid isPermaLink="true">https://birtles.blog/2015/08/06/mozilla-japan-engineering-is-quite-hot-right-now/</guid><description>Fortunately Taipei’s shaved ice extravaganza Ice Monster has popped-up just
around the
corner
from our office in Tokyo!

Now that I’ve sufficiently buried the lede, I’d like to introduce you to what
our platform engineers have been up to in the land of the rising (and scorching)
sun.

Since April we’ve been trying to focus our efforts around two themes: Input and
Animation although we also work on other items like fonts and supporting partner
projects.
</description><pubDate>Thu, 06 Aug 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Fortunately Taipei’s shaved ice extravaganza Ice Monster has &lt;a href=&quot;https://entabe.jp/news/gourmet/8765/ice-monster-pop-up-shop-opens-in-mercedes-benz-connection&quot;&gt;popped-up just
around the
corner&lt;/a&gt;
from our office in Tokyo!&lt;/p&gt;
&lt;p&gt;Now that I’ve sufficiently buried the lede, I’d like to introduce you to what
our platform engineers have been up to in the land of the rising (and scorching)
sun.&lt;/p&gt;
&lt;p&gt;Since April we’ve been trying to focus our efforts around two themes: Input and
Animation although we also work on other items like fonts and supporting partner
projects.
Some of the things we’re tackling this quarter include:&lt;/p&gt;
&lt;p&gt;Input:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prototype a new Japanese IME for Firefox OS&lt;/li&gt;
&lt;li&gt;Fix IME-related bugs blocking e10s&lt;/li&gt;
&lt;li&gt;Work on some &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1168271&quot;&gt;performance issues in the Firefox OS
keyboard&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Animation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Try to get our &lt;a href=&quot;https://birtles.github.io/areweanimatedyet/&quot;&gt;Web Animations
implementation&lt;/a&gt; in shape so we
can ship Element.animate by the end of the quarter&lt;/li&gt;
&lt;li&gt;Work on PerformanceObserver so we can implement the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1158032&quot;&gt;Frame Timing
API&lt;/a&gt; on top of it&lt;/li&gt;
&lt;li&gt;Work on a &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1105509&quot;&gt;few&lt;/a&gt;
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1166500&quot;&gt;animation&lt;/a&gt;
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=984961&quot;&gt;performance&lt;/a&gt; issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Other:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start to merge the &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1180124&quot;&gt;Firefox OS TV
simulator&lt;/a&gt; into
mozilla-central&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Gecko guts&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2015/08/06/mozilla-japan-engineering-is-quite-hot-right-now/gecko-inside.jpg&quot; alt=&quot;Makoto takes the floor to teach us the ins and outs of e10s in the first ever Gecko inside event&quot;&gt;&lt;/p&gt;
&lt;p&gt;Last night we held our first &lt;a href=&quot;https://twitter.com/search?q=%23geckoinside&quot;&gt;“Gecko
inside”&lt;/a&gt; meetup. The idea is for
engineers to teach each other about different parts of our code and provide some
useful information to people who are interested in contributing. This time,
Makoto gave us a great overview of e10s in Firefox.&lt;/p&gt;
&lt;p&gt;We plan to do it again on September 8 including a special guest appearance from
Gary Kwong presenting on fuzzing in Firefox!&lt;/p&gt;
&lt;p&gt;If you’re in Tokyo please drop by! Better still, if you’re hacking on any of the
same things, why not pay us an extended visit? In addition to Taiwanese shaved
ice, we’ll gladly introduce you to some tasty sushi or barbecued beef tongue.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2015/08/06/mozilla-japan-engineering-is-quite-hot-right-now/#comments</comments><category>Archive</category><category>Mozilla</category></item><item><title>What do we do with SMIL?</title><link>https://birtles.blog/2015/05/01/what-do-we-do-with-smil/</link><guid isPermaLink="true">https://birtles.blog/2015/05/01/what-do-we-do-with-smil/</guid><description>Earlier this week, Blink announced their intention to deprecate
SMIL.
I thought they were going to replace their native implementation with
a Javascript one so this was a surprise to me.

Prompted by this, the SVG WG decided it would be better to split the animation
features in SVG2 out into a separate
spec. (This was something
I started doing a while ago, calling it Animation
Elements,
but I haven’t had time to follow up on it recently.)
</description><pubDate>Fri, 01 May 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Earlier this week, Blink announced their &lt;a href=&quot;https://groups.google.com/a/chromium.org/g/blink-dev/c/5o0yiO440LM&quot;&gt;intention to deprecate
SMIL&lt;/a&gt;.
I thought they were going to replace their native implementation with
a Javascript one so this was a surprise to me.&lt;/p&gt;
&lt;p&gt;Prompted by this, the SVG WG decided it would be better to &lt;a href=&quot;https://www.w3.org/2015/04/30-svg-minutes.html#item02&quot;&gt;split the animation
features in SVG2 out into a separate
spec&lt;/a&gt;. (This was something
I started doing a while ago, calling it &lt;a href=&quot;https://svgwg.org/specs/animation-elements/animation-elements.html&quot;&gt;Animation
Elements&lt;/a&gt;,
but I haven’t had time to follow up on it recently.)&lt;/p&gt;

&lt;p&gt;I’ve spent quite a lot of time working on SMIL in Gecko (Firefox) so I’m
probably more attached to it than most.
I also started work on
&lt;a href=&quot;https://drafts.csswg.org/web-animations-1/&quot;&gt;Web Animations&lt;/a&gt;
specifically to address Microsoft’s concern that we needed a unified model for
animations on the Web and I was under the impression they were finally open to
the idea of a Javascript implementation of SMIL in Edge.&lt;/p&gt;
&lt;p&gt;I’m not sure what will happen next, but it’s interesting to think about what we
would lose without SMIL and what we could do to fix that. Back in 2011 I wrote
up a &lt;a href=&quot;https://www.w3.org/Graphics/SVG/WG/wiki/F2F/Seattle_2011/Agenda/Animations/Harmonisation&quot;&gt;gap analysis of features missing in CSS that exist in SVG
animation&lt;/a&gt;.
One example, is that even with &lt;a href=&quot;https://drafts.csswg.org/css-animations/&quot;&gt;CSS
Animations&lt;/a&gt;, &lt;a href=&quot;https://drafts.csswg.org/css-transitions/&quot;&gt;CSS
Transitions&lt;/a&gt;, &lt;a href=&quot;https://drafts.csswg.org/web-animations-1/&quot;&gt;Web
Animations&lt;/a&gt; and the &lt;a href=&quot;https://drafts.fxtf.org/motion-1/&quot;&gt;Motion Path
module&lt;/a&gt;, we still couldn’t create a font using
&lt;a href=&quot;https://hacks.mozilla.org/2014/10/svg-colors-in-opentype-fonts/&quot;&gt;SVG-in-OpenType&lt;/a&gt;
where the outlines of the glyphs wiggle.
That’s because even though Web Animations lets you animate attributes (and not
just CSS properties), that feature is only available via the script API and you
can’t run script in some contexts like font glyph documents.&lt;/p&gt;
&lt;p&gt;So what would we need? I think some of the following might be interesting specs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Path animation module&lt;/strong&gt; – We need some means of animating path data such as
the ‘d’ attribute on an SVG element. With SMIL this is actually really
hard—you need to have exactly the same number and type of segments in order to
interpolate between two paths. Tools could help with this but there aren’t any
yet.&lt;/p&gt;
&lt;p&gt;It would be neat to be able to interpolate between, say, a &lt;code&gt;&amp;#x3C;circle&gt;&lt;/code&gt; and
a &lt;code&gt;&amp;#x3C;rect&gt;&lt;/code&gt;. Once you allow different numbers of segments you probably need
a means of annotating anchor points so you can describe how the different
paths are supposed to line up.&lt;/p&gt;
&lt;p&gt;(If, while we’re at it, we could define a way of warping paths that would be
great for doing cartoons!)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Animation group module&lt;/strong&gt; – SMIL lets you sequence and group animations so
they play perfectly together. That’s not easy with CSS at the moment. &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/&quot;&gt;Web
Animations level 2&lt;/a&gt; actually
defines &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#grouping-and-synchronization&quot;&gt;grouping and synchronization
primitives&lt;/a&gt;
for this but there’s no proposed CSS syntax for it.&lt;/p&gt;
&lt;p&gt;I think it would be useful if CSS Animations Level 2 added a single level of
grouping, something like an &lt;code&gt;animation-group&lt;/code&gt; property where all animations
with a matching group name were kept in lock-step (with
&lt;code&gt;animation-group-reset&lt;/code&gt; to create new groups of the same name). A subsequent
level could extend that to the more advanced hierarchies of groups described
in Web Animations level 2.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Property addition&lt;/strong&gt; – SMIL lets you have independent animations target the
same element and add together. For example, you can have a ‘spin’ animation
and a ‘swell’ animation defined completely independently and then applied to
the same element, and they combine together without conflict. Allowing CSS
properties to add together sounds like a big change but you can actually
narrow down the problem space in three ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Most commonly you’re adding together lists: e.g. transform lists or filter
lists. A solution that only lets you add lists together would probably
solve a lot of use cases.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Amongst lists, transform lists are the most common. For this the FXTF
already resolved to &lt;a href=&quot;https://www.w3.org/2015/02/10-fx-minutes.html#item10&quot;&gt;add translate, rotate and scale properties in CSS
transforms level 2&lt;/a&gt; so
we should be able to address some of those use cases in the near future.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;While it would be nice to add properties together in static contexts like
below, if it simplifies the solution, we could just limit the issue to
animations at first.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;.blur {  filter: blur(10px); }
.sepia { filter: sepia(50%); }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are other things that SMIL lets you do such as change the source URL of an
image in response to an arbitrary event like a click without writing any
programming code but I think the above cover some of the bigger gaps? What else
would we miss?&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2015/05/01/what-do-we-do-with-smil/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>After 10 years</title><link>https://birtles.blog/2014/10/31/after-10-years/</link><guid isPermaLink="true">https://birtles.blog/2014/10/31/after-10-years/</guid><description>Yesterday marks 10 days to the day since I posted my first patch to
Bugzilla.
It was a small patch to composite SVG images with their background (and not just
have a white background).

Since then I’ve contributed to Firefox as a volunteer, an intern, a contractor,
and, as of 3 years ago tomorrow, a Mozilla Japan employee.

It’s still a thrill and privilege to contribute to Firefox.
I’m deeply humbled by the giants I work alongside who support me like I was one
of their own.
In the evening when I’m tired from the day I still often find myself bursting
into a spontaneous prayer of thanks that I get to work on this stuff.

So here are 8 reflections from the last 10 years. It should have been 10 but
I ran out of steam.
</description><pubDate>Fri, 31 Oct 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yesterday marks 10 days to the day since I &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=134708#c13&quot;&gt;posted my first patch to
Bugzilla&lt;/a&gt;.
It was a small patch to composite SVG images with their background (and not just
have a white background).&lt;/p&gt;
&lt;p&gt;Since then I’ve contributed to Firefox as a volunteer, an intern, a contractor,
and, as of 3 years ago tomorrow, a Mozilla Japan employee.&lt;/p&gt;
&lt;p&gt;It’s still a thrill and privilege to contribute to Firefox.
I’m deeply humbled by the giants I work alongside who support me like I was one
of their own.
In the evening when I’m tired from the day I still often find myself bursting
into a spontaneous prayer of thanks that I get to work on this stuff.&lt;/p&gt;
&lt;p&gt;So here are 8 reflections from the last 10 years. It should have been 10 but
I ran out of steam.&lt;/p&gt;

&lt;h2&gt;Why I joined&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;I got involved with Firefox because, as a Web developer, I wanted to make the
Web platform better.
&lt;strong&gt;Firefox was in a position of influence and anyone could join in.&lt;/strong&gt;
It was open technically and culturally.
XPCOM took a little getting used to but everyone was very supportive.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;What I learned&lt;/h2&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Don’t worry about the boundaries.&lt;/strong&gt;
When I first started hacking on SVG code
I would be afraid to touch any source file outside &lt;code&gt;/content/svg/content/src&lt;/code&gt;
(now, thankfully, &lt;code&gt;dom/svg&lt;/code&gt;!). When I started on the SVG working group
I would think,
“we can’t possibly change that, that’s another working group’s spec!”
But when Cameron McCormack joined Mozilla I was really impressed how he
fearlessly fixed things all over the tree.
As I’ve become more familiar and confident with Firefox code and Web specs
I’ve stopped worrying about artificial boundaries like folders and working
groups and more concerned with fixing things properly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Blessed are the peacemakers.&lt;/strong&gt; It’s really easy to get into arguments on
the Internet that don’t help anyone. I once heard a colleague consider how
&lt;a href=&quot;https://robert.ocallahan.org/2008/12/new-game-old-rules_13.html&quot;&gt;Jesus’ teaching applies to the
Internet&lt;/a&gt;. He
suggested that sometimes when someone makes a fool of us on the Internet the
best thing is just to leave it and look like a fool. I find that hard to do
and don’t do it often, but I’m always glad when I do. Earlier this year
another colleague impressed me with her &lt;a href=&quot;https://subfictional.com/2014/03/24/on-brendan-eich-as-ceo-of-mozilla/&quot;&gt;very graceful
response&lt;/a&gt;
to Brendan’s appointment to CEO. I thought it was a great example of
peace-making.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Nothing is new.&lt;/strong&gt; I’ve found these words very sobering:&lt;/p&gt;
 
&lt;blockquote&gt;
&lt;p&gt;What has been will be again,&lt;br&gt;
what has been done will be done again;&lt;br&gt;
there is nothing new under the sun.&lt;br&gt;
Is there anything of which one can say,&lt;br&gt;
“Look! This is something new”?&lt;br&gt;
It was here already, long ago;&lt;br&gt;
it was here before our time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href=&quot;https://www.biblegateway.com/passage/?search=Ecclesiastes%201:9-10&quot;&gt;Ecclesiastes 1:9–10&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;It’s so easy to get caught up in some new technology—I got pretty caught up
defending SVG Animation (aka SMIL) for a while when I worked on it. Taking
a step back though, that new thing has almost invariably been done before in
some form, and it will certainly be superseded in my lifetime. In fact,
every bit of code I’ve ever written will almost certainly be either
rewritten or abandoned altogether within my lifetime.&lt;/p&gt;
&lt;p&gt;In light of that I try to fixate less on each new technology and more on the
process: what kind of person was I when I implemented that (now obsolete)
feature? What motivated me to work at it each day? That, I believe, is
eternal.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;How I hope Mozilla will shape up over the next 10 years&lt;/h2&gt;
&lt;ol start=&quot;5&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I hope we’ll be the most welcoming community on the Web.&lt;/strong&gt; I don’t mean
that we’ll give free hugs to new contributors, or that we’ll accept any patch
that manages to enter Bugzilla, or we’ll entertain any troublemaker who
happens upon
&lt;code&gt;#developers&lt;/code&gt;.
Rather, I hope that anyone who wants to help out finds overwhelming
encouragement and enthusiasm and without having to sign up to an ideological
agenda first.
Something like &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=1081013&quot;&gt;this
interaction&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I hope we’ll stay humble.&lt;/strong&gt; I’d love to see Mozilla be known as servants of
the Web but when things go well there’s always the danger we’ll become
arrogant, less welcoming of others’ ideas, and deaf to our critics. I hope we
can celebrate our victories while taking a modest view of ourselves. Who
knows, maybe our harshest critics will become some of our most valuable
contributors.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I hope we’ll talk less, show more.&lt;/strong&gt; By building amazing products through
the input of thousands of people around the world we can prove Open works, we
can prove you don’t need to choose between privacy and convenience.
My initial interest in Mozilla was because of its technical excellence and
welcoming community. The philosophy came later.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;I hope we’ll make less t-shirts.&lt;/strong&gt; Can we do, I don’t know, a shirt once in
a while? Socks even? Pretty much anything else!&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;</content:encoded><comments>https://birtles.blog/2014/10/31/after-10-years/#comments</comments><category>Archive</category><category>Mozilla</category></item><item><title>Animations on Fire @ Graphical Web 2014</title><link>https://birtles.blog/2014/09/08/animations-on-fire-graphical-web-2014/</link><guid isPermaLink="true">https://birtles.blog/2014/09/08/animations-on-fire-graphical-web-2014/</guid><description>Just recently I had the chance to talk about authoring animations of CSS/SVG for
better performance at The Graphical Web
2014\. I thought I’d put up the slides here
in case they’re useful to others.
</description><pubDate>Mon, 08 Sep 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just recently I had the chance to talk about authoring animations of CSS/SVG for
better performance at &lt;a href=&quot;https://www.graphicalweb.org/2014/&quot;&gt;The Graphical Web
2014&lt;/a&gt;. I thought I’d put up the slides here
in case they’re useful to others.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/pres/graphical-web-2014/&quot;&gt;Original HTML slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.slideshare.net/brianskold/animations-on-fire&quot;&gt;Slideshare version with notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/pres/graphical-web-2014/pdf/Animations%20on%20Fire.pdf&quot;&gt;PDF version with notes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=cpDqc5KPk7U&quot;&gt;Video&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re reading this blog directly or the syndicator didn’t eat this bit, you
can view the slides right here:&lt;/p&gt;
</content:encoded><comments>https://birtles.blog/2014/09/08/animations-on-fire-graphical-web-2014/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Web Animations @ html5j 2013</title><link>https://birtles.blog/2013/12/24/web-animations-html5j-2013/</link><guid isPermaLink="true">https://birtles.blog/2013/12/24/web-animations-html5j-2013/</guid><description>Over the weekend I had the chance to speak about Web Animations at the HTML5
conference 2013 in Tokyo.
I put a fair bit of work into the presentation so I thought I’d put up an
English version of the slides (including videos of the demos) in case they’re
useful to someone else looking for a gentle introduction to Web Animations.
</description><pubDate>Tue, 24 Dec 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the weekend I had the chance to speak about Web Animations at the &lt;a href=&quot;https://events.html5j.org/&quot;&gt;HTML5
conference 2013 in Tokyo&lt;/a&gt;.
I put a fair bit of work into the presentation so I thought I’d put up an
English version of the slides (including videos of the demos) in case they’re
useful to someone else looking for a gentle introduction to Web Animations.&lt;/p&gt;

&lt;p&gt;I ran out of steam when producing the last few slides so it kind of ends with
a fizzle but I put a fair bit of work into the other ones so hopefully it’s
entertaining.
Although you can’t tell from the slideshare version most of the slides include
animation somewhere and most of the pictures are made with SVG so I think it
looked pretty.&lt;/p&gt;

&lt;div&gt;
&lt;p&gt;&lt;a href=&quot;https://www.slideshare.net/brianskold/serious-animation-an-introduction-to-web-animations&quot;&gt;Slideshare&lt;/a&gt; /
&lt;a href=&quot;https://birtles.blog/pres/html5j-2013/pdf/html5j-2013-en.pdf&quot;&gt;PDF&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;(If you’re curious there’s the &lt;a href=&quot;https://birtles.blog/pres/html5j-2013/index-en.html&quot;&gt;HTML version&lt;/a&gt;
too but be warned that it doesn’t have explanatory notes like the slideshare
and PDF versions.)&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;(日本語の資料ももちろんあります！&lt;a href=&quot;https://www.youtube.com/watch?v=Chdlf5PK7E0#t=435&quot;&gt;イベントの配信&lt;/a&gt;、&lt;a href=&quot;https://www.slideshare.net/brianskold/html5j-2013&quot;&gt;Slideshareの資料&lt;/a&gt;、&lt;a href=&quot;https://birtles.blog/pres/html5j-2013/pdf/html5j-2013-ja.pdf&quot;&gt;PDF版&lt;/a&gt;、&lt;a href=&quot;https://birtles.blog/pres/html5j-2013/&quot;&gt;HTML版&lt;/a&gt;(注釈なし)をご覧ください。）&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2013/12/24/web-animations-html5j-2013/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Players wanted: the pause and seek game</title><link>https://birtles.blog/2013/07/25/players-wanted-the-pause-and-seek-game/</link><guid isPermaLink="true">https://birtles.blog/2013/07/25/players-wanted-the-pause-and-seek-game/</guid><description>Last
time
I introduced timing
groups in
Web Animations as a simple yet powerful
tool for synchronising animations. Great as they are, they open up a few
interesting questions.
For example, what happens when you pause an animation that’s in a timing
group?
</description><pubDate>Thu, 25 Jul 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://birtles.blog/2013/07/09/group-and-conquer-timing-groups-for-your-synchronization-woes/&quot;&gt;Last
time&lt;/a&gt;
I introduced &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#grouping-and-synchronization&quot;&gt;timing
groups&lt;/a&gt; in
&lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;Web Animations&lt;/a&gt; as a simple yet powerful
tool for synchronising animations. Great as they are, they open up a few
interesting questions.
&lt;strong&gt;For example, what happens when you pause an animation that’s in a timing
group?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Consider the following parallel timing group.
It has two child animations, A and B, and the group repeats twice.&lt;/p&gt;

  
    A parallel timing group with two children A and B whereby the group repeats
    twice.
  
  
  
  
  
  
  
    
    
  
  
  
  
    
     
  
  
  
  
  
  

&lt;p&gt;Suppose we pause child animation A at the red down arrow and then resume it at
the red up arrow. What should happen?&lt;/p&gt;
&lt;p&gt;One option is to just let everything play as normal.&lt;/p&gt;

  
    A child of the parallel timing group is paused such that all other animations
    continue to play as normal.
  
  
  
  
  
  
  
    
    
  
  
  
    
    
  
  
  
  
  
    
    
  
  
  
  
  
  
  

&lt;p&gt;But then what happens to the second run of A? Does it run at all? Get squashed?
Get overlapped? And if so, who wins?&lt;/p&gt;
&lt;p&gt;So what if we automatically unpause animation A when we hit an iteration
boundary?&lt;/p&gt;

  
    A child of the parallel timing group is paused such that it is automatically
    unpaused when an interval boundary is reached.
  
  
  
  
  
  
  
    
    
  
  
  
    
    
  
  
  
  
  
    
    
  
  
  
  
  
  
  

&lt;p&gt;From an API point-of-view that automatic unpausing is tricky and likely to lead
to bugs where a piece of script assumes an animation is paused but on some
devices the interval boundary occurs before the script gets a chance to run,
breaking the assumption.&lt;/p&gt;
&lt;p&gt;Another approach is just to stretch the iteration to fit the pause like so.&lt;/p&gt;

  
    A child of the parallel timing group is paused such that the iteration is
    stretched to fill the pause amount.
  
  
  
  
  
  
  
    
    
  
  
  
    
    
  
  
  
  
  
    
    
  
  
  
  
  
  
  

&lt;p&gt;This mostly works for parallel containers but, &lt;strong&gt;like the other behaviours, it
doesn’t make sense for a sequence timing group because the sequence is broken&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Also, &lt;strong&gt;all these behaviours are problematic if we seek the group whilst a child
is paused&lt;/strong&gt;. And if we seek backwards after unpausing what is the expected state
of the world?&lt;/p&gt;
&lt;p&gt;The approach that provides the most intuitive behaviour in these situations is
simply to pause the group as a whole like so.&lt;/p&gt;

  
    A child of the parallel timing group is paused by applying the pause to the
    group.
  
  
  
  
  
  
  
    
    
  
  
  
    
    
  
  
  
  
    
    
  
  
  
    
    
  
  
  
  
  
  
  

&lt;p&gt;This of course applies all the way up the tree.&lt;/p&gt;
&lt;h2&gt;But what do other APIs do?&lt;/h2&gt;
&lt;p&gt;Looking at &lt;a href=&quot;https://www.w3.org/Graphics/fx/wiki/Web_Animations/API_Comparison&quot;&gt;a number of other animation
APIs&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-animation.html&quot;&gt;QML&lt;/a&gt; just
ignores play control on animations if they’re in a group.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.android.com/reference/android/animation/AnimatorSet.html&quot;&gt;Android&lt;/a&gt;
doesn’t include repeating etc. on groups and animations and groups don’t have
play control.&lt;/li&gt;
&lt;li&gt;In &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ms752312.aspx&quot;&gt;WPF&lt;/a&gt; only the root
clock can be interactively controlled.&lt;/li&gt;
&lt;li&gt;In
&lt;a href=&quot;https://html.spec.whatwg.org/multipage/media.html#htmlmediaelement&quot;&gt;HTML&lt;/a&gt;,
media slaved to a controller (similar in some sense to a timing group) behaves
differently to independent media. You can pause it independently, but seeking
throws an exception. Pausing due to buffering pauses the controller. There is
no repeating.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, QML and WPF push pausing to the root of timing hierarchy. Android
and HTML manage to do something different but only because they don’t allow
groups to repeat.&lt;/p&gt;
&lt;p&gt;For Web Animations, like QML and WPF, the best option is to push pausing and
other play control to the root of the timing hierarchy. The trouble comes when
we try to represent this in the API.&lt;/p&gt;
&lt;p&gt;At first we tried to do this transparently, that is, you’d call &lt;code&gt;pause&lt;/code&gt; and it
would just go up to the top-level timing group and apply the pause there.
However, a couple of concerns were raised with this,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It’s not obvious that the operation you’re performing may have wide-reaching
effects.&lt;/li&gt;
&lt;li&gt;It doesn’t work for seeking since the time values are relative to the child
not the parent. HTML just throws an exception in this case, but some people
felt uncomfortable that this method would sometimes work and sometimes throw
an exception depending on whether there was a parent timing group or not.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Enter the players&lt;/h2&gt;
&lt;p&gt;In order to emphasise the fact that play control (pausing, seeking, etc.) takes
place at the root-most timing group a new concept, the &lt;strong&gt;player&lt;/strong&gt;, was
introduced.
&lt;strong&gt;A player plays things.&lt;/strong&gt;
It’s the point of attachment between some timed content and a timeline.
The arrangement is as follows.&lt;/p&gt;

  
    Players form the point of attachment between the rootmost timing groups and
    animations and a timeline.
  
  
  
  
  
    
    
    
    
    
    
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  

&lt;p&gt;From a code point of view it looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;var anim = elem.animate({ left: &apos;20px&apos; }, 3);
anim.player.pause();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This separation hopefully makes it more obvious to an author that the change
they are making may have more wide-reaching effects.&lt;/p&gt;
&lt;p&gt;It also can make avoiding some common coding mistakes a little easier.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;// The following could cause some animations to be sped up 4, 8 times or more
elem.getCurrentAnimations().forEach(function (anim) {
  anim.player.playbackRate *= 2;
});

// The following will speed everything up by a factor of 2 and no more
elem.getCurrentPlayers().forEach(function (player) {
  player.playbackRate *= 2;
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It also has a few nice properties:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;TimedItem.localTime&lt;/code&gt; is always readonly and has a different name to the
always writeable Player.currentTime.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TimedItem.timing.playbackRate&lt;/code&gt; affects the model in the same way as changing
other timing parameters does including possibly causing the playback position
to jump. &lt;code&gt;Player.playbackRate&lt;/code&gt;, on the other hand, makes dynamic changes so
that the current playback position is preserved.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately, introducing the idea of players adds conceptual weight to the
API. It’s probably one of the most unfamiliar concepts for people coming to the
specification (hence this blog post!). For these reasons I resisted this change
strongly but ultimately lost. 🙂&lt;/p&gt;
&lt;p&gt;That said, it does make the model more consistent and therefore, to some degree,
more intuitive. It is also expected that many authors will never use this
functionality (jQuery, for example, does not provide pause control) and so this
additional concept shouldn’t become a barrier to adoption for simple usage.&lt;/p&gt;
&lt;p&gt;I’ll look forward to seeing how authors take to this concept. If you have any
feedback, feel free to follow-up at &lt;a href=&quot;mailto:public-fx@w3.org&quot;&gt;public-fx@w3.org&lt;/a&gt;
with subject starting &lt;code&gt;[web-animations]&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Upcoming changes&lt;/h2&gt;
&lt;p&gt;Recently we’ve been discussing some changes to the way players work. Currently
they just keep playing forever but we think it might make sense for them to
behave more like a VCR and stop when they hit the end of their media. This would
allow us to define a &lt;code&gt;reverse()&lt;/code&gt; method that behaves sensibly and perhaps make
players &lt;code&gt;then&lt;/code&gt;-able.&lt;/p&gt;
&lt;p&gt;You can see some of the discussion in &lt;a href=&quot;https://lists.w3.org/Archives/Public/public-fx/2013JulSep/0009.html&quot;&gt;the minutes from our recent
telcon&lt;/a&gt;,
item 6, &lt;em&gt;Making players stop&lt;/em&gt;. As always, your comments are welcome at
&lt;a href=&quot;mailto:public-fx@w3.org&quot;&gt;public-fx@w3.org&lt;/a&gt;.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2013/07/25/players-wanted-the-pause-and-seek-game/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Group and conquer: timing groups for your synchronization woes</title><link>https://birtles.blog/2013/07/09/group-and-conquer-timing-groups-for-your-synchronization-woes/</link><guid isPermaLink="true">https://birtles.blog/2013/07/09/group-and-conquer-timing-groups-for-your-synchronization-woes/</guid><description>Once you start animating anything more than simple fade and slide effects,
pretty soon you start wanting to synchronize things.
The penguins should start dancing together, the watermelon should explode the
moment the blind-folded person hits it, the credits should roll after the movie
finishes and so on.
</description><pubDate>Tue, 09 Jul 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Once you start animating anything more than simple fade and slide effects,
pretty soon you start wanting to synchronize things.
The penguins should start dancing together, the watermelon should explode the
moment the blind-folded person hits it, the credits should roll after the movie
finishes and so on.&lt;/p&gt;

&lt;p&gt;In this post I want to outline the approach taken to these problems in &lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;Web
Animations&lt;/a&gt; and the biggest new feature in
the spec: &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#grouping-and-synchronization&quot;&gt;timing
groups&lt;/a&gt;.
But first, what can we already do?&lt;/p&gt;
&lt;h2&gt;Synchronization in CSS&lt;/h2&gt;
&lt;p&gt;In CSS you can do a few things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;By toggling a style on a common ancestor you can get two animations to start
at the same time. For example, see &lt;a href=&quot;https://coding.smashingmagazine.com/2011/09/14/the-guide-to-css-animation-principles-and-examples/&quot;&gt;this example from Smashing
Magazine&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Using
&lt;a href=&quot;https://www.w3.org/TR/css-animations-1/#animation-delay&quot;&gt;animation-delay&lt;/a&gt;
you can stagger the start times of animations and by calculating the length of
A, you can use this to make B start after A.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are a few limitations though:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It’s not particularly scalable&lt;/strong&gt;—if A changes duration, you need to update
B as well. That’s particularly problematic if, for example, A is a video of
unknown length.&lt;/li&gt;
&lt;li&gt;You’re not declaring the temporal relationships between different
animations—their synchronization is just a by-product of how you triggered
them—and as a &lt;strong&gt;result there’s no easy way to pause or seek a particular set
of animations.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;It requires you to structure your document so that you’ve got a common
ancestor to toggle a class on.
Suddenly &lt;strong&gt;your document structure is doing triple duty:&lt;/strong&gt; semantics, layout
(all those empty &lt;code&gt;&amp;#x3C;div&gt;&lt;/code&gt;s to persuade CSS to do what you want), and timing.&lt;/li&gt;
&lt;li&gt;You &lt;strong&gt;can’t create animations on the fly that line up&lt;/strong&gt; with already running
animations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The problem with SVG and syncbase timing&lt;/h2&gt;
&lt;p&gt;SVG has a neat feature which seems to meet these needs: syncbase timing. That
lets you create arrangements like:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-svg&quot;&gt;&amp;#x3C;animate id=&quot;a&quot; begin=&quot;b.end&quot; ... /&gt;
&amp;#x3C;animate id=&quot;b&quot; begin=&quot;0s&quot; end=&quot;c.end&quot; ... /&gt;
&amp;#x3C;animate id=&quot;c&quot; begin=&quot;a.begin+2s&quot; ... /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That would seem to do everything we could ever want, except it has a few problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;It’s complex.&lt;/strong&gt;
The above example is just the tip of the iceberg. You can have any number of
conditions on both the begin and end of an animation pointing to any other
animation including the same animation. You can create cyclic dependencies and
some are allowed, some are not, and the rules for breaking cycles are vague
(and thus, inconsistently implemented).&lt;/p&gt;
&lt;p&gt;What’s more, all this feeds in to the most complex part of SVG animation:
deciding what intervals to create. As a result if you want to determine what
animations are active at a given time, you have to step through all the
significant moments up to that time and work out what intervals to create.
This makes seeking costly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Another problem is that &lt;strong&gt;you can’t cancel just part of such a sequence.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For example, imagine you have a sequence of actions A, B, and C representing
“fade the background of the button from grey to blue”, “pulse it”, then “make
it glow”. You trigger A when the mouse moves over the button but the mouse
suddenly leaves while A is still running. You cancel A (e.g. using
&lt;code&gt;end=&quot;mouseout&quot;&lt;/code&gt; or &lt;code&gt;endElement&lt;/code&gt;) but then B still runs since it sees that A has
ended. And consequently C also runs. There’s no way to cancel the chain and
nor is there any way to seek/pause such a chain independently of other
animations that might be running.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Enter timing groups&lt;/h2&gt;
&lt;p&gt;These use cases can be addressed using the concept of timing groups. This is a well-established concept in animation APIs. For example,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-animation.html&quot;&gt;QML&lt;/a&gt; has
&lt;code&gt;ParallelAnimation&lt;/code&gt;s and &lt;code&gt;SequenceAnimation&lt;/code&gt;s.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/TR/SMIL/smil-timing.html#q52&quot;&gt;SMIL&lt;/a&gt; has &lt;code&gt;&amp;#x3C;par&gt;&lt;/code&gt;, &lt;code&gt;&amp;#x3C;seq&gt;&lt;/code&gt;,
and &lt;code&gt;&amp;#x3C;excl&gt;&lt;/code&gt; time containers.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.android.com/reference/android/animation/AnimatorSet.html&quot;&gt;Android&lt;/a&gt;
has &lt;code&gt;AnimatorSet&lt;/code&gt;s that play animations together or in sequence.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common to all these APIs is the concept of two types of groups: &lt;strong&gt;groups that
run animations together&lt;/strong&gt; and &lt;strong&gt;groups that run animations in sequence&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Furthermore, in each of these APIs the two types of &lt;strong&gt;groups can be nested&lt;/strong&gt; so
you can easily build complex arrangements up from simple parts in a way that is
easy to reason about.&lt;/p&gt;
&lt;p&gt;For example, the following arrangement:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-svg&quot;&gt;&amp;#x3C;animate id=&quot;curtainOpens&quot; ... /&gt;
&amp;#x3C;animate id=&quot;penguinADances&quot; begin=&quot;curtainOpens.end&quot; ... /&gt;
&amp;#x3C;animate id=&quot;penguinBDances&quot; begin=&quot;curtainOpens.end&quot; ... /&gt;
&amp;#x3C;animate id=&quot;curtainCloses&quot; begin=&quot;penguinBDances.end&quot; ... /&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;could be represented with timing groups as:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-svg&quot;&gt;&amp;#x3C;seq&gt;
  &amp;#x3C;animate id=&quot;curtainOpens&quot; ... /&gt;
  &amp;#x3C;par&gt;
    &amp;#x3C;animate id=&quot;penguinADances&quot; ... /&gt;
    &amp;#x3C;animate id=&quot;penguinBDances&quot; ... /&gt;
  &amp;#x3C;/par&gt;
  &amp;#x3C;animate id=&quot;curtainCloses&quot; ... /&gt;
&amp;#x3C;/seq&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Graphically, the arrangement is as follows:&lt;/p&gt;

  
    
      
    
  
  
  
    
    
      
    
  
  
  
    
    
    
    
    
    
      
      
      
        
      
      
        
      
    
    
      
    
  

&lt;p&gt;You can cancel a chain of animations in this case by simply cancelling the
group. The hierarchical nature of the groups also means seeking is constant-time
with regards to the seek interval.&lt;/p&gt;
&lt;h2&gt;Timing groups in Web Animations&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;Web Animations&lt;/a&gt; we have adopted this
same approach of using timing groups with the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Two types of timing groups: &lt;strong&gt;parallel, sequence&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Children of a group can have a delay which can also be negative.&lt;/strong&gt;
This allows children of a sequence group to overlap so you can, for example,
start a fade animation 2s before a video ends. (SMIL does not allow negative
delays on children of a sequence group.)&lt;/li&gt;
&lt;li&gt;Any timing property you can apply to an animation, you can also apply to
a group which means &lt;strong&gt;you can repeat, ease, reverse, delay, or speed up
a group.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The last point is interesting since most other APIs don’t do that. It can be
quite useful as we showed in a demo of this in &lt;a href=&quot;https://www.youtube.com/watch?v=VvNQNtIfXXI&quot;&gt;our preview video last
October&lt;/a&gt; where we combined a door
closing animation and a creaking sound “animation” in a group then eased the
group.&lt;/p&gt;
&lt;p&gt;However, it introduces some complexity. For example, since easing functions can
be non-invertible, it means you can’t always convert from child time to group
time which complicates event handling.&lt;/p&gt;
&lt;p&gt;Also, the interaction between &lt;a href=&quot;https://www.w3.org/TR/web-animations/#fill-behavior&quot;&gt;fill
modes&lt;/a&gt; specified on a group
and on a child are not always obvious and we need to revise the spec to be more
intuitive in this area.&lt;/p&gt;
&lt;p&gt;Building up the example above using the API in Web Animations look like the
following.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-js&quot;&gt;document.timeline.play(
  new SeqGroup([
    new Animation(...),   // Curtains open
    new ParGroup([
      new Animation(...), // Penguin A
      new Animation(...)  // Penguin B
    ]),
    new Animation(...)    // Curtains close
  ])
);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On a side-note, we’ve had some feedback about &lt;code&gt;ParGroup&lt;/code&gt; and &lt;code&gt;SeqGroup&lt;/code&gt; being
a bit cryptic, especially for anyone not familiar with SMIL (which is pretty
much everyone).
&lt;code&gt;ParallelGroup&lt;/code&gt; would be more readable but it’s a lot to type for something we
expect authors to use a lot.
I wonder if just &lt;code&gt;Parallel&lt;/code&gt; would make sense?
Perhaps this could be a named constructor for &lt;code&gt;ParallelGroup&lt;/code&gt;?
If you have any suggestions we’d love to hear them.
Either respond here, or, better yet, send a mail to
&lt;a href=&quot;mailto:public-fx@w3.org&quot;&gt;public-fx@w3.org&lt;/a&gt; with subject starting
&lt;code&gt;[web-animations]&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The mapping of timing groups to SVG and CSS has yet to be worked out.&lt;/p&gt;
&lt;h2&gt;Future extensions to timing groups&lt;/h2&gt;
&lt;p&gt;One common request that arises in regards to timing groups is the ability to set
the duration of the group and specify the duration of the children as fractions
of that parent.
That sort of adaptive duration is something that’s quite useful but also can
easily become complex—like CSS flexbox in the temporal domain.
It’s something we’ll look at in a future version but for now we’re comfortable
it can be added to the model and API fairly naturally.&lt;/p&gt;
&lt;p&gt;If you want to read up on the detail, have a look at &lt;a href=&quot;https://drafts.csswg.org/web-animations-2/#grouping-and-synchronization&quot;&gt;the
spec&lt;/a&gt;.
As always, your comments are welcome at
&lt;a href=&quot;mailto:public-fx@w3.org&quot;&gt;public-fx@w3.org&lt;/a&gt; with subject starting
&lt;code&gt;[web-animations]&lt;/code&gt;.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2013/07/09/group-and-conquer-timing-groups-for-your-synchronization-woes/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Introducing Web Animations</title><link>https://birtles.blog/2013/06/26/introducing-web-animations/</link><guid isPermaLink="true">https://birtles.blog/2013/06/26/introducing-web-animations/</guid><description>Today we finally shipped the First Public Working Draft of Web
Animations!
</description><pubDate>Wed, 26 Jun 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today we finally shipped the &lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;First Public Working Draft of Web
Animations&lt;/a&gt;!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Working Draft: &lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;https://www.w3.org/TR/web-animations/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Editor’s Draft: &lt;a href=&quot;https://drafts.csswg.org/web-animations-1/&quot;&gt;https://drafts.csswg.org/web-animations-1/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Over the coming weeks I’d like to introduce some of the key concepts as well as
some of the issues that need your input.&lt;/p&gt;
&lt;p&gt;First, I’d like to give an overview of where the spec comes from and what it
covers.&lt;/p&gt;
&lt;h2&gt;Why Web Animations? A summary of happenings until now&lt;/h2&gt;
&lt;p&gt;On the Web today we have &lt;a href=&quot;https://www.w3.org/TR/css-animations-1/&quot;&gt;CSS
Animation&lt;/a&gt;
(including &lt;a href=&quot;https://www.w3.org/TR/css-transitions-1/&quot;&gt;Transitions&lt;/a&gt;) and &lt;a href=&quot;https://www.w3.org/TR/SVG11/animate.html&quot;&gt;SVG
Animation&lt;/a&gt; and they both have their
problems.
For example, CSS is so simple it doesn’t even support synchronization and SVG is
pretty hairy when it comes to interval negotiation and syncbase timing—and it’s
SVG-only.
Most of all, though, they’re completely separate.&lt;/p&gt;
&lt;p&gt;Also, Microsoft don’t support SVG Animation.
They have consistently maintained that they want to see a single model for
animation on the Web (e.g.
&lt;a href=&quot;https://www.w3.org/2011/03/02-svg-irc#T22-19-34&quot;&gt;minutes&lt;/a&gt;) and that that model
should have an API. That’s a very reasonable position in my mind, albeit
frustrating for authors who want to use SVG Animation now.&lt;/p&gt;
&lt;p&gt;The story since then is as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On several occasions throughout 2011 and 2012 I proposed various alternatives
(&lt;a href=&quot;https://www.w3.org/Graphics/SVG/WG/wiki/F2F/Auckland_2011/Animation_improvements&quot;&gt;#1&lt;/a&gt;
– &lt;a href=&quot;https://birtles.blog/pres/svg-2-animation/&quot;&gt;presentation&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/Graphics/SVG/WG/wiki/F2F/Seattle_2011/Agenda/Animations/Harmonisation&quot;&gt;#2&lt;/a&gt;,
&lt;a href=&quot;https://www.w3.org/Graphics/SVG/WG/wiki/F2F/Sydney_2012/Agenda/Animations/WebAnimations&quot;&gt;#3&lt;/a&gt;)
for harmonizing the two such as importing SVG features into CSS and vice
versa. People mostly just nodded in agreement and nothing happened.&lt;/li&gt;
&lt;li&gt;In January 2012, Adobe wisely suggested I &lt;a href=&quot;https://www.w3.org/2012/01/13-svg-irc#T23-14-43&quot;&gt;go away and prepare a concrete
proposal&lt;/a&gt; so people can get
a feel for what is might look like. Adobe also offered to assist where they
could.&lt;/li&gt;
&lt;li&gt;At the end of January 2012 I invited a contact from Google to join in since he
had some great ideas about state machines.&lt;/li&gt;
&lt;li&gt;In March 2012 folks from Adobe, Google and I (Mozilla) got together in Tokyo
and hacked out a first version of the spec.&lt;/li&gt;
&lt;li&gt;In May 2012 we &lt;a href=&quot;https://lists.w3.org/Archives/Public/public-fx/2012AprJun/0107.html&quot;&gt;got approval from the CSS and SVG working
groups&lt;/a&gt; to
continue this work as an official work item.&lt;/li&gt;
&lt;li&gt;In September 2012 we presented a &lt;a href=&quot;https://www.youtube.com/watch?v=VvNQNtIfXXI&quot;&gt;demo of the
work&lt;/a&gt; at the Graphical Web conference in Zurich
(&lt;a href=&quot;https://www.multimedia.ethz.ch/conferences/2012/svgopen/05-1_thursday?doi=10.3930/ETHZ/AV-f8a1c756-a4de-4e64-98f5-c2c0b90bc9af&amp;#x26;autostart=false&quot;&gt;video recording&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;In June 2013 we &lt;a href=&quot;https://logs.csswg.org/irc.w3.org/css/?date=2013-06-04&quot;&gt;got approval from the CSS and SVG working
groups&lt;/a&gt; to publish
a FPWD.&lt;/li&gt;
&lt;li&gt;Today (25 June 2013) we finally &lt;a href=&quot;https://www.w3.org/TR/web-animations/&quot;&gt;published
something&lt;/a&gt;!&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What’s in the box?&lt;/h2&gt;
&lt;p&gt;Basically, this:&lt;/p&gt;

  
    
    
    
  
  
    
    
    
    
  
  
    
    
    
    
    
    
      
      
      
      
    
    
    
      
      
      
      
      
      
    
    
    
      
      
      
      
      
    
    
    
      
      
      
      
    
    
    
      
    
    
    
    
      
    
    
  

&lt;p&gt;Web Animations is essentially a common model for animation that underlies CSS and SVG. It covers the common features of both plus a few only found in one or the other.&lt;/p&gt;
&lt;p&gt;It also has a few extra features not currently found in either:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#grouping-and-synchronization&quot;&gt;Timing
groups&lt;/a&gt;&lt;/strong&gt;
– This is the primary means of synchronization. It’s quite powerful but I’ll
leave the details and justification for this to a separate post.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Speed control
(&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#speed-control&quot;&gt;#1&lt;/a&gt; and
&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#timed-item-speed-control&quot;&gt;#2&lt;/a&gt;)&lt;/strong&gt;
– This is a &lt;a href=&quot;https://www.w3.org/Graphics/SVG/WG/wiki/SVG2_Requirements_Input#SMIL_time_manipulation_module&quot;&gt;requested feature for
SVG2&lt;/a&gt;
and may be useful for achieving reversing effects such as exposed in CSS.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#custom-effects&quot;&gt;Custom
effects&lt;/a&gt;
(&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#the-customeffect-callback-interface&quot;&gt;API&lt;/a&gt;)&lt;/strong&gt;
– This allows the Web Animations timing model to be used to drive animations
of HTML canvas etc. by registering a script callback.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.w3.org/TR/2013/WD-web-animations-20130625/#dfn-iteration-start&quot;&gt;Iteration
start&lt;/a&gt;&lt;/strong&gt;
– This is a minor but much-requested feature that allows you to start an
animation part-way through its interval.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What’s &lt;em&gt;not&lt;/em&gt; included?&lt;/h2&gt;
&lt;p&gt;Bear in mind that Web Animations is essentially a model. It’s not a declarative syntax. That’s something left to other specs. The API happens to be bundled with the model simply because that makes it easy to keep the two in sync.&lt;/p&gt;
&lt;p&gt;The arrangement is as follows:&lt;/p&gt;

  
  
  
  
  
  
  
  
  
    
    
    
  
  
  
  
  
  
  
    
    
    
  
  
  
  
  
  
    
    
    
  

&lt;p&gt;The CSS-specific features required for CSS animations and transitions will be covered in a separate specification, possibly called “CSS Animations/Transitions level 4” which expresses its features in terms of the Web Animations model.&lt;/p&gt;
&lt;p&gt;Likewise, current SVG features such as syncbase timing, or targetting attributes (not just CSS properties) will be covered by a separate specification (my next task) expressed in terms of that model. That specification may be called something like “SVG Animation” but I suspect not since quite a few people have expressed interest in allowing it to apply to HTML content too.&lt;/p&gt;
&lt;p&gt;Other features that are not included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bounce/spring timing functions&lt;/strong&gt; – we really wanted to make this possible
and have a couple of simple extensions to timing functions to allow this but
we haven’t yet reached agreement about which one is best so we’re leaving them
both out for now.&lt;/p&gt;
&lt;p&gt;The plan is to follow up with a separate specification which provides
additional timing functions anyway.&lt;/p&gt;
&lt;p&gt;(In fact, with the current working draft, you can’t even do more than one
timing function over an animation currently but that will be fixed in the next
draft when we introduce chained timing functions).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Media integration&lt;/strong&gt; – this is something a lot of people have been asking for
but we decided to postpone it in the interests of progressing the spec along.&lt;/p&gt;
&lt;p&gt;The good news is this used to be part of the spec so we know it integrates very cleanly.&lt;/p&gt;
&lt;p&gt;For now we’ll work on it in a separate spec and if that comes along quickly
enough we might merge it back in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;State machines&lt;/strong&gt; – this is something that is very useful when you start
programming UI interactions but something we decided is not critical for the
first version of the spec.&lt;/p&gt;
&lt;p&gt;Again, we’ll probably work on this as a separate spec.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;API?&lt;/h2&gt;
&lt;p&gt;Originally I opposed the idea of adding an API because I think declarative solutions are generally preferable. However, the API is useful in a few cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It lets you inspect the state of all animations in the document. Anyone can
build developer tools that present you with a timeline of all the running CSS
animations/transitions/SVG animations in the document for debugging.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It lets you make runtime changes to declarative animations—for many apps
a combination of declarative and procedural approaches is the best fit and
lets you achieve effects that might not be possible using purely declarative
features.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;For some problems a procedural approach is suitable and in those cases using
the API is both simpler than writing the animation loop yourself and also
means the browser can optimise the animation for smoother performance and less
battery consumption.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Implementations?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://groups.google.com/a/chromium.org/forum/#!searchin/blink-dev/web$20animations/blink-dev/jDjDMTuKegI/Uh1qz44DSBsJ&quot;&gt;Work has started on implementation in
Blink&lt;/a&gt;
and is &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=875219&quot;&gt;on the radar for
Gecko&lt;/a&gt;. Until then &lt;a href=&quot;https://github.com/web-animations/web-animations-js&quot;&gt;a
polyfill&lt;/a&gt; is coming along
in leaps and bounds and covers nearly all of the FPWD.&lt;/p&gt;
&lt;p&gt;That’s it for now. I’ll follow up with posts explaining specific features and
issues needing input but if you have any feedback on the spec, don’t hesitate to
send it along to &lt;a href=&quot;mailto:public-fx@w3.org&quot;&gt;public-fx@w3.org&lt;/a&gt; with subject
&lt;code&gt;[web-animations]&lt;/code&gt;.
Thanks!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2013/06/26/introducing-web-animations/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Help with math(s)</title><link>https://birtles.blog/2013/01/15/help-with-maths/</link><guid isPermaLink="true">https://birtles.blog/2013/01/15/help-with-maths/</guid><pubDate>Tue, 15 Jan 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I originally prepared this post before others working on the Web
Animations spec assured me they would find a solution. I posted it
password-protected for their sake not realising it would show up on planet!
Sorry! Anyway, here is the original post for those who were curious. There are
already some folks working on this, but other input may still be useful!&lt;/p&gt;
&lt;p&gt;One of the limitations of CSS and SVG animations is that you can’t do a bouncing
effect. That is, you can’t easily do this:&lt;/p&gt;


  
    
  
  

Bouncing in SVG. Click the circle to restart.

&lt;p&gt;You can emulate it (as above), but it really should be the job of the timing
function to do this kind of easing.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&quot;https://dvcs.w3.org/hg/FXTF/raw-file/tip/web-anim/index.html&quot;&gt;Web
Animations&lt;/a&gt; we’ve
been trying to address this.
At first I tried creating a simple smoothing function where you’d specify
a series of points and it interpolates smoothly between then. This proved more
complex than expected so I narrowed the problem down to just spring-like
animations.&lt;/p&gt;
&lt;p&gt;It’s easy to generate a spring-like function—I found a sine wave plus
exponential dampening plus some scaling of the period does ok, but in terms of
parameterisation I &lt;strong&gt;think&lt;/strong&gt; you probably want the following handles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;overshoot&lt;/strong&gt; – How far past the target value to reach on the first cycle of
the spring-like motion. 1.5 means overshoot by 50% (when exposed to CSS and
SVG, this parameter might be exposed as just ’50%’ instead of 1.5). This is
particularly useful if, for example, you’re animating something inside
a container and want to be sure the effect won’t fall outside the bounds of
the container.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;elasticity&lt;/strong&gt; - How much should it bounce back and forwards before converging
on the target value? Higher numbers mean more bouncing. After discussing with
the others working on Web Animations spec, this may or may not be the most
suitable parameter. If at all possible however we want to reduce the number of
parameters to avoid being &lt;a href=&quot;https://doc.qt.io/qt-6/qml-qtquick-springanimation.html&quot;&gt;as complex as
QML&lt;/a&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Parameterising the spring function in those terms proved a bit beyond my
mathematical abilities. I made the following prototype but it’s all kinds of
clumsy.&lt;/p&gt;
&lt;div&gt;
  &lt;p&gt;
    Overshoot: &lt;input id=&quot;user-content-overshoot&quot; size=&quot;4&quot; value=&quot;1.5&quot; disabled type=&quot;checkbox&quot;&gt;
    Elasticity: &lt;input id=&quot;user-content-elasticity&quot; size=&quot;3&quot; value=&quot;3&quot; disabled type=&quot;checkbox&quot;&gt;
  &lt;/p&gt;
  
    
  
&lt;/div&gt;

&lt;p&gt;Problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Doesn’t work in all ranges.
For example, for an &lt;em&gt;overshoot&lt;/em&gt; of 5, the second peak is higher than the
first.
An &lt;em&gt;overshoot&lt;/em&gt; of 1 also doesn’t work.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The first part of the curve (on the initial path to the overshoot value) seems
wrong—sometimes there are lumps or kinks in it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Rough requirements for the function, &lt;code&gt;f(x)&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;overshoot&lt;/em&gt; is a value in the range [1,∞)&lt;/li&gt;
&lt;li&gt;&lt;em&gt;elasticity&lt;/em&gt; — not even sure if this is the right parameter. It would probably
be ideal if &lt;em&gt;elasticity&lt;/em&gt; of 1 simply made the animation go to the overshoot
value and then return to 1 without any bouncing. A value of 2 might make it
overshoot once, dip below 1, then return on 1.&lt;/li&gt;
&lt;li&gt;For 0 ≤ x ≤ 1 the global(?) maximum of the function is overshoot and this
should also be the first maximum in the range&lt;/li&gt;
&lt;li&gt;&lt;code&gt;f(0) = 0&lt;/code&gt; and &lt;code&gt;f(1) = 1&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;When elasticity is high or overshoot is high it should probably reach the
overshoot value sooner since the bounce component will take longer to complete&lt;/li&gt;
&lt;li&gt;The function should probably not go negative initially, unless &lt;em&gt;overshoot&lt;/em&gt; &gt;
2 in which case it might be ok.&lt;/li&gt;
&lt;li&gt;Not sure if the first part should be ease-in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As I said, there are already some folks working on this, but if you want to have
a try you can &lt;a href=&quot;https://jsfiddle.net/CZ3Kn/11/#fork&quot;&gt;fork the fiddle above&lt;/a&gt; and
hack away.
Alternatively, there is an &lt;a href=&quot;https://birtles.blog/assets/timingfunctions.xls&quot;&gt;Excel spreadsheet&lt;/a&gt;
or &lt;a href=&quot;https://birtles.blog/assets/timingfunctions.ods&quot;&gt;OpenDocument spreadsheet&lt;/a&gt; version.&lt;/p&gt;
&lt;p&gt;On the other hand, if you think this is not the most useful function or
something more general is possible, feel free to suggest that too!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2013/01/15/help-with-maths/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Web Animations</title><link>https://birtles.blog/2012/10/31/web-animations/</link><guid isPermaLink="true">https://birtles.blog/2012/10/31/web-animations/</guid><description>It must be time for my biannual blog post and this time I’d like to introduce
a new development in animation for the Web, called, creatively enough, Web
Animations.
</description><pubDate>Wed, 31 Oct 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It must be time for my biannual blog post and this time I’d like to introduce
a new development in animation for the Web, called, creatively enough, Web
Animations.&lt;/p&gt;

&lt;p&gt;Some of you may have heard rumblings of an attempt to overcome some of the
limitations with both CSS and SVG animations and unify them at the same time.
Well, that’s what some folks at Google, Adobe and myself (Mozilla) are trying to
do.&lt;/p&gt;
&lt;p&gt;I’ve put together a video of some of the ideas we have so far:&lt;/p&gt;

&lt;video&gt;
&lt;source src=&quot;https://birtles.blog/assets/web-anim-demo-1-with-captions.mp4&quot; type=&quot;video/mp4&quot;&gt;
&lt;source src=&quot;https://birtles.blog/assets/web-anim-demo-1-with-captions.webm&quot; type=&quot;video/webm&quot;&gt;
&lt;/video&gt;

&lt;p&gt;An in case the video gets synderadicated here’s a Youtube link:
&lt;a href=&quot;https://www.youtube.com/watch?v=VvNQNtIfXXI&quot;&gt;https://www.youtube.com/watch?v=VvNQNtIfXXI&lt;/a&gt;&lt;/p&gt;


&lt;p&gt;If you’re interested in the details, the latest version of the spec is here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://dvcs.w3.org/hg/FXTF/raw-file/tip/web-anim/index.html&quot;&gt;https://dvcs.w3.org/hg/FXTF/raw-file/tip/web-anim/index.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A few points to bear in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There are still lots of holes. The behaviour of pausing and reversing is
particularly in flux at the moment and the integration with media is still
just thoughts, yet to be fleshed out and spec-ified.&lt;/li&gt;
&lt;li&gt;The integration with CSS and SVG will be specified in
&lt;a href=&quot;https://github.com/w3c/web-animations/blob/master/css-integration.html&quot;&gt;separate&lt;/a&gt;
&lt;a href=&quot;https://github.com/w3c/web-animations/blob/master/animation-elements.html&quot;&gt;documents&lt;/a&gt;
(just placeholder text for now).&lt;/li&gt;
&lt;li&gt;If you’ve got suggestions, please feel free to send feedback to &lt;a href=&quot;https://lists.w3.org/Archives/Public/public-fx/&quot;&gt;the public-fx
W3C mailing list&lt;/a&gt;
with the subject &lt;code&gt;[web-anim]&lt;/code&gt; at the start of the subject.&lt;/li&gt;
&lt;li&gt;Progress from my end has slowed down recently due to some workshops I’ve been
involved in but I’ll hopefully be back into it by the end of November.&lt;/li&gt;
&lt;li&gt;We have a shim in the works (that’s what the video uses) but it’s currently
awaiting approval for release. Should be ready soon.&lt;/li&gt;
&lt;/ul&gt;</content:encoded><comments>https://birtles.blog/2012/10/31/web-animations/#comments</comments><category>Archive</category><category>Web Animations</category></item><item><title>Parapara Animation</title><link>https://birtles.blog/2012/01/27/parapara-animation/</link><guid isPermaLink="true">https://birtles.blog/2012/01/27/parapara-animation/</guid><description>About a week ago Mozilla Japan put on a two-day event in Tokyo called Mozilla
Vision 2012.
It was a great weekend with several hundred people coming to talk about what it
means to be Open, and, in very Japanese-style, see some cool robots (courtesy of
Takahashi Tomotaka-san).
</description><pubDate>Fri, 27 Jan 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;About a week ago Mozilla Japan put on a two-day event in Tokyo called Mozilla
Vision 2012.
It was a great weekend with several hundred people coming to talk about what it
means to be Open, and, in very Japanese-style, see some cool robots (courtesy of
&lt;a href=&quot;http://www.robo-garage.com/&quot;&gt;Takahashi Tomotaka-san&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/takahashi-san.jpg&quot; alt=&quot;Takahashi Tomotaka-san with his robot&quot; title=&quot;高橋智隆さん&quot;&gt;&lt;/p&gt;
&lt;p&gt;Personally, I was involved in running the Parapara Animation Workshop* where
kids enjoyed drawing simple frame-based animation on a tablet which was then
added to a much bigger animation projected on the walls. The purpose of the
project was to teach kids the basics of animation as well as to encourage them
to be not just web spectators but web makers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/parapara-icon.png&quot; alt=&quot;Parapara animation icon&quot; title=&quot;パラパラアニメーション&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s a workshop that was &lt;a href=&quot;https://web.archive.org/web/20111105201457/https://minism.jp/parapara/workshop.html&quot;&gt;originally done by a group of Keio University
Students&lt;/a&gt; and they helped run it again
this time. The main difference is that last time it was mostly iOS-based, this
time it was all Web.&lt;/p&gt;
&lt;p&gt;Christian Heilmann has &lt;a href=&quot;https://hacks.mozilla.org/2012/01/mozilla-vision-2012-day-two-here-come-the-web-makers-of-tomorrow/&quot;&gt;written up a great summary of this part of the
program&lt;/a&gt;
including a quick interview where you can see how it worked.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/parapara-video-thumb.jpg&quot; alt=&quot;Screencap from video demonstration&quot; title=&quot;Parapara workshop video. Select to watch the video.&quot;&gt;&lt;/p&gt;
&lt;p&gt;Japanese kids are really creative so it was a really fun time.
But not only was the event fun, the technology side was really fun too.&lt;/p&gt;
&lt;h2&gt;Some of the technology used&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SVG&lt;/strong&gt;—heaps of SVG. The hand-drawn paths, UI widgets, all of the
animation, all of it is SVG. In particular we used a lot of &lt;a href=&quot;https://developer.mozilla.org/en/SVG/SVG_animation_with_SMIL&quot;&gt;SVG
Animation&lt;/a&gt; and
even &lt;a href=&quot;https://developer.mozilla.org/docs/Web/SVG/Applying_SVG_effects_to_HTML_content&quot;&gt;SVG applied to
HTML&lt;/a&gt;
to provide the glowing effect on the form text (as per the designer’s
prototype—not my idea!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fennec&lt;/strong&gt; (Firefox for Mobile)–Just a regular release build (version 9),
plus &lt;a href=&quot;https://web.archive.org/web/20121122093411/https://addons.mozilla.org/ja/mobile/addon/full-screen-252573/&quot;&gt;Matt Brubeck’s Full Screen
add-on&lt;/a&gt; and
a few config tweaks.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en/DOM/Touch_events&quot;&gt;Touch events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/en/CSS/calc&quot;&gt;CSS calc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_transitions/Using_CSS_transitions&quot;&gt;CSS transitions&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What went well&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;SVG’s native motion on a path (&lt;code&gt;&amp;#x3C;animateMotion&gt;&lt;/code&gt;) saved us so much time.
The auto-rotate feature (&lt;code&gt;rotate=&quot;auto&quot;&lt;/code&gt;), path APIs (&lt;code&gt;getPointAtLength&lt;/code&gt;), and
ability to calibrate the path length (&lt;code&gt;pathLength=&quot;1&quot;&lt;/code&gt;) also made it easy to
position animations at just the right place so they would appear on the screen
as soon as the user pressed “send”.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Using SVG made it really easy to do the drop shadows.
Just a transform and a blur filter and we were done.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/drop-shadow.jpg&quot; alt=&quot;Character with SVG drop shadow&quot; title=&quot;Character with SVG drop shadow&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SVG animation was surprisingly fast. I expected it to be really slow but it
was the fastest of the alternatives we tried. That said there’s still a lot
more work to be done (see below).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overall SVG just proved really versatile. Being able to show a faint greyed
outline of previous frames just by setting an attribute was great. Likewise
being able to do all the animation work on the client-side and then just
serialise the subtree and send it to the server was so much simpler than the
previous version.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deployment over the Web was great. Just refresh the page to pick up the bug
fixes! Likewise when we ran out of tablets at one point we could just load up
the editor URL on a laptop and keep drawing.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What didn’t go so well&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The app marketplace.&lt;/strong&gt; We badly wanted to package it all up as a Web app
using the framework developed by the Mozilla Labs
Apps project.
We hoped that would give us full-screen display and stop the user from
accidentally navigating to other pages.
We had high hopes but were shattered to find the Android runtime launched the
app in a Webkit runtime which didn’t even support SVG.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Going full-screen.&lt;/strong&gt; Due to some technical reasons we were stuck with an old
version of Fennec and old UI which took some coaxing to go full-screen and
stop the chrome from flying in when the user was drawing. Fortunately the bugs
that stopped us from using a more recent version of Fennec appear to have been
fixed so next time we can hopefully use &lt;a href=&quot;https://developer.mozilla.org/DOM/Using_full-screen_mode&quot;&gt;the Fullscreen
API&lt;/a&gt; and
&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=603006&quot;&gt;multi-touch&lt;/a&gt; for drawing
with all your fingers at once (something the really young kids really wanted
to do!)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CSS and UI layout.&lt;/strong&gt; Countless hours were sunk into trying to convince CSS to
layout widgets on the screen. In the end I gave up and did half of it in
script. I’m told &lt;a href=&quot;https://www.w3.org/TR/css3-flexbox/&quot;&gt;CSS flexbox&lt;/a&gt; can help
a lot here but I spoke to one implementer of flexbox who said that some of the
things we were trying to do weren’t possible even with flexbox.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Graphics performance.&lt;/strong&gt; For the combined animation we badly need a boost to
our SVG rendering performance. On Windows the performance was generally ok (if
you don’t have a loud fan!) but occasionally got jittery. On Mac it looked
terrible. We still have a way to go here. Apart from the graphics performance
there’s still lots of room to optimize SVG animation itself too. For the
editor running on the tablets, I have &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=629200&quot;&gt;one patch awaiting
review&lt;/a&gt; which I hope will
make using SVG’s path APIs faster and speed up the drawing and erasing
operations.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The result&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/wall.jpg&quot; alt=&quot;The wall gallery&quot; title=&quot;The wall gallery&quot;&gt;&lt;/p&gt;
The gallery of animations


&lt;p&gt;&lt;img src=&quot;https://birtles.blog/2012/01/27/parapara-animation/editor.jpg&quot; alt=&quot;Animation editor&quot; title=&quot;Animation editor&quot;&gt;&lt;/p&gt;
The editor

&lt;p&gt;And, of course, &lt;a href=&quot;https://github.com/mozilla/parapara&quot;&gt;the code is waiting for your help at
github&lt;/a&gt;!&lt;/p&gt;
&lt;h2&gt;Feedback&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;“That’s a web page?!?”&lt;/strong&gt; I’m certain that most people who used the demo were
oblivious to the fact they were using the Web and that’s probably the greatest
success of this demo. Without exception, everyone who asked about the technology
was surprised it was Web-based. Everyone assumed it was a native Android app or
otherwise Flash.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“That’s SVG?!?”&lt;/strong&gt; The web developers who came were also surprised at the use
of SVG. Most had never really thought of making use of it. They assumed we were
using canvas.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;“I want to cry, this is the first time I’ve seen Fennec used for something
other than reading the news”&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Although a lot of the features we used are still in development it was very
rewarding to see how much is already possible with Open Web technologies. We’ve
had many requests to run this workshop elsewhere and, &lt;a href=&quot;https://github.com/mozilla/parapara&quot;&gt;with your
help&lt;/a&gt;, it will hopefully get better each
time. Thanks very much to the Parapara Animation team and to everyone who
contributed to Fennec, Gecko and the Web standards that this is built on.&lt;/p&gt;
&lt;p&gt;* For anyone wondering what “parapara” means, it’s the sound of flipping paper
and its use here comes from “parapara manga” which means “flipbook comic”. It’s
also the name of a kind of hand dancing so we might have to reconsider the name
so as not to disappoint the kids.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2012/01/27/parapara-animation/#comments</comments><category>Archive</category><category>Mozilla</category></item><item><title>It’s about time…</title><link>https://birtles.blog/2010/10/13/its-about-time/</link><guid isPermaLink="true">https://birtles.blog/2010/10/13/its-about-time/</guid><description>Firefox 4 is going four dimensional! Time dimensional! (Ok, for those who know
physics, just pretend 🙂)

There’s
CSS transitions
for all sorts of animated eye-candy, major JS speed-ups to give scripted
animations a boost and
mozRequestAnimationFrame
to get keep them smooth and in sync, and a whole host of other graphics and
video improvements.
Oh, and SMIL in SVG!
</description><pubDate>Wed, 13 Oct 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Firefox 4 is going four dimensional! Time dimensional! (Ok, for those who know
physics, just pretend 🙂)&lt;/p&gt;
&lt;p&gt;There’s
&lt;a href=&quot;https://developer.mozilla.org/docs/Web/CSS/CSS_transitions/Using_CSS_transitions&quot;&gt;CSS transitions&lt;/a&gt;
for all sorts of animated eye-candy, major JS speed-ups to give scripted
animations a boost and
&lt;a href=&quot;https://hacks.mozilla.org/2010/08/more-efficient-javascript-animations-with-mozrequestanimationframe/&quot;&gt;&lt;code&gt;mozRequestAnimationFrame&lt;/code&gt;&lt;/a&gt;
to get keep them smooth and in sync, and a whole host of other graphics and
video improvements.
Oh, and &lt;strong&gt;SMIL in SVG&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Speaking of which, I thought I’d bring you up to speed on some of the recent
progress on the SMIL front.&lt;/p&gt;
&lt;h2&gt;Event timing&lt;/h2&gt;
&lt;p&gt;One of the more recent additions to our implementation is the ability to key
animations off DOM events such as mouse clicks and key presses.&lt;/p&gt;
&lt;p&gt;This paves the way to creating widgets of questionable aesthetic value:&lt;/p&gt;



&lt;p&gt;You’ll need to be running a recent nightly to experience this button is all its
tacky glory. With the latest Firefox 4 beta the motion will be jerky due to &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=557885&quot;&gt;bug
557885&lt;/a&gt;.)&lt;/p&gt;


&lt;p&gt;However, SMIL animations need not only be keyed off SVG events but any event in
the current document is fair game. So, for example, suppose we want to add
a tape animation that runs whenever a certain video is in play, we can do it
with this piece of SMIL:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-svg&quot;&gt;&amp;#x3C;animate attributeName=&quot;stroke-dashoffset&quot; from=&quot;0&quot; to=&quot;90&quot;
  dur=&quot;1s&quot; repeatCount=&quot;indefinite&quot; fill=&quot;freeze&quot;
  begin=&quot;video.playing&quot; end=&quot;video.pause; video.ended&quot;/&gt;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;Demo of video with SMIL-animated icon synchronised with the video playback state&lt;/p&gt;


&lt;p&gt;In addition to events, you can also key animations off:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;key presses: &lt;code&gt;&amp;#x3C;animate begin=&quot;accessKey(a)+1s&quot;…&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;other animations: &lt;code&gt;&amp;#x3C;animate begin=&quot;otherAnimation.begin-2.5s&quot;…&lt;/code&gt; (and this is
generally a much better choice than event timing when you want to keep
animations in sync. Although you can write &lt;code&gt;begin=&quot;otherAnimation.beginEvent&quot;&lt;/code&gt;
you may get surprising results when a seek is performed. Use
&lt;code&gt;begin=&quot;otherAnimation.begin&quot;&lt;/code&gt; instead.)&lt;/li&gt;
&lt;li&gt;repeat iterations: &lt;code&gt;&amp;#x3C;animate begin=&quot;otherAnimation.repeat(2)+25ms&quot;…&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;plain old time offsets: &lt;code&gt;&amp;#x3C;animate begin=&quot;12.3h&quot;…&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;all of the above! &lt;code&gt;&amp;#x3C;animate begin=&quot;rect.click; accessKey(a)+1s; otherAnimation.begin-2.5s; otherAnimation.repeat(2)+25ms; 12.3s&quot;…&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;SMIL and script are friends&lt;/h2&gt;
&lt;p&gt;There are a lot of advantages to using SMIL over script (it’s generally easier
for a start!) but sometimes it can’t do everything you need. In those cases you
can use both together!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SMIL → Script:&lt;/strong&gt; To synchronise script with SMIL, just listen for the relevant
&lt;a href=&quot;http://www.w3.org/TR/SVG/animate.html#InterfaceTimeEvent&quot;&gt;time events&lt;/a&gt;
generated when animations start (&lt;code&gt;beginEvent&lt;/code&gt;), repeat (&lt;code&gt;repeatEvent&lt;/code&gt;), and stop
(&lt;code&gt;endEvent&lt;/code&gt;). If you need a bit more context you can always query &lt;a href=&quot;http://www.w3.org/TR/SVG/animate.html#InterfaceSVGAnimationElement&quot;&gt;the animation’s
start time and current
time&lt;/a&gt; too.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Script → SMIL:&lt;/strong&gt; To go the other direction, that is, to kick-start SMIL from
script, just use the appropriate &lt;a href=&quot;http://www.w3.org/TR/SVG/animate.html#InterfaceElementTimeControl&quot;&gt;time control
interfaces&lt;/a&gt;
&lt;code&gt;beginElement&lt;/code&gt;, &lt;code&gt;endElement&lt;/code&gt; on the target animation, or seek and pause all
animations in the &lt;code&gt;&amp;#x3C;svg&gt;&lt;/code&gt; block as a whole with &lt;a href=&quot;http://www.w3.org/TR/SVG/struct.html#InterfaceSVGSVGElement&quot;&gt;&lt;code&gt;setCurrentTime&lt;/code&gt;,
&lt;code&gt;pauseAnimations&lt;/code&gt; and
friends&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;SMIL outside the box&lt;/h2&gt;
&lt;p&gt;While we’re only supporting SMIL for SVG content that doesn’t mean it’s entirely
off limits to your HTML content. Not only can we tie SMIL to HTML events as
above but we can also &lt;a href=&quot;https://developer.mozilla.org/docs/Web/SVG/Applying_SVG_effects_to_HTML_content&quot;&gt;apply various SVG features to
HTML&lt;/a&gt;,
and these places can play host to a bit of declarative animation too.&lt;/p&gt;



&lt;p&gt;Woah woah woah! Example of a SMIL-animated SVG filter applied to HTML content.
(Hint: try selecting the text)&lt;/p&gt;


&lt;h2&gt;What’s left?&lt;/h2&gt;
&lt;p&gt;Still, there are a few features missing in our SMIL implementation that are yet
to come. I’m maintaining &lt;a href=&quot;https://birtles.blog/smil/status/&quot;&gt;a somewhat detailed
summary&lt;/a&gt;, but in short we’re missing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Mexican waves&lt;/strong&gt; — There are still a few SVG data types that can’t be
animated yet. Paths are very much on the way, but lists of points are yet to
come. That means all your squiggling, warping, barrelling, twisting, waving
lines and stars will have to wait a little longer to mesmerise the world.
Hopefully most of this will be done in time for Firefox 4.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hyperlinking&lt;/strong&gt; — The ability to &lt;a href=&quot;https://www.w3.org/TR/smil-animation/#HyperlinkSemantics&quot;&gt;trigger animations from
a hyperlink&lt;/a&gt; is also
yet to come but will probably not make it’s debut until after Firefox 4.0.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What’s not on the radar?&lt;/h2&gt;
&lt;p&gt;There are also a couple of features that are neither done, nor likely to get
done in the foreseeable future. These are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;#x3C;animateColor&gt;&lt;/code&gt; — So long as &lt;code&gt;&amp;#x3C;animate&gt;&lt;/code&gt; honours &lt;code&gt;color-interpolation&lt;/code&gt; then
&lt;code&gt;&amp;#x3C;animateColor&gt;&lt;/code&gt; isn’t necessary and only complicates the Web. &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=436296&quot;&gt;See bug
436296&lt;/a&gt;.
We recommend using &lt;code&gt;&amp;#x3C;animate&gt;&lt;/code&gt; instead.
(This issue was &lt;a href=&quot;https://lists.w3.org/Archives/Public/www-svg/2010Oct/0069.html&quot;&gt;recently discussed on
www-svg&lt;/a&gt;.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wallclock timing&lt;/strong&gt; — That is, the ability to set up an animation to begin at
&lt;code&gt;2011-01-01T00:00:00+09:00&lt;/code&gt;.
Real uses cases for wallclock timing &lt;a href=&quot;https://lists.w3.org/Archives/Public/www-smil/2010AprJun/0006.html&quot;&gt;were discussed on www-smil earlier in
the year&lt;/a&gt;
but it seems the syntax provided by SMIL, at least as far as it is used in
SVG, is insufficient for these use cases. For the time being, we’d rather not
clutter the Web platform by implementing something half-baked. For most use
cases, it should be possible to provide this sort of functionality by adding
a sprinkling of script to your SMIL.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; I just noticed Robert Longson (who’s played a big part in us getting to
this point) beat me to reporting much of this news, so for more details on where
we’re up to &lt;a href=&quot;https://longsonr.wordpress.com/2010/10/12/svg-news&quot;&gt;see his post
too&lt;/a&gt;.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2010/10/13/its-about-time/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Synchronising SMIL</title><link>https://birtles.blog/2010/01/13/synchronising-smil/</link><guid isPermaLink="true">https://birtles.blog/2010/01/13/synchronising-smil/</guid><description>Our SMIL implementation passed another little milestone yesterday when we landed
syncbase timing. We’ve still got a long way to go but this was always going to
be the hardest feature for the timing model.
</description><pubDate>Wed, 13 Jan 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Our SMIL implementation passed another little milestone yesterday when we landed
syncbase timing. We’ve still got a long way to go but this was always going to
be the hardest feature for the timing model.&lt;/p&gt;

&lt;p&gt;I thought I’d just take this chance to acknowledge some of the people who’ve
helped get us here. Particularly Daniel Holbert for his incredible helpfulness
and for just being awesome at everything he does; Jonathan Watt for all his help
with SMIL recently and for always looking out for me; Robert O’Callahan for his
oversight, invaluable input, and support technical and personal; and Chris
Double for keeping SMIL moving in the early days.&lt;/p&gt;
&lt;p&gt;Also, as alumni of the &lt;a href=&quot;https://www.uts.edu.au/&quot;&gt;University of Technology, Sydney
(UTS)&lt;/a&gt; I used &lt;a href=&quot;https://www.lib.uts.edu.au/&quot;&gt;their
library&lt;/a&gt; a number of times last year as a kind of
virtual office. It’s a great library where they really try to help the students,
allow you to eat at your desk, and even let you &lt;a href=&quot;https://twitter.com/utslibrary/status/933169504728662018&quot;&gt;pay for your fines with canned
food&lt;/a&gt; that is then given to an
Australian charity group. Thanks UTS!&lt;/p&gt;
&lt;p&gt;Finally, thanks to &lt;a href=&quot;https://sol1.com.au/&quot;&gt;Solutions First&lt;/a&gt;,
specialists in Open Source and Linux solutions and a whole lot more, and who
have generously provided me with this web space for longer than I can remember.
Cheers guys!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2010/01/13/synchronising-smil/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Beached as bro</title><link>https://birtles.blog/2009/01/22/beached-as-bro/</link><guid isPermaLink="true">https://birtles.blog/2009/01/22/beached-as-bro/</guid><description>One last post as I race out the door. It appears my attempt to quash the
enthusiasm surrounding SMIL doesn’t seem to have
worked.
It seems like some people are genuinely interested in SMIL and not just for
Acid3!
</description><pubDate>Thu, 22 Jan 2009 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One last post as I race out the door. It appears my attempt to quash the
enthusiasm surrounding SMIL &lt;a href=&quot;https://arstechnica.com/information-technology/2009/01/smil-animation-and-3d-canvas-library-for-firefox/&quot;&gt;doesn’t seem to have
worked&lt;/a&gt;.
It seems like some people are genuinely interested in SMIL and not just for
Acid3!&lt;/p&gt;

&lt;p&gt;This weeks developments:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=468996&quot;&gt;&lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=473702&quot;&gt;SVGAnimationElement interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=474357&quot;&gt;Fixes to better synchronise the DOM state with the animation state&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A couple of other &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=474257&quot;&gt;small&lt;/a&gt; &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=474740&quot;&gt;fixes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Today I ran up against some questions about
&lt;a href=&quot;https://lists.w3.org/Archives/Public/www-smil/2009JanMar/0001.html&quot;&gt;zero-length&lt;/a&gt;
&lt;a href=&quot;https://lists.w3.org/Archives/Public/www-smil/2009JanMar/0002.html&quot;&gt;intervals&lt;/a&gt;
so if you have any insights there I’d be glad to hear from you! I’ve &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=474739&quot;&gt;adjusted
our timing model&lt;/a&gt; based on
what I think SMIL intends.&lt;/p&gt;
&lt;p&gt;That brings to an end my stint with the NZ office. I had a &lt;a href=&quot;https://robert.ocallahan.org/2009/01/mountain-fun_14.html&quot;&gt;great
time&lt;/a&gt;
with the fellas here—cheers guys! Or as some people here say, “chur!”&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2009/01/22/beached-as-bro/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Wet blanket</title><link>https://birtles.blog/2009/01/17/wet-blanket/</link><guid isPermaLink="true">https://birtles.blog/2009/01/17/wet-blanket/</guid><description>Well, SMIL has finally landed on mozilla-central!
It’s been a long road since I first started out on this project nearly 5 years
ago but we’ve finally reached the first milestone!
Thank you very much to many who have helped or even just offered encouraging
comments but thank you particularly to Daniel Holbert, Robert O’Callahan, Chris
Double, and Tim Rowley for their massive contributions.
It’s been a team job all the way.
</description><pubDate>Sat, 17 Jan 2009 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Well, SMIL has finally landed on mozilla-central!
It’s been a long road since I first started out on this project nearly 5 years
ago but we’ve finally reached the first milestone!
Thank you very much to many who have helped or even just offered encouraging
comments but thank you particularly to Daniel Holbert, Robert O’Callahan, Chris
Double, and Tim Rowley for their massive contributions.
It’s been a team job all the way.&lt;/p&gt;

&lt;p&gt;But althought we’ve come a long way I want to emphasise that we still have
a long way to go.
I’ve updated &lt;a href=&quot;https://birtles.blog/smil/status/&quot;&gt;the status page&lt;/a&gt;
to give you an idea of the features still remaining to be implemented.
In particular, integration with SVG and CSS is a massive task (although it makes
up only two rows of the chart) and by far the bulk of animation demos and tests
won’t work without this.
Also, syncbase timing is a big job.&lt;/p&gt;
&lt;p&gt;The good news is &lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt; is in the pipeline (ready for review any
day now) and for maybe the first time ever, there’s a little bit of momentum
behind SMIL.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2009/01/17/wet-blanket/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>ただ今！</title><link>https://birtles.blog/2009/01/01/tadaima/</link><guid isPermaLink="true">https://birtles.blog/2009/01/01/tadaima/</guid><description>Yay, back to SMIL! This is just a brief update to let you know about the state
of SMIL in Mozilla!

Here’s the low-context summary:
</description><pubDate>Thu, 01 Jan 2009 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Yay, back to SMIL! This is just a brief update to let you know about the state
of SMIL in Mozilla!&lt;/p&gt;
&lt;p&gt;Here’s the low-context summary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Daniel Holbert has been taking on this work and pushing it along steadily
(thanks a million Daniel!!)&lt;/li&gt;
&lt;li&gt;I’ve joined the Auckland office for my summer break (from December to the end
of January) to work full-time on SMIL.&lt;/li&gt;
&lt;li&gt;A (very) &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=216462&quot;&gt;basic patch&lt;/a&gt; is
nearly ready to land after it undergoes some final review and rework.
After that SMIL should be on the trunk but disabled by default.
I’ve updated the &lt;a href=&quot;https://birtles.blog/smil/status/&quot;&gt;status page&lt;/a&gt; to reflect the features of this
patch.&lt;/li&gt;
&lt;li&gt;A &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=468996&quot;&gt;proper implementation of
&lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt;&lt;/a&gt; is
also ready but needs review.
I’ve written up (in painfully boring detail) &lt;a href=&quot;https://birtles.blog/animatetransform-issues/&quot;&gt;some spec issues I encountered regarding
&lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next on the agenda I hope to be working on syncbase timing.&lt;/p&gt;
&lt;p&gt;Thanks again for all your support and Happy New Year! Godt nytår!
あけましておめでとうございます！ 新年もよろしくお願いいたします！&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2009/01/01/tadaima/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Farvel</title><link>https://birtles.blog/2007/04/05/farvel/</link><guid isPermaLink="true">https://birtles.blog/2007/04/05/farvel/</guid><description>You’ve probably worked it out, but I’m no longer working on SMIL at the moment.
tor has very kindly helped out and has
been doing some work on this but it will not make it for Firefox 3.

From now on, if you want to track the progress of SMIL in Mozilla I recommend:

\#216462 Implement SVG (SMIL) Animation

tor’s weblog
</description><pubDate>Thu, 05 Apr 2007 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You’ve probably worked it out, but I’m no longer working on SMIL at the moment.
&lt;a href=&quot;https://web.archive.org/web/20111104063822/http://weblogs.mozillazine.org/tor/&quot;&gt;tor&lt;/a&gt; has very kindly helped out and has
been doing some work on this but it will not make it for Firefox 3.&lt;/p&gt;
&lt;p&gt;From now on, if you want to track the progress of SMIL in Mozilla I recommend:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=216462&quot;&gt;#216462 Implement SVG (SMIL) Animation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://web.archive.org/web/20111104063822/http://weblogs.mozillazine.org/tor/&quot;&gt;tor’s weblog&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As for me, I’m travelling around Asia, so unless someone can sponsor me to work
on this in Asia I can’t really offer much time to the project.&lt;/p&gt;
&lt;p&gt;Thank you to everyone who helped me to get SMIL this far. I hope that someone
else can pick it up.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2007/04/05/farvel/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>SMIL</title><link>https://birtles.blog/2006/07/25/smil/</link><guid isPermaLink="true">https://birtles.blog/2006/07/25/smil/</guid><description>Wow, what a heading! Some would call it lack of imagination, I like to think of
it as artistic restraint — it’s just too easy to make puns with “SMILe”!

Progress on SMIL continues, albeit in slow motion. Just a really quick note for
those one or two people who want to know what’s going on:
</description><pubDate>Tue, 25 Jul 2006 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Wow, what a heading! Some would call it lack of imagination, I like to think of
it as &lt;em&gt;artistic restraint&lt;/em&gt; — it’s just too easy to make puns with “SMILe”!&lt;/p&gt;
&lt;p&gt;Progress on SMIL continues, albeit in slow motion. Just a really quick note for
those one or two people who want to know what’s going on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not only does it compile it now runs too!&lt;/li&gt;
&lt;li&gt;All my visual tests pass again&lt;/li&gt;
&lt;li&gt;All my unit tests pass again&lt;/li&gt;
&lt;li&gt;My early attempt at &lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt; is up and running again and seems to
work.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I need to do some tidying up before it’s ready for review. Most of all:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Some deCOMtamination&lt;/li&gt;
&lt;li&gt;Making better use of Moz utilities (string iterators, &lt;code&gt;nsTArray&lt;/code&gt; etc.)&lt;/li&gt;
&lt;li&gt;Removing redundant code&lt;/li&gt;
&lt;li&gt;Fixing the scope of the animation controller&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s hard to give a timeframe for this — it depends a bit on my workload with
other things (Japanese, Bible college, surfing, life – not to mention my day
job). Hopefully a month?&lt;/p&gt;
&lt;p&gt;As for new feature work, I’ll have to re-negotiate with work before I can do
that. So I’d really appreciate any help at all. The SVG guys have already been
incredibly helpful and have begun preparing the SVG code so it can be animated
more efficiently. Thanks guys!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2006/07/25/smil/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>SMIL compiles again</title><link>https://birtles.blog/2006/06/12/smil-compiles-again/</link><guid isPermaLink="true">https://birtles.blog/2006/06/12/smil-compiles-again/</guid><description>Today is the Queen’s birthday public holiday in Australia. In Sydney the weather
is freezing and the surf is huge. All this means I’ve finally got my SMIL work
to compile against the trunk again. Now to get it working again!
</description><pubDate>Mon, 12 Jun 2006 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Today is the Queen’s birthday public holiday in Australia. In Sydney the weather
is freezing and the surf is huge. All this means I’ve finally got my SMIL work
to compile against the trunk again. Now to get it working again!&lt;/p&gt;

&lt;p&gt;Thanks to the many people who have left very encouraging comments in the
meantime. I’ll do my best to get this up and running as soon as possible. One
very experienced developer has suggested they might be able to contribute which
would really help bring this to reality.&lt;/p&gt;
&lt;p&gt;I’ll wait until it’s actually working (and I’ve done some more deCOMtamination)
before posting another patch. But thanks for being patient with me!&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2006/06/12/smil-compiles-again/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>SMIL Animation in Mozilla report</title><link>https://birtles.blog/2006/01/09/smil-animation-in-mozilla-report/</link><guid isPermaLink="true">https://birtles.blog/2006/01/09/smil-animation-in-mozilla-report/</guid><description>I’ve published the report I wrote
for regarding my project implementing SMIL Animation in Mozilla.
At 147 pages and ~700kb it’s fairly detailed but I hope it will be of interest
to some. Thanks to all who helped.
Here it is:

https://birtles.blog/smil/report/report.pdf
</description><pubDate>Mon, 09 Jan 2006 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve &lt;a href=&quot;https://birtles.blog/smil/report/report.pdf&quot;&gt;published&lt;/a&gt; the report I wrote
for regarding my project implementing SMIL Animation in Mozilla.
At 147 pages and ~700kb it’s fairly detailed but I hope it will be of interest
to some. Thanks to all who helped.
Here it is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/smil/report/report.pdf&quot;&gt;https://birtles.blog/smil/report/report.pdf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, I was invited to represent the Software Engineering faculty by presenting
my project at an Engineering project competition run by &lt;a href=&quot;https://www.uts.edu.au/&quot;&gt;my
university&lt;/a&gt; from which I picked up the prize for
innovation which means I got paid for working on Mozilla! Stoked!&lt;/p&gt;
&lt;p&gt;Finally, I’m taking a bit of a break from this work at the moment.
I nearly went crazy finishing the uni project last year and right now it’s
summer so I’m getting back into surfing, swimming, running, riding, squash and
maybe even some karate!
Maybe in a month or two I’ll be ready to look at the code again and I’ll try to
tidy up the SMIL Animation code.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2006/01/09/smil-animation-in-mozilla-report/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>SMIL Animation patch</title><link>https://birtles.blog/2005/11/05/smil-animation-patch/</link><guid isPermaLink="true">https://birtles.blog/2005/11/05/smil-animation-patch/</guid><description>G’day!
I’ve produced a new patch to provide SMIL Animation for SVG.
Since last time I’ve added:

keySplines

keyTimes

accumulate

restart

min, max

ElementTimeControl DOM interface
</description><pubDate>Sat, 05 Nov 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;G’day!
I’ve produced a new patch to provide SMIL Animation for SVG.
Since last time I’ve added:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;keySplines&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keyTimes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;accumulate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;restart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min&lt;/code&gt;, &lt;code&gt;max&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ElementTimeControl&lt;/code&gt; DOM interface&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve added a &lt;a href=&quot;https://birtles.blog/smil/status/&quot;&gt;status page&lt;/a&gt; showing just
what’s been implemented and I’ve also updated the &lt;a href=&quot;https://birtles.blog/smil/tests/&quot;&gt;test
cases&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This represents all the features I intend to implement this year although I may
attempt a draft implementation of &lt;code&gt;&amp;#x3C;animateTransform&gt;&lt;/code&gt; for demonstration
purposes.
The next obvious thing to implement is syncbase timing although none of this
will be of much use until we determine how to represent animated values in SVG
and CSS!&lt;/p&gt;
&lt;p&gt;For now I’ll be working on a report of my attempts and documenting some
difficulties I’ve come across with SMIL.&lt;/p&gt;
&lt;p&gt;Here are the patches:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-11-03-2024.patch&quot;&gt;smil-anim-2005-11-03-2024.patch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-11-03-2024-wo-configure.patch&quot;&gt;smil-anim-2005-11-03-2024-wo-configure.patch&lt;/a&gt;
– The same but without the patch to configure—this is much smaller and more
likely to work but requires you have &lt;code&gt;autoconf-2.13&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I’ve (hopefully) fixed the paths in the patch so you should be able to apply it
from &lt;code&gt;mozilla&lt;/code&gt; with:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ patch -p0 smil-anim-2005-11-05-1539.patch
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Known issues:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An SVG image referenced via &lt;code&gt;&amp;#x3C;object&gt;&lt;/code&gt; will remain paused when returning to
the page using the back button if the page is in the bfcache. This is because
page transition events are not received. If anyone can help me with this I’d
really appreciate it!&lt;/li&gt;
&lt;li&gt;An SVG document added entirely via script won’t be animated.
(See &lt;a href=&quot;https://birtles.blog/smil/tests/deferred-tree.html&quot;&gt;this test case&lt;/a&gt;.)&lt;/li&gt;
&lt;/ul&gt;</content:encoded><comments>https://birtles.blog/2005/11/05/smil-animation-patch/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>SMIL work: performance and integration</title><link>https://birtles.blog/2005/10/16/smil-work-performance-and-integration/</link><guid isPermaLink="true">https://birtles.blog/2005/10/16/smil-work-performance-and-integration/</guid><description>Here’s an updated patch
with my latest changes including:

Optimised performance—a lot of unnecessary rendering has been filtered out
and the profiling I was able to perform suggests this has made a significant
difference, especially when the animation is frozen.

Animation now pauses and resets when the page is cached in the bfcache.

Better thread safety.
</description><pubDate>Sun, 16 Oct 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Here’s an &lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-10-16-1736.patch&quot;&gt;updated patch&lt;/a&gt;
with my latest changes including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Optimised performance—a lot of unnecessary rendering has been filtered out
and the profiling I was able to perform suggests this has made a significant
difference, especially when the animation is frozen.&lt;/li&gt;
&lt;li&gt;Animation now pauses and resets when the page is cached in the bfcache.&lt;/li&gt;
&lt;li&gt;Better thread safety.&lt;/li&gt;
&lt;li&gt;Animation now starts at the same time as the SVGLoad event (although this has
meant a regression in the &lt;a href=&quot;https://birtles.blog/smil/tests/deferred-tree.html&quot;&gt;deferred tree&lt;/a&gt; test
case).&lt;/li&gt;
&lt;li&gt;Support for pausing via the DOM (see &lt;a href=&quot;https://birtles.blog/smil/tests/pause-controls.html&quot;&gt;this test
case&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Animation is now disabled if the &lt;code&gt;image.animation_mode&lt;/code&gt; pref is set to ‘none’
(although I’m not sure if this is a good idea).&lt;/li&gt;
&lt;li&gt;Fixed the to-animation prioritisation issue &lt;a href=&quot;https://birtles.blog/2005/10/04/fill-modes-nearly-there/#comment-7&quot;&gt;Olaf pointed
out&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The &lt;a href=&quot;https://birtles.blog/smil/tests/frozen-to-animation.html&quot;&gt;frozen to animation&lt;/a&gt; test case now
produces the correct result in all cases (although there are still unresolved
issues with regard to seeking).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The latest patch is at:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-10-16-1736.patch&quot;&gt;smil-anim-2005-10-16-1736.patch&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’ve also put up &lt;a href=&quot;https://birtles.blog/smil/patches/configure&quot;&gt;my configure script&lt;/a&gt;
as some people have had trouble regenerating the script from &lt;code&gt;configure.in&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;You might like to read &lt;a href=&quot;https://birtles.blog/2005/10/04/fill-modes-nearly-there/#comment-5&quot;&gt;Twitwi’s
comment&lt;/a&gt; for some help on
applying the patch.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/10/16/smil-work-performance-and-integration/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Fill modes (nearly) there</title><link>https://birtles.blog/2005/10/04/fill-modes-nearly-there/</link><guid isPermaLink="true">https://birtles.blog/2005/10/04/fill-modes-nearly-there/</guid><description>Aided by flat surf but hampered by perfect weather
I’ve spent most of the last week tidying up my code and updating the
documentation on the
wiki.
The latest patch
is hopefully much better, or at least not quite as hideous as it was in some
parts.
</description><pubDate>Tue, 04 Oct 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Aided by &lt;a href=&quot;https://www.realsurf.com/&quot;&gt;flat surf&lt;/a&gt; but hampered by perfect weather
I’ve spent most of the last week tidying up my code and updating the
documentation on &lt;a href=&quot;https://web.archive.org/web/20060820172201/http://wiki.mozilla.org/SVGDev:SMIL_Model&quot;&gt;the
wiki&lt;/a&gt;.
The &lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-10-04-2138.patch&quot;&gt;latest patch&lt;/a&gt;
is hopefully much better, or at least not quite as hideous as it was in some
parts.&lt;/p&gt;
&lt;p&gt;Fill modes are now implemented except for one edge case of a frozen to animation
that is stopped in the middle of the simple duration.
It’s the third case in &lt;a href=&quot;https://birtles.blog/smil/tests/frozen-to-animation.html&quot;&gt;this test&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m putting feature work on hold for a while to focus on a few obvious
optimisations such as suspending the timer when it’s not needed.&lt;/p&gt;
&lt;p&gt;Here’s the latest patch:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-10-04-2138.patch&quot;&gt;smil-anim-2005-10-04-2138.patch&lt;/a&gt;&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/10/04/fill-modes-nearly-there/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Additive animation</title><link>https://birtles.blog/2005/09/21/additive-animation/</link><guid isPermaLink="true">https://birtles.blog/2005/09/21/additive-animation/</guid><description>Additive animation appears to be working.
The test case I mentioned in the last
post works even the nasty tree re-ordering
cases.
I’ve also extended the additive test case
a little to test a bit more of the dynamic behaviour.
</description><pubDate>Wed, 21 Sep 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Additive animation appears to be working.
The &lt;a href=&quot;https://birtles.blog/smil/tests/frozen-to-animation.html&quot;&gt;test case I mentioned in the last
post&lt;/a&gt; works even the nasty tree re-ordering
cases.
I’ve also &lt;a href=&quot;https://birtles.blog/smil/tests/additive.html&quot;&gt;extended the additive test case&lt;/a&gt;
a little to test a bit more of the dynamic behaviour.&lt;/p&gt;
&lt;p&gt;In implementing this I’ve tightened up the implementation of the &lt;code&gt;&amp;#x3C;animate&gt;&lt;/code&gt;
element somewhat and wrapped each sample in a pair of calls to &lt;code&gt;suspendRedraw&lt;/code&gt;
and &lt;code&gt;unsuspendRedraw&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;I’m putting feature work on hold while I tidy up the code and update the
documentation on the
&lt;a href=&quot;https://web.archive.org/web/20070702103839/https://wiki.mozilla.org/SVGDev::Animation&quot;&gt;wiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The remaining features I hope to add this year are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;fill&lt;/code&gt; modes&lt;/li&gt;
&lt;li&gt;&lt;code&gt;restart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;accumulate&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keyTimes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keySplines&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I may have a chance to look at adding support for specifying target elements via
&lt;code&gt;xlink:href&lt;/code&gt; and perhaps CSS values and relative values but I’m not sure.
I’ll be focussing more on thread safety, performance, optimisations, DOM
interfaces etc.&lt;/p&gt;
&lt;p&gt;The latest patch:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-09-21-2129.patch&quot;&gt;smil-anim-2005-09-21-2129.patch&lt;/a&gt;&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/09/21/additive-animation/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Additive animation nearly done</title><link>https://birtles.blog/2005/09/14/additive-animation-nearly-done/</link><guid isPermaLink="true">https://birtles.blog/2005/09/14/additive-animation-nearly-done/</guid><description>I’ve done most of the work required for additive animation. The remaining part
is to correctly order animations in the animation sandwich after changes to the
document structure.
</description><pubDate>Wed, 14 Sep 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve done most of the work required for additive animation. The remaining part
is to correctly order animations in the animation sandwich after changes to the
document structure. So in
&lt;a href=&quot;https://birtles.blog/smil/tests/additive.html&quot;&gt;this test case&lt;/a&gt; the
last two squares don’t behave as they should.
(However, ASV fails in the same way.)&lt;/p&gt;
&lt;p&gt;Also, I’ve implemented from/to/by animation and animation using a list of values.&lt;/p&gt;
&lt;p&gt;I’ve done a lot of tidying up too but the nsSVG(Animated)Length situation is
still a nightmare.&lt;/p&gt;
&lt;p&gt;By the end of September I hope to have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;cumulative animation, and&lt;/li&gt;
&lt;li&gt;fill modes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and maybe:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;restart&lt;/code&gt;, and&lt;/li&gt;
&lt;li&gt;&lt;code&gt;min&lt;/code&gt; and &lt;code&gt;max&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that I’ll hopefully add &lt;code&gt;keyTimes&lt;/code&gt; and &lt;code&gt;keySplines&lt;/code&gt; and &lt;code&gt;calcMode&lt;/code&gt;
(at least for &lt;code&gt;spline&lt;/code&gt;, &lt;code&gt;linear&lt;/code&gt; and &lt;code&gt;discrete&lt;/code&gt;)
but mostly I’ll focus on integration, performance, testing etc.
Something should be ready by December.&lt;/p&gt;
&lt;p&gt;Here’s the patch for my latest changes:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-09-14-2043.patch&quot;&gt;smil-anim-2005-09-14-2043.patch&lt;/a&gt;
(about 230k).&lt;/p&gt;
&lt;p&gt;I haven’t included &lt;code&gt;configure&lt;/code&gt; in the diff so you’ll need to regenerate it from
&lt;code&gt;configure.in&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Under Cygwin the following works for me:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;$ autoconf-2.13 configure.in &gt; configure
&lt;/code&gt;&lt;/pre&gt;</content:encoded><comments>https://birtles.blog/2005/09/14/additive-animation-nearly-done/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Compositing underway</title><link>https://birtles.blog/2005/09/07/compositing-underway/</link><guid isPermaLink="true">https://birtles.blog/2005/09/07/compositing-underway/</guid><description>I’ve begun work on implementing compositing. This will take some time. Also I’m
no longer sure I’ll be able to deliver syncbase timing this year as instead
I may need to focus on integration issues, performance, documentation,
thread-safety and so on. Hopefully all this will mean it has a better chance of
getting checked in sooner though.
</description><pubDate>Wed, 07 Sep 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve begun work on implementing compositing. This will take some time. Also I’m
no longer sure I’ll be able to deliver syncbase timing this year as instead
I may need to focus on integration issues, performance, documentation,
thread-safety and so on. Hopefully all this will mean it has a better chance of
getting checked in sooner though.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/09/07/compositing-underway/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Repeating</title><link>https://birtles.blog/2005/09/04/repeating/</link><guid isPermaLink="true">https://birtles.blog/2005/09/04/repeating/</guid><description>I’ve added a basic implementation of repeating. This doesn’t include
accumulating or repeat-based timing but this test
and a whole lot of other tests seem to work.
Also, I’ve added a couple more tests.
</description><pubDate>Sun, 04 Sep 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve added a basic implementation of repeating. This doesn’t include
accumulating or repeat-based timing but &lt;a href=&quot;https://birtles.blog/smil/tests/repeating.html&quot;&gt;this test&lt;/a&gt;
and a whole lot of other tests seem to work.
Also, I’ve added a couple more &lt;a href=&quot;https://birtles.blog/smil/tests/&quot;&gt;tests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve made up a &lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-09-04-1725.patch&quot;&gt;patch&lt;/a&gt; of
these latest changes and managed to remove the dependency on the changes in the
wings for &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=301628&quot;&gt;bug 301628&lt;/a&gt; so
the patch is a little smaller than last time but still 400k.
Most of that is just changes to &lt;code&gt;configure&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here’s the patch again:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-09-04-1725.patch&quot;&gt;smil-anim-2005-09-04-1725.patch&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The same instructions and caveats apply as last time except I haven’t tested
this patch on Linux like I did the last one.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/09/04/repeating/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Intervals</title><link>https://birtles.blog/2005/09/03/intervals/</link><guid isPermaLink="true">https://birtles.blog/2005/09/03/intervals/</guid><description>I’ve implemented handling for multiple begin and end values including
calculating the active duration, selecting the correct interval etc.
</description><pubDate>Sat, 03 Sep 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve implemented handling for multiple begin and end values including
calculating the active duration, selecting the correct interval etc.&lt;/p&gt;

&lt;p&gt;Interestingly Adobe SVG Viewer (6 beta) seems to do things a little differently
to what I’d expect based on the SMIL Animation spec. There are a few cases but
probably the most important one is when you specify a list of begin times and
a list of end times but the latest begin time is after the latest end time. The
pseudocode in the spec says this is an error—it’s ok if the end time is not
set as it will default to indefinite—but if it is set, then it needs to
provide a valid end value for the intervals defined by the begin attribute. The
pseudocode isn’t authoritative but I couldn’t find anywhere else where this is
spelled out in the spec.&lt;/p&gt;
&lt;p&gt;(Content authors can always work around this by adding &lt;code&gt;indefinite&lt;/code&gt; to their end
specifications, e.g. &lt;code&gt;end=&quot;...; indefinite&quot;&lt;/code&gt;.)&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/09/03/intervals/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>New patch</title><link>https://birtles.blog/2005/08/29/new-patch/</link><guid isPermaLink="true">https://birtles.blog/2005/08/29/new-patch/</guid><description>I thought I’d post this patch
which contains my work so far.

This patch contains most of the classes I outlined in my
design.
It will do very simple animation of lengths using a very limited subset of
timing specifiers.
</description><pubDate>Mon, 29 Aug 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I thought I’d post &lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-08-29-1947.patch&quot;&gt;this patch&lt;/a&gt;
which contains my work so far.&lt;/p&gt;
&lt;p&gt;This patch contains most of the classes I outlined in &lt;a href=&quot;https://web.archive.org/web/20080324202216/http://wiki.mozilla.org/SVGDev:Possible_SMIL_timing_and_animation_model&quot;&gt;my
design&lt;/a&gt;.
It will do very simple animation of lengths using a very limited subset of
timing specifiers. Please don’t look at the code in
&lt;code&gt;nsSVGLength&lt;/code&gt; and &lt;code&gt;nsSVGAnimatedLength&lt;/code&gt;.
It’s just a hack to get it to work while I wait to hear
from others how this should be done in the end.
Probably the implementation I included in the previous patch was better.&lt;/p&gt;
&lt;p&gt;I wouldn’t really recommend applying it because it also contain’s tor’s patch
for &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=301628&quot;&gt;bug 301628&lt;/a&gt; but along
the way I’ve had to merge it with recent &lt;code&gt;&amp;#x3C;textPath&gt;&lt;/code&gt; and events checkins and
I’ve possibly broken something along the way. So you’re better off just to leave
it until &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=301628&quot;&gt;bug 301628&lt;/a&gt; gets
checked-in and I re-create the patch.&lt;/p&gt;
&lt;p&gt;If you’re feeling brave however, you’ll probably want to apply it from
&lt;code&gt;/mozilla&lt;/code&gt; and run:
&lt;code&gt;patch -p 3 -u -N &amp;#x3C; smil-anim-2005-08-29-1947.patch&lt;/code&gt;
(I’ll fix the absolute paths someday so you don’t need &lt;code&gt;-p 3&lt;/code&gt;).
You’ll need to add &lt;code&gt;--enable-smil&lt;/code&gt; to your &lt;code&gt;.mozconfig&lt;/code&gt; and then do a full build.&lt;/p&gt;
&lt;p&gt;If you want to try just doing a minimal re-build, the following might work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mozilla&gt; ./configure&lt;/code&gt; (to re-create &lt;code&gt;autoconf.mk&lt;/code&gt;, although this will have
the effect of touching all the Makefiles meaning that when you run make libs
later on it will take a while. You might want to just try and patch up
&lt;code&gt;autoconf.mk&lt;/code&gt; yourself).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/dom/public&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt; (to export the headers and make the IDL definitions)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/content/smil/public&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt; (to export the headers required by
&lt;code&gt;nsPresContext.h&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/layout/base&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt; (to update &lt;code&gt;nsPresContext&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/dom/src/base&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/dom&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt; (not sure if this is necessary)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/content/smil&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/content/svg/content/src&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/layout/svg/base/src&gt;&lt;/code&gt; &lt;code&gt;make&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mozilla/layout&gt;&lt;/code&gt; &lt;code&gt;make libs&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like I said, you’re probably better off doing a full build, I’m really not sure
that the above approach will work.
I’ve tried the patch on Windows and Linux and it works for &lt;a href=&quot;https://birtles.blog/smil/tests/&quot;&gt;these test
cases&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here’s the patch again:
&lt;a href=&quot;https://birtles.blog/smil/patches/smil-anim-2005-08-29-1947.patch&quot;&gt;smil-anim-2005-08-29-1947.patch&lt;/a&gt;.
It’s about 500k.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/08/29/new-patch/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Iteration one</title><link>https://birtles.blog/2005/08/13/iteration-one/</link><guid isPermaLink="true">https://birtles.blog/2005/08/13/iteration-one/</guid><description>Just a quick update in case anyone someone actually reads this page. I’ve
implemented most of what I intended to cover in the first iteration and now some
very basic animations work.
</description><pubDate>Sat, 13 Aug 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Just a quick update in case anyone someone actually reads this page. I’ve
implemented most of what I intended to cover in the first iteration and now some
very basic animations work. If anyone is at all interested
I’ll post a patch, but otherwise I’ll leave it for a while.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/08/13/iteration-one/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Draft design</title><link>https://birtles.blog/2005/07/19/draft-design/</link><guid isPermaLink="true">https://birtles.blog/2005/07/19/draft-design/</guid><description>I’ve added a very draft
design
to the Mozilla wiki page.
</description><pubDate>Tue, 19 Jul 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve added a &lt;a href=&quot;https://web.archive.org/web/20080324202216/http://wiki.mozilla.org/SVGDev:Possible_SMIL_timing_and_animation_model&quot;&gt;very draft
design&lt;/a&gt;
to the Mozilla wiki page. If you have any comments,
please add them to the wiki page!
Thanks to &lt;a href=&quot;http://www.ludicrum.org/plsWork/&quot;&gt;Patrick L. Schmitz&lt;/a&gt; for
allowing me to use some of the ideas he proposed in his &lt;a href=&quot;http://www.ludicrum.org/plsWork/papers/BatikSMILsupport.htm&quot;&gt;Batik Timing and
Animation Support&lt;/a&gt;
design.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/07/19/draft-design/#comments</comments><category>Archive</category><category>SMIL</category></item><item><title>Basic prototype</title><link>https://birtles.blog/2005/05/18/basic-prototype/</link><guid isPermaLink="true">https://birtles.blog/2005/05/18/basic-prototype/</guid><description>I’ve put together a very basic prototype with some of the ideas discussed so
far.
</description><pubDate>Wed, 18 May 2005 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve put together a very basic prototype with some of the ideas discussed so
far. Please be aware that it’s very limited.
The idea was just to help with discussion and to help me try to understand some
of the suggestions.
So it’s not a serious proposal.
I was working on something a bit more solid but I threw it away after I read
some of the suggestions on usenet/IRC/wiki.&lt;/p&gt;
&lt;p&gt;So there are about a bzillion things wrong with the prototype but I think it
should still aid discussion.&lt;/p&gt;
&lt;p&gt;I tried to implement Alex’s suggestion for the anim/base value split. It mostly
works but produces a lot of assertions and doesn’t function correctly via the
DOM (not sure if it’s because a modified QueryInterface is needed or because of
vtable magic involved in XPConnect). I won’t look at this too much more because
there seem to be a lot of (much more capable) people interested in this. Scooter
and I agreed that he’d look at this and I’d look at the timegraph stuff.&lt;/p&gt;
&lt;p&gt;This experiment only animates the x and y attributes of elements and only for
very simple animations.
Basically it runs &lt;a href=&quot;https://birtles.blog/smil/tests/simple-embedded.xhtml&quot;&gt;this test case&lt;/a&gt; and
probably nothing else.&lt;/p&gt;
&lt;p&gt;Here it is: &lt;a href=&quot;https://birtles.blog/smil/patches/anim-proto-1.patch&quot;&gt;Animation experimenting patch&lt;/a&gt;
(to be applied from &lt;code&gt;/mozilla&lt;/code&gt;, I ran &lt;code&gt;patch -p 3 -u -N &amp;#x3C; anim-proto-1.patch&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Please &lt;a href=&quot;mailto:birtles@gmail.com&quot;&gt;email me&lt;/a&gt; if you have any comments—or better
yet email everyone or write something on the
&lt;a href=&quot;https://web.archive.org/web/20070702103839/https://wiki.mozilla.org/SVGDev::Animation&quot;&gt;wiki&lt;/a&gt;.&lt;/p&gt;</content:encoded><comments>https://birtles.blog/2005/05/18/basic-prototype/#comments</comments><category>Archive</category><category>SMIL</category></item></channel></rss>