Image generation is all the rage these days (for some people). With the release of Sora, it’s never been easier to create an image of yourself flying over a volcano, living in a candy house, graduating your masters with honours… But what if you could actually do those things? What if prompts were invitations to build realities rather than simulate them?

Sora’s marketing page
These models and outputs now look more and more realistic, more and more like photographs, but, unlike photographs they document nothing real. When you submit a prompt to Levi & Queenie, we, Levi & Queenie, will actually attempt it.
During brainstorming, we paced around the room with no project idea that we were both excited about. When Levi suggested the constraint that it be a project that makes us do something, we landed on the idea of turning our real selves into “image generation models”. We wanted to surrender control to the audience, and push our own boundaries. We also wanted it to be a little tongue and cheek to all the AI slop and engagement bait parasitizing our feeds, and see how we can add a bit of patience, effort, and whimsy into it.
Our ultimate hope for this project was that it be small in scope, straightforward for users, and something fun and silly that we can be proud of.

To plan out the experience, we drew a flowchart showing all the dependencies and features needed for our image generation tool. First, restricted prompt submissions needed to go through a notification system to us, Levi and Queenie. We needed to upload a photo, while on the client side, display a loading state and lock submissions. Once the photo is uploaded, the user could get notified (although a nice-to-have feature, and then get displayed on the page, unlocking the submission form. We could also reject the submission by sending back a message declining the request.
We decided to use Express as our backend and lowDB as a simple JSON database to store images and prompts. We also used Svelte for our frontend framework, making each element a component that’s easy to package and load.
For the notifyer, we didn’t want to work with Twilio due to its cost, which wrote off texts. Nor did we want email, worried that those would get buried in all our notification noise.
Discord bots were the other option that could easily give us notifications on our devices, while being super easy to set up.
// Have bot send a message in general when a chat is sent
events.on("newUpload", async (entry) => {
const channel = await client.channels.fetch(GENERAL_CHANNEL_ID);
if (!channel) {
return
}
We could use it to send a message to our server when a prompt came in, and it could also read messages we send and upload it into our database, alongside our user IDs.

For the user interface and interaction, we wanted it to resemble ChatGPT as closely as possible. The only difference being adding a drop down sentence completion, that restricted image generation to Levi, Queenie, or Queenie and Levi. Even the about pages were styled to look like ChatGPT’s. Though, we had to obscure the voice functionality, and replace it with their standard submit button
Here’s a comparison:


We screenshotted and colour dropped my way through the CSS. I matched border radii, line heights, padding, spacing, to make it look like a real image generation tool. Even copying the breathing dot loading state.
textarea {
resize: none;
border: none;
background: transparent;
color: #fff;
font-size: 0.9rem;
line-height: 1.5;
font-family: inherit;
margin-top: 8px;
}

Graveyard of UI screenshots.