Tyler Morgan-Wall - Quarto, AI, and the Art of Getting Your Life Back
videoimage: thumbnail.jpg
Transcript#
This transcript was generated automatically and may contain errors.
Hello everyone, yes, I'm Tyler Morgan-Wall. I'm the developer of RayShader and the Rayverse, a collection of packages for 3D data visualization and mapping, and a researcher at the Institute for Defense Analyses in Alexandria, Virginia, and today I'm going to be talking to you about Quarto, AI, and the Art of Getting Your Life Back.
So late last year, I had done something really cool, and I wanted to share it with the world. I had created an R package that allowed you to transform 2D geospatial data of building footprints into 3D buildings and generate entire cities in a matter of minutes. But getting the coding finished was just the beginning. Without explaining the value of what I had done in terms of solving actual problems, the chance that someone would both come across my work and come to the conclusion on their own that it was worth their time was next to none.
So how was I going to get it out there? Well, I decided to write a blog post about it. Even if I wrote great documentation in the package itself, documentation focuses on the how to use the package and not the why to use the package. With a blog post, you can tell your project's origin story, what problem or idea brought it into being, and the trials and tribulations you encountered on your journey to solve those problems.
Additionally, with a blog post, you control the medium. You can add as many high-quality images and videos or make it as long as you want, and there is absolutely no chance that your blog will be purchased by Elon Musk.
Now, I've run my own blog since 2016, and having a place to feature my own long-form content has been a great boon for my professional life. However, when I was first getting started and trying to spin up my blog, it immediately became apparent that actually running a blog is awful. Having to deal with HTML, CSS, and JavaScript on top of the hard technical work I was already doing with R, no thank you. So after a bit of research, I decided to run my blog on WordPress.
Now, if you don't know, WordPress powers over 40% of all websites on the Internet. It's so popular because it's super easy to theme, customize, and publish content without any technical background. So it seemed like the obvious choice for somebody who wanted to spend as little time on the actual act of running a blog as possible. But appearances can be deceiving.
The downside to WordPress' ubiquity is it's constantly being probed by hackers, so security updates are essential and unrelentingly frequent. And at the time I went to publish this post on 3DCities, I discovered I couldn't install these security updates without updating my Linux distribution, which I couldn't do because my server didn't have enough space, so I'd have to upgrade it, and figuring this out was taking a lot of time, and I wanted to be spending time doing the stuff I actually enjoy doing, not server maintenance.
So I was also, though, dreading the idea of moving away from WordPress because it had such nice facilities for publishing content and customizing and adding cool dynamic features to my website. So basically I wanted it all. I wanted the easy ability to publish content, but I didn't want all of the tedious server maintenance.
Switching to Quarto
So enter Quarto. Quarto builds static sites so there's no constant parade of security updates. However, customizing your website is harder because you have to do so manually. And while in the past that meant having to learn languages like CSS and JavaScript, the development of large language models, which henceforth are referred to as AI, has greatly lowered this barrier to entry.
So here's what you should expect to take away from this talk. First, I'm going to tell you the one weird trick I use to convert an existing blog to Quarto. Second, I'm going to tell you how you can automate your website's deployment by using something called Quarto render hooks. And then finally, I'm going to tell you how you can customize and add cool dynamic features to your Quarto website using AI.
Converting an existing blog to Quarto
So to begin, let's say you have an existing website, Quarto or otherwise, and after this talk you decide that you're going to switch to Quarto. How would you go about doing that? Doing the absolute bare minimum amount of work. So to give you some context, I originally wrote all of my blog posts in R Markdown, knitted them to HTML, and then just copied that raw HTML into my WordPress editor. So I could have gone back to the RMD files and manually converted them to QMD files, but that would have been a lot of time and effort, and again, I did not want to do that.
So here is an example of one of my old blog posts on WordPress, and to illustrate the trick I'm going to use, let's compare this. Note that the content is actually not important, but just that it is raw HTML pasted into the WordPress editor. So for the trick, let's look at one of my new posts in the QMD format for my new website, which, if you look closely, is the exact same content.
And that is the trick. You can just copy and paste your old blog post's HTML directly into a QMD file. When you render your Quarto website, that text will render as HTML, not text. You can also put it in a raw HTML block if you'd like, but you don't have to.
You can just copy and paste your old blog post's HTML directly into a QMD file. When you render your Quarto website, that text will render as HTML, not text.
The only work I had to do in this transition was to write a Quarto header for each post. Now, these are places where you specify the title and authors and date, but you could also add shared content to each post. So on my old website, I had custom JavaScript and style sheets added to each post via a global customization option in WordPress, and I was able to add these to the old posts on my new site via this include in header, include after body, and CSS fields. Additionally, you can specify a featured image for each post, which here you might note is actually still pointing to a WordPress-specific media directory, wp-content. In order to complete the full transition, all I did was copy this directory and all of its subdirectories to my new site, and that is how I transition my site to Quarto.
So let's look and compare one of my old blog posts and the new one. So here is an example of one of my old blog posts on my old website, and here is the new version of that. Different style, but note that all of the content is rendered perfectly, and it only required writing a few Quarto headers. And because this trick used just HTML, this could potentially apply to other blogging frameworks as well, although particularly in this case, if you had an RMD file, that's what makes this, I think, so seamless.
Additionally, the only caveat is that if you have hard-coded layout elements that depend on the specific design of a page or things like dynamic content such as WordPress shortcodes, those would have to be handled manually, but I had very few of those, so this was basically the whole process.
Automating deployment with Quarto render hooks
However, having converted my website to Quarto, I now face the next issue, which is actually getting it online. Because in WordPress, I could just press the button Publish Post, and my content was online. I wanted the equivalent of that Publish Post button in RStudio, and for me, that meant never having to touch a terminal and being able to do this entirely from my Quarto project. So how could I do that?
With Quarto Render Hooks. Quarto Render Hooks are a neat and powerful feature that allow you to inject your own scripts into the Quarto rendering pipeline. You can specify them in your project-level Quarto file like this. These can be arbitrary shell commands, Lua, Python, and R scripts. So here, I specified a pre-render hook that just prints a fun message, as well as a post-render hook that does some actual work.
For example, in my website, I store my media into non-standard directories, posts and videos located within my posts directory. And when I render my Quarto website, these are not automatically copied over. So all the first two post-render hooks do is copy those over to my site directory. I then call an R script called transferSite that does exactly what it sounds like. But note the one little argument at the end of this script. What exactly is that doing?
So let's dive into the script and see. That little string is just effectively the toggle button to upload my site. When I don't want to upload my site and just work locally, I just change this string to anything else. And in R, you can use this command args function to inspect what extra arguments are passed R when you called R. And when I change this to something else, this just skips the uploading process and just renders locally. I also then remind future me how to turn uploading back on because that is just basic programming self-care.
Now, here's the meat of the automation. So what I do here is just specify my local directories, my remote directories. And then I call this rsync utility via a system call, which then uploads the site. And that's it. Since I put this together, I haven't had to touch a terminal. I've been able to publish multiple blog posts and edit my site without ever thinking about any technical steps in between.
And even though I had never used rsync before, I learned to use it very quickly by using AI.
Customizing your Quarto website with AI
So AI is a great tool for learning new and well-established utilities such as rsync or popular languages like CSS and JavaScript. And that is what brings me to the last part of my talk, customizing your website with AI. While transitioning from a server-generated framework like WordPress to a static framework like Quarto brings many performance and maintenance improvements, it does also limit some of the cool dynamic features of your website. And by moving from a massively popular tool like WordPress to a relatively new tool like Quarto, you lose a lot of the great community resources and tools that have been developed to help you go through that process.
So the development of AI, however, has vastly evened this playing field. The current batch of AI tools are in large part trained on web-based data, and we are trying to build a website. So while AI is not good at things necessarily like data science or being really good at R or critical thinking or basic mathematics, it is pretty good at asking you things like, hey, generate the CSS for me to make my submit form button sashay across the page when I press it.
So let's do that. Not dancing buttons, but let's add some nice decorative 3D effects to our Quarto main page. So here are the Quarto postcards for each one of my blog posts on my old website. I wanted some sort of subtle 3D effect like that on my Quarto main page. So let's look and see what we're starting with in Quarto. So this is the default Quarto postcards, completely static with a white background. They're fine. I wanted to write some CSS to add some subtle animations and that sort of 3D pop-out effect when a reader mouths over the card.
To do so, I iterated back and forth with ChatGPT, adding the generated CSS to my Quarto style.css file and then provided feedback with each iteration, which honed in on the effect I was after. We made small adjustments to the existing CSS to get closer to what I wanted. And note that nowhere in my prompts was I using technical language specific to CSS to request what I wanted. I was using plain descriptive language, like tilting a piece of brushed metal rather than asking for specific CSS features or classes. And that's one of the really strengths of AI is that it's very good at translating your plain language request into specific features and functionality in these languages.
And even if it doesn't get the implementation exactly right, it will often get you about 90% there just by pointing out the features relevant to your response. And the risk of AI giving you the wrong answer, which is always present, can be mitigated if you have the ability to quickly check for correctness, which you can do here simply by rendering the page. So after 10 minutes, back and forth the chat GPT, this was the final result, a nice little 3D effect on my Quarto landing page made entirely with AI.
Building an image carousel
However, this was a relatively easy ask of AI since what I was asking for was a relatively common and simple decorative effect. How could the AI handle something with user interactivity and imposed design constraints? So that brings me to the second effect I wanted AI to assist me on, which is an image carousel. So on my old website, I had an image carousel that faded through the seven most recent posts at the top of the main page, as well as showed the title and put an image selector at the bottom that allowed you to select and go between the images.
So in WordPress, this was actually generated dynamically every single time you went to the website. The page would query the server, it would generate the most recent posts, and then some JavaScript would transform that into an image carousel. So how could I recreate this in Quarto? To do so, I would need two elements. First, I would need a way to query the most recent posts when I rendered the website, and then I would need some JavaScript to transform it into an image carousel.
And thankfully, I didn't have to use AI for the first portion because I took a workshop in Quarto at this very conference two years ago that gave me the solution for what I needed, which is document listings. Document listings allow you to generate a feed of categorized and recent posts and add them to any Quarto page. And so here, the Quarto main page consists of a main listing of all posts, but you can add as many additional listings as you want. So here I added an additional listing above the first of the most recent seven posts.
Now I need a way to transform these into the image carousel. So the first thing we can do entirely in Quarto is just get them to the right size. And I adjust it to take the full width of the main page, of the main content area on the main page, and then I adjust the image height via the image height argument, and then to our desired final image height for our carousel. And then I just need to write some JavaScript to transform those into an image carousel.
So that was an animated mock-up of what I was attempting to do with each post card. So this process was a bit more involved than the CSS one, unsurprisingly, so I'm not going to go through the full series of prompts. But what I will do is share with you four useful prompting strategies that I developed as I was working with AI.
So the first, and unsurprisingly, I think, is it's very good to give the AI the exact source code you want it to manipulate so that it has access to the structure and classes in your page. So here I just copied and pasted the listing HTML directly into my prompt and then asked it to transform it into an image carousel.
Second, as you iterate, it can often be good to constantly remind the AI what the current status of your script looks like. So even if it just generated for you a few prompts prior, AIs can lose focus over time due to their limited context window, and I found if I didn't constantly remind the AI what the current status was, it would kind of forget and make really bad mistakes. And by providing it that current version, it actually ended up much more likely to give me a relevant response.
Third, if you have visual details you want the AI to adjust, it can often be helpful to provide a screenshot of the issue as well as the description of it with your prompt. So here I had successfully transformed the post title into a semi-transparent gray overlay on the image. However, it had a very small few pixel gap at the bottom that I wanted removed. So I provided the screenshot and a description of the image, or a description of the problem, and the AI was able to issue a fix.
And then finally, sometimes the AI can seemingly get stuck and be unable to solve a problem solely by prompting. So, for example, I managed to get the AI to come up with an almost complete implementation of my image carousel, but there were one or two issues that it could not seem to solve just solely by prompting. So at that point, I just started asking the AI to explain the purpose of a specific snippet of code, and then once I understood what the code was doing, I just went in and solved the problem myself.
So AI can be middling at best when actually writing code, but I found that it's actually very good and very consistent at explaining the purpose of specific snippets of code. So combining the breadth of AI's knowledge with your far superior problem-solving skills can really supercharge your development speed.
So AI can be middling at best when actually writing code, but I found that it's actually very good and very consistent at explaining the purpose of specific snippets of code.
And while I didn't escape entirely unscathed from boring and tedious front-end work, the final result was pretty much exactly what I had in mind. In fact, I liked it a little better than the original WordPress version because this one actually rotated between images rather than just faded, as you'd think something called an image carousel would.
So in the end, my site was faster, better, easier to maintain. I guess the moral of the story is with Quarto, you can have it all.
Takeaways
So as a takeaway, Quarto can render pre-existing HTML pasted into a QMD file. A very simple but powerful fact. Second, you can use Quarto render hooks to automate much of the tedious parts of website deployment and publishing away, and these can be written in R, and you can control them entirely via your project-level Quarto file. And then finally, while AI can write code for you, it's often much more useful as a learning resource when working with unfamiliar tools. So using AI can help you focus on doing the things you actually like and save time so you can do those things that you love.
We have just a minute for a question. There we go. Would you recommend integrating the Rsync bit into a workflow for rendering and uploading a Quarto website deposit connect? I don't know if you know. I can't speak to that.
Then we'll ask the other one. You kind of answered this a little bit, but what are your thoughts on just, like, language-specific LLMs, so, like, in particular for assistance with, like, R code? Yeah, I found it to be, I mean, I've used the various forms of chat, GPT-4.0, the latest version. I found it to be, you know, it's best of the things I've seen a lot, and in particular, there's far less R code out there than there is at other code, and particularly a lot of the use cases for R code is very data science-focused, where there's actual, like, you know, important things on the line, and I found it to make really egregious mistakes in basic statistics to the point where I would never, unless you have that, again, that ability to quickly check for correctness in a way that you're 100% sure it's giving you the right result, I don't trust it further than I can check, so that's my opinion on that.
