Creating a presentation from a single huge PSD file

presentations
python
An experiment to convert a huge PSD file into a presentation. It worked well, but think there is a better way to do this
Published

June 2, 2025

I give a lot of presentations. For many years I have used Apple Keynote for this but in the last couple of years I have started to experiment with other methods. I’ve created about half a dozen presentations with revealjs, and I’ve done various experiments with it that I’ve written about it here:

I also use PowerPoint for client presentations, but PowerPoint sucks.

But my ideal presentation tool would allow me to make an “infinite canvas” that can also act as my own study tool. The advantage of an infinite canvas is that you can create large mind maps of a subject where the information is spatially laid-out, which is great for memory and seeing the relationship between things.

These days Photoshop works great with really huge images. It also has a lot of features built-in that could make it a great tool for creating an infinite canvas, for example named layers and groups of layers. I thought it might make a good tool to create the infinite canvas presentation I am thinking about.

Above you can see the test PSD file I created, with a group called “Slides” containing rectangles in 16:9 ratio representing the slides, named sequentially for the sequence of the slides in the presentation. The test PSD is pretty huge— 19200 by 10800 pixels, in other words about 10x HDTV resolution.

Step 1 — converting the PSD to JSON

I used Claude Sonnet 3.7 to help me write a nodejs tool to automatically convert the PSD file to a JSON file of all the data. This uses psd.js, a Photoshop PSD parser for NodeJS. Here’s what the generated JSON file looks like (with most of it removed, it’s very repetitive):

I did investigate using Python, but decided that using NodeJS makes more sense, and the Javascript PSD parser is good.

{
  "children": [
    {
      "type": "group",
      "visible": false,
      "opacity": 1,
      "blendingMode": "normal",
      "name": "slides",
      "left": -2,
      "right": 5611,
      "top": -1,
      "bottom": 3153,
      "height": 3154,
      "width": 5613,
      "children": [
        {
          "type": "layer",
          "visible": true,
          "opacity": 0.4,
          "blendingMode": "normal",
          "name": "10",
          "left": 6,
          "right": 5611,
          "top": -1,
          "bottom": 3153,
          "height": 3154,
          "width": 5605,
          "mask": {},
          "image": {}
        },
        ...
    {
      "type": "layer",
      "visible": true,
      "opacity": 1,
      "blendingMode": "normal",
      "name": " Luca Signorelli  Apocalyptic Frescoes",
      "left": 4547,
      "right": 5200,
      "top": 1793,
      "bottom": 1954,
      "height": 161,
      "width": 653,
      "mask": {},
      "text": {
        "value": " Luca Signorelli \rApocalyptic Frescoes",
        "font": {
          "lengthArray": [
            38
          ],
          "styles": [
            "normal"
          ],
          "weights": [
            "normal"
          ],
          "names": [
            "Palatino-Roman",
            "AdobeInvisFont",
            "MyriadPro-Regular"
          ],
          "sizes": [
            70
          ],
          "colors": [
            [
              204,
              204,
              204,
              255
            ]
          ],
          "alignment": [
            "left",
            "left"
          ],
          "textDecoration": [
            "none"
          ],
          "leading": [
            90
          ]
        },
        "left": 0,
        "top": 0,
        "right": 0,
        "bottom": 0,
        "transform": {
          "xx": 1,
          "xy": 0,
          "yx": 0,
          "yy": 1,
          "tx": 4546.40625,
          "ty": 1844.005208333334
        }
      },
      "image": {}
    },
    {
      "type": "layer",
      "visible": true,
      "opacity": 1,
      "blendingMode": "normal",
      "name": "orvieto-large.jpg",
      "left": 2520,
      "right": 4440,
      "top": 720,
      "bottom": 2160,
      "height": 1440,
      "width": 1920,
      "mask": {},
      "image": {}
    },
    ... 
  ],
  "document": {
    "width": 19200,
    "height": 10800,
    "resources": {
      "layerComps": [],
      "resolutionInfo": {
        "h_res": 72,
        "h_res_unit": 1,
        "width_unit": 1,
        "v_res": 72,
        "v_res_unit": 1,
        "height_unit": 1
      },
      "guides": [
        {
          "location": "29495882.4",
          "direction": "horizontal"
        },
        {
          "location": "35651584.0",
          "direction": "vertical"
        }
      ],
      "slices": []
    }
  }
}

an HTML presentation with the slides as defined in the PSD. Rather than use the PSD file as the displayed image, I wrote the script so that it used the original images (you’ll notice above that the image layers are named by their filenames).

Step 2 — converting the PSD to JSON

I then wrote another script to convert the JSON to a presentation. When coding with LLMs I try to break down the problem into smaller modules, and doing it in two steps like this made sense. It also means I could use other scripts to process the JSON, or example to create an interactive web page.

So what do the final results look like? Tada:

So that worked pretty well! The things I don’t like about this method are:

  1. Photoshop is of course closed-source and Adobe is a fairly customer hostile company, so I would prefer not to have it in processes I create for myself.
  2. I would really like a process that is friendly to vector files such as SVG, and can include huge vector files.
  3. I’d like an infinite canvas tool that can be an integral part of my research process. Whilst it is possible to use Photoshop as a kind of infinite canvas, it isn’t ideal.

So this experiment worked well, but it’s not ideal and I’m going to explore other methods to do this.