<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: minecraft</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/minecraft.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2025-05-26T23:48:36+00:00</updated><author><name>Simon Willison</name></author><entry><title>CSS Minecraft</title><link href="https://simonwillison.net/2025/May/26/css-minecraft/#atom-tag" rel="alternate"/><published>2025-05-26T23:48:36+00:00</published><updated>2025-05-26T23:48:36+00:00</updated><id>https://simonwillison.net/2025/May/26/css-minecraft/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://benjaminaster.github.io/CSS-Minecraft/"&gt;CSS Minecraft&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Incredible project by Benjamin Aster:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There is no JavaScript on this page. All the logic is made 100% with pure HTML &amp;amp; CSS. For the best performance, please close other tabs and running programs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The page implements a full Minecraft-style world editor: you can place and remove blocks of 7 different types in a 9x9x9 world, and rotate that world in 3D to view it from different angles.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Animated demo. I start with a 9x9 green grid and add several blocks to it in different materials, rotating the screen with on-screen controls to see different angles." src="https://static.simonwillison.net/static/2025/minecraft-css.gif" /&gt;&lt;/p&gt;
&lt;p&gt;It's implemented in just &lt;a href="https://github.com/BenjaminAster/CSS-Minecraft/blob/main/main.css"&gt;480 lines of CSS&lt;/a&gt;... and 46,022 lines (3.07MB) of HTML!&lt;/p&gt;
&lt;p&gt;The key trick that gets this to work is &lt;strong&gt;labels&lt;/strong&gt; combined with the &lt;code&gt;has()&lt;/code&gt; selector. The page has 35,001 &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; elements and 5,840 &lt;code&gt;&amp;lt;input type="radio"&amp;gt;&lt;/code&gt; elements - those radio elements are the state storage engine. Clicking on any of the six visible faces of a cube is clicking on a label, and the &lt;code&gt;for=""&lt;/code&gt; of that label is the radio box for the neighboring cube in that dimension.&lt;/p&gt;
&lt;p&gt;When you switch materials you're actually switching the available visible labels:&lt;/p&gt;
&lt;pre&gt;.&lt;span class="pl-c1"&gt;controls&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;has&lt;/span&gt;(
  &lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; .&lt;span class="pl-c1"&gt;block-chooser&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; .&lt;span class="pl-c1"&gt;stone&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; &lt;span class="pl-ent"&gt;input&lt;/span&gt;[&lt;span class="pl-c1"&gt;type&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-s"&gt;radio&lt;/span&gt;]&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;checked&lt;/span&gt;
) &lt;span class="pl-c1"&gt;~&lt;/span&gt; &lt;span class="pl-ent"&gt;main&lt;/span&gt; .&lt;span class="pl-c1"&gt;cubes-container&lt;/span&gt; &lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt; .&lt;span class="pl-c1"&gt;cube&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;not&lt;/span&gt;(.&lt;span class="pl-c1"&gt;stone&lt;/span&gt;) {
  &lt;span class="pl-c1"&gt;display&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; none;
}&lt;/pre&gt;

&lt;p&gt;Claude Opus 4 &lt;a href="https://claude.ai/share/35ccb894-d26d-4698-b743-3de130adf433"&gt;explanation&lt;/a&gt;: "When the "stone" radio button is checked, all cube elements except those with the &lt;code&gt;.stone&lt;/code&gt; class are hidden (&lt;code&gt;display: none&lt;/code&gt;)".&lt;/p&gt;
&lt;p&gt;Here's a shortened version of the &lt;a href="https://pugjs.org/api/getting-started.html"&gt;Pug&lt;/a&gt; template (&lt;a href="https://github.com/BenjaminAster/CSS-Minecraft/blob/main/index.pug"&gt;full code here&lt;/a&gt;) which illustrates how the HTML structure works:&lt;/p&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;//- pug index.pug -w&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;/span&gt;&lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;blocks&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; [&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;air&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;stone&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;grass&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;dirt&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;log&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;wood&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;leaves&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;glass&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;];&lt;/span&gt;
&lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;layers&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;9&lt;/span&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;rows&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;9&lt;/span&gt;;&lt;/span&gt;
&lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;columns&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-c1"&gt;9&lt;/span&gt;;&lt;/span&gt;
&amp;lt;&lt;span class="pl-ent"&gt;html&lt;/span&gt; &lt;span class="pl-e"&gt;lang&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;en&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;style&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-v"&gt;--layers&lt;/span&gt;: #{layers}; &lt;span class="pl-v"&gt;--rows&lt;/span&gt;: #{rows}; &lt;span class="pl-v"&gt;--columns&lt;/span&gt;: #{columns}&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
&lt;span class="pl-c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;
&amp;lt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;blocks&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
  &lt;span class="pl-k"&gt;for&lt;/span&gt; _, layer &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-c1"&gt;Array&lt;/span&gt;(layers)
    &lt;span class="pl-k"&gt;for&lt;/span&gt; _, row &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-c1"&gt;Array&lt;/span&gt;(rows)
      &lt;span class="pl-k"&gt;for&lt;/span&gt; _, column &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-c1"&gt;Array&lt;/span&gt;(columns)
        &amp;lt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cubes-container&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;style&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-v"&gt;--layer&lt;/span&gt;: #{layer}; &lt;span class="pl-v"&gt;--row&lt;/span&gt;: #{&lt;span class="pl-c1"&gt;row&lt;/span&gt;}; &lt;span class="pl-v"&gt;--column&lt;/span&gt;: #{&lt;span class="pl-c1"&gt;column&lt;/span&gt;}&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
          &lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;selectedBlock&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; layer &lt;span class="pl-k"&gt;===&lt;/span&gt; layers &lt;span class="pl-k"&gt;-&lt;/span&gt; &lt;span class="pl-c1"&gt;1&lt;/span&gt; &lt;span class="pl-k"&gt;?&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;grass&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-k"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;air&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
          &lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;name&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;cube-layer-&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;layer&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;-row-&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;row&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;-column-&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;column&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
          &amp;lt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube #{blocks[0]}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
            &lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;id&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;name&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;-&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;blocks[&lt;span class="pl-c1"&gt;0&lt;/span&gt;]&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
            &amp;lt;&lt;span class="pl-ent"&gt;input&lt;/span&gt; &lt;span class="pl-e"&gt;type&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;radio&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;name&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{name}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;id&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;!{selectedBlock&lt;/span&gt; === &lt;span class="pl-e"&gt;blocks[0]&lt;/span&gt; &lt;span class="pl-e"&gt;?&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;checked&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-e"&gt;}&lt;/span&gt; /&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;front&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;back&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;left&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;right&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;top&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;bottom&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
          &amp;lt;/&lt;span class="pl-ent"&gt;div&lt;/span&gt;&amp;gt;
          &lt;span class="pl-k"&gt;each&lt;/span&gt; block, index &lt;span class="pl-k"&gt;in&lt;/span&gt; &lt;span class="pl-smi"&gt;blocks&lt;/span&gt;.&lt;span class="pl-c1"&gt;slice&lt;/span&gt;(&lt;span class="pl-c1"&gt;1&lt;/span&gt;)
            &lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;id&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;name&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;-&lt;span class="pl-s1"&gt;&lt;span class="pl-pse"&gt;${&lt;/span&gt;block&lt;span class="pl-pse"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-pds"&gt;`&lt;/span&gt;&lt;/span&gt;;&lt;/span&gt;
            &lt;span class="pl-s1"&gt;- &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-c1"&gt;checked&lt;/span&gt; &lt;span class="pl-k"&gt;=&lt;/span&gt; index &lt;span class="pl-k"&gt;===&lt;/span&gt; &lt;span class="pl-c1"&gt;0&lt;/span&gt;;&lt;/span&gt;
            &amp;lt;&lt;span class="pl-ent"&gt;div&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube #{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;input&lt;/span&gt; &lt;span class="pl-e"&gt;type&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;radio&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;name&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{name}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;id&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;#{id}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;!{selectedBlock&lt;/span&gt; === &lt;span class="pl-e"&gt;block&lt;/span&gt; &lt;span class="pl-e"&gt;?&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;checked&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;:&lt;/span&gt; &lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="pl-e"&gt;}&lt;/span&gt; /&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer}-row-#{row + 1}-column-#{column}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;front&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer}-row-#{row - 1}-column-#{column}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;back&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer}-row-#{row}-column-#{column + 1}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;left&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer}-row-#{row}-column-#{column - 1}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;right&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer - 1}-row-#{row}-column-#{column}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;top&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
              &amp;lt;&lt;span class="pl-ent"&gt;label&lt;/span&gt; &lt;span class="pl-e"&gt;for&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;cube-layer-#{layer + 1}-row-#{row}-column-#{column}-#{block}&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="pl-e"&gt;class&lt;/span&gt;=&lt;span class="pl-s"&gt;&lt;span class="pl-pds"&gt;"&lt;/span&gt;bottom&lt;span class="pl-pds"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&amp;lt;/&lt;span class="pl-ent"&gt;label&lt;/span&gt;&amp;gt;
            &amp;lt;/&lt;span class="pl-ent"&gt;div&lt;/span&gt;&amp;gt;
&lt;span class="pl-c"&gt;          //- /each&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;/span&gt;        &amp;lt;/&lt;span class="pl-ent"&gt;div&lt;/span&gt;&amp;gt;
&lt;span class="pl-c"&gt;      //- /for&lt;/span&gt;
&lt;span class="pl-c"&gt;    //- /for&lt;/span&gt;
&lt;span class="pl-c"&gt;  //- /for&lt;/span&gt;
&lt;span class="pl-c"&gt;&lt;/span&gt;&amp;lt;/&lt;span class="pl-ent"&gt;div&lt;/span&gt;&amp;gt;
&lt;span class="pl-c"&gt;&amp;lt;!-- ... --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;So for every one of the 9x9x9 = 729 cubes there is a set of eight radio boxes sharing the same name such as &lt;code&gt;cube-layer-0-row-0-column-3&lt;/code&gt; - which means it can have one of eight values ("air" is clear space, the others are material types). There are six labels, one for each side of the cube - and those label &lt;code&gt;for=""&lt;/code&gt; attributes target the next block over of the current selected, visible material type.&lt;/p&gt;
&lt;p&gt;The other brilliant technique is the way it implements 3D viewing with controls for rotation and moving the viewport. The trick here relies on CSS animation:&lt;/p&gt;
&lt;pre&gt;.&lt;span class="pl-c1"&gt;controls&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;has&lt;/span&gt;(.&lt;span class="pl-c1"&gt;up&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;active&lt;/span&gt;) &lt;span class="pl-c1"&gt;~&lt;/span&gt; &lt;span class="pl-ent"&gt;main&lt;/span&gt; .&lt;span class="pl-c1"&gt;down&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation-play-state&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; running;
}
.&lt;span class="pl-c1"&gt;controls&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;has&lt;/span&gt;(.&lt;span class="pl-c1"&gt;down&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;active&lt;/span&gt;) &lt;span class="pl-c1"&gt;~&lt;/span&gt; &lt;span class="pl-ent"&gt;main&lt;/span&gt; .&lt;span class="pl-c1"&gt;up&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation-play-state&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; running;
}
.&lt;span class="pl-c1"&gt;controls&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;has&lt;/span&gt;(.&lt;span class="pl-c1"&gt;clockwise&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;active&lt;/span&gt;) &lt;span class="pl-c1"&gt;~&lt;/span&gt; &lt;span class="pl-ent"&gt;main&lt;/span&gt; .&lt;span class="pl-c1"&gt;clockwise&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation-play-state&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; running;
}
.&lt;span class="pl-c1"&gt;controls&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;has&lt;/span&gt;(.&lt;span class="pl-c1"&gt;counterclockwise&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt;&lt;span class="pl-c1"&gt;active&lt;/span&gt;) &lt;span class="pl-c1"&gt;~&lt;/span&gt; &lt;span class="pl-ent"&gt;main&lt;/span&gt; .&lt;span class="pl-c1"&gt;counterclockwise&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation-play-state&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; running;
}&lt;/pre&gt;

&lt;p&gt;Then later on there are animations defined for each of those different controls:&lt;/p&gt;
&lt;pre&gt;.&lt;span class="pl-c1"&gt;content&lt;/span&gt; .&lt;span class="pl-c1"&gt;clockwise&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-en"&gt;var&lt;/span&gt;(&lt;span class="pl-s1"&gt;--animation-duration&lt;/span&gt;) linear &lt;span class="pl-c1"&gt;1&lt;span class="pl-smi"&gt;ms&lt;/span&gt;&lt;/span&gt; paused rotate-clockwise;
}
&lt;span class="pl-k"&gt;@keyframes&lt;/span&gt; rotate-clockwise {
  &lt;span class="pl-k"&gt;from&lt;/span&gt; {
    &lt;span class="pl-c1"&gt;rotate&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; y &lt;span class="pl-c1"&gt;0&lt;span class="pl-smi"&gt;turn&lt;/span&gt;&lt;/span&gt;;
  }
  &lt;span class="pl-k"&gt;to&lt;/span&gt; {
    &lt;span class="pl-c1"&gt;rotate&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; y &lt;span class="pl-en"&gt;calc&lt;/span&gt;(&lt;span class="pl-c1"&gt;-1&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-en"&gt;var&lt;/span&gt;(&lt;span class="pl-s1"&gt;--max-rotation&lt;/span&gt;));
  }
}
.&lt;span class="pl-c1"&gt;content&lt;/span&gt; .&lt;span class="pl-c1"&gt;counterclockwise&lt;/span&gt; {
  &lt;span class="pl-c1"&gt;animation&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; &lt;span class="pl-en"&gt;var&lt;/span&gt;(&lt;span class="pl-s1"&gt;--animation-duration&lt;/span&gt;) linear &lt;span class="pl-c1"&gt;1&lt;span class="pl-smi"&gt;ms&lt;/span&gt;&lt;/span&gt; paused rotate-counterclockwise;
}
&lt;span class="pl-k"&gt;@keyframes&lt;/span&gt; rotate-counterclockwise {
  &lt;span class="pl-k"&gt;from&lt;/span&gt; {
    &lt;span class="pl-c1"&gt;rotate&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; y &lt;span class="pl-c1"&gt;0&lt;span class="pl-smi"&gt;turn&lt;/span&gt;&lt;/span&gt;;
  }
  &lt;span class="pl-k"&gt;to&lt;/span&gt; {
    &lt;span class="pl-c1"&gt;rotate&lt;/span&gt;&lt;span class="pl-kos"&gt;:&lt;/span&gt; y &lt;span class="pl-en"&gt;calc&lt;/span&gt;(&lt;span class="pl-en"&gt;var&lt;/span&gt;(&lt;span class="pl-s1"&gt;--max-rotation&lt;/span&gt;));
  }
}&lt;/pre&gt;

&lt;p&gt;Any time you hold the mouse down on one of the controls you switch the animation state out of &lt;code&gt;paused&lt;/code&gt; to &lt;code&gt;running&lt;/code&gt;, until you release that button again. As the animation runs it changes the various 3D transform properties applied to the selected element.&lt;/p&gt;
&lt;p&gt;It's &lt;em&gt;fiendishly&lt;/em&gt; clever, and actually quite elegant and readable once you figure out the core tricks it's using.

    &lt;p&gt;&lt;small&gt;&lt;/small&gt;Via &lt;a href="https://news.ycombinator.com/item?id=44100148"&gt;Hacker News&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/css"&gt;css&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/html"&gt;html&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/minecraft"&gt;minecraft&lt;/a&gt;&lt;/p&gt;



</summary><category term="css"/><category term="html"/><category term="minecraft"/></entry><entry><title>The Mirai Botnet Was Part of a College Student Minecraft Scheme</title><link href="https://simonwillison.net/2017/Dec/15/mirai-minecraft/#atom-tag" rel="alternate"/><published>2017-12-15T03:18:52+00:00</published><updated>2017-12-15T03:18:52+00:00</updated><id>https://simonwillison.net/2017/Dec/15/mirai-minecraft/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.wired.com/story/mirai-botnet-minecraft-scam-brought-down-the-internet/"&gt;The Mirai Botnet Was Part of a College Student Minecraft Scheme&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Fascinating story about last year’s Mirai botnet, which was originally developed to help corner the Minecraft server market.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/denial-of-service"&gt;denial-of-service&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/security"&gt;security&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/minecraft"&gt;minecraft&lt;/a&gt;&lt;/p&gt;



</summary><category term="denial-of-service"/><category term="security"/><category term="minecraft"/></entry><entry><title>Are there guides for playing Minecraft on Mac laptops?</title><link href="https://simonwillison.net/2012/Dec/12/are-there-guides-for/#atom-tag" rel="alternate"/><published>2012-12-12T11:52:00+00:00</published><updated>2012-12-12T11:52:00+00:00</updated><id>https://simonwillison.net/2012/Dec/12/are-there-guides-for/#atom-tag</id><summary type="html">
    &lt;p&gt;&lt;em&gt;My answer to &lt;a href="https://www.quora.com/Are-there-guides-for-playing-Minecraft-on-Mac-laptops/answer/Simon-Willison"&gt;Are there guides for playing Minecraft on Mac laptops?&lt;/a&gt; on Quora&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I play on a Mac laptop using the trackpad and ctrl+click for right clicking and that works absolutely fine. It's worth fiddling with the keyboard commands in the options screen (as with any game) but I've found it to be perfectly playable otherwise.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/games"&gt;games&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/gaming"&gt;gaming&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/macos"&gt;macos&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/quora"&gt;quora&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/minecraft"&gt;minecraft&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="games"/><category term="gaming"/><category term="macos"/><category term="quora"/><category term="minecraft"/></entry></feed>