Published: Apr 8, 2025 by Isaac Johnson
As I write this I’m preparing for a week of AI information. It will be like drinking from the firehose I’m sure
But before I head out to GCP Next, let’s look at few AI Site/App generation tools that we can add to our toolbelt. I’ve had these stashed in a notepad to get back to for a while. First up is Relume
Relume.io has been on my list of AI Codegen tools for a while. I really wanted to dig in so I could wrap my head around this site builder offering. Its goal is mostly around layouts and sitemaps.
In this post I’ll cover using it to build a fake landing page for a pyromaniac company called Trogdor. We’ll see how we can pair it several different ways using a variety of tools wrapping with a complete hosted landing page on a URL.
Relume.io setup
Relume.io is a site we can use to help build out wireframes and style guides that can then be fed to an AI generator like Cursor or Claude.
I signed up for an account and the first thing I’m presented with after confirming a code was a buy-more pitch - this isn’t a good sign
I chose free then did a survey and finally got to the landing page
First Prompt
Let’s make a website for Trogdor (I used their prompting guide):
Company description:
Trogdor is an up and coming fresh venture that encourages people to burn things. Offering guides, tips and tricks and regular blog called "The Burnables", Trogdor leads the way in social for the fire fanatics and one-armed dragon lovers alike.
Goals:
- Primary goal is to encourage new members to engage in social content
- Secondar goals include sharing how to burn things, where to find burnables, the joys of burning and learning more about fire
Other relevant notes:
- Trogdor has a logo of a dragon and dragon themes should be applied
- Include any references to StrongBad
I can then update a given section with more details
I’ll now try exporting to react with the updated site
However, to export to React, I need to create wireframes.
And in doing so, the moment I click the second page I get an upgrade prompt
I went through and deleted the other pages
Then I did an export and it worked
Claude
Let’s pull this over to Claude next.
I’ll get it into WSL
builder@DESKTOP-QADGF36:~$ cd Workspaces/
builder@DESKTOP-QADGF36:~/Workspaces$ mv /mnt/c/Users/isaac/Downloads/trogdor.zip ./
builder@DESKTOP-QADGF36:~/Workspaces$ unzip trogdor.zip
Archive: trogdor.zip
extracting: home/components/Cta3.jsx
extracting: home/components/Layout6.jsx
extracting: home/components/Footer3.jsx
extracting: home/components/Navbar5.jsx
extracting: home/components/Team2.jsx
extracting: home/components/Layout22.jsx
extracting: home/components/Blog38.jsx
extracting: home/components/Header78.jsx
extracting: home/components/Layout237.jsx
extracting: home/index.jsx
builder@DESKTOP-QADGF36:~/Workspaces$ mkdir trogdor
builder@DESKTOP-QADGF36:~/Workspaces$ mv home trogdor
I’ll make sure I’m using a newer NodeJS
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ nvm list
-> v10.22.1
v12.22.11
v14.18.1
v16.14.2
v17.6.0
v18.17.1
v18.18.2
v18.20.3
v20.9.0
v22.13.0
default -> 10.22.1 (-> v10.22.1)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v22.13.0) (default)
stable -> 22.13 (-> v22.13.0) (default)
lts/* -> lts/jod (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.3 (-> N/A)
lts/gallium -> v16.20.2 (-> N/A)
lts/hydrogen -> v18.20.7 (-> N/A)
lts/iron -> v20.18.3 (-> N/A)
lts/jod -> v22.14.0 (-> N/A)
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ nvm use 22.13
Now using node v22.13.0 (npm v10.9.2)
Npm Init
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (trogdor)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC) MIT
About to write to /home/builder/Workspaces/trogdor/package.json:
{
"name": "trogdor",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "MIT",
"description": ""
}
Is this OK? (yes) yes
npm notice
npm notice New major version of npm available! 10.9.2 -> 11.2.0
npm notice Changelog: https://github.com/npm/cli/releases/tag/v11.2.0
npm notice To update run: npm install -g npm@11.2.0
npm notice
Then (according to docs) add tailwind
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ npm i tailwindcss-animate @tailwindcss/typography
added 9 packages, and audited 10 packages in 1s
found 0 vulnerabilities
and the config they show
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ vi tailwind.config.js
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ wc -l tailwind.config.js
496 tailwind.config.js
I feel like I’m missing a piece, so i went back and started at the installation page to add tailwind
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ npm i @relume_io/relume-ui @relume_io/relume-tailwind
added 117 packages, and audited 334 packages in 14s
30 packages are looking for funding
run `npm fund` for details
found 0 vulnerabilities
I feel a bit dense - I know there is a step missing here and the docs do not cover it. My package.json is obviously wrong (there is no ‘index.js’) and there are now scripts to invoke tailwind.
Copilot
Let’s first see if Copilot can give us an assist
My tailwind project will not start. I believe the package.json is missing scripts or settings. the tailwind files are in the "home" folder
Since I’m using the free tier, I can just use Sonnet 3.5 (and not 3.7)
It’s going to now walk me through the steps
The reason I step through the changes is in some cases, the AI is removing things I don’t want removed. So I’ll skip the removal of license and description
In launching, I do see an error about pages and app missing (since we used /home)
I’ll just move “home” to “app” and try again
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ mv home app
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ npm run dev
> trogdor@1.0.0 dev
> next dev
⚠ Port 3000 is in use, trying 3001 instead.
⚠ Port 3001 is in use, trying 3002 instead.
▲ Next.js 14.2.26
- Local: http://localhost:3002
✓ Starting...
✓ Ready in 1188ms
It launched, but I just get 404 pages
Claude Code
Let’s pivot to Claude Code
I need to restart to apply an update but this reminds me how much I spend. 20 cents just to view my code
Claude went pretty quick to finding the cause and correcting:
This works, albeit looks absolutely terrible
I don’t think it’s pulling in the tailwind config
I’ll ask for some more help:
That now worked! And I think it just cost me another couple of dimes
Of course, we are missing art, but the layout looks reasonable
Bing (Copilot) Image Generation
I usually use MG for this, but let’s fire up something free like Bing via Copilot
create a company logo for "Trogdor" featuring a one armed dragon in the style of a modern corporate logo
It has two arms but i guess it is a dragon.
Google Gemini Image Generation
That is exactly what I want:
I dropped it into logo.png in the components
I also wanted some headshots for the company profile.
However, Gemini had some nanny settings that would prevent headshots of pyromaniacs
Midjourney Image Generation
Midjourney didn’t mind though
At this point I’ve used a mix of Gemini with Imogen3 and Midjourney through discord to build out the images. I also leveraged Copilot free tier to fix up some image sections in the code.
Let’s see how it looks:
Containerizing it
I used Copilot to whip up a Dockerfile
# Stage 1: Dependencies
FROM node:18-alpine AS deps
WORKDIR /app
# Install dependencies needed for node-gyp
RUN apk add --no-cache libc6-compat python3 make g++
# Copy package files
COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci
# Stage 2: Builder
FROM node:18-alpine AS builder
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Set environment variables
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
# Build application
RUN npm run build
# Stage 3: Runner
FROM node:18-alpine AS runner
WORKDIR /app
# Set environment variables
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Set correct permissions
RUN chown -R nextjs:nodejs /app
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
ENV PORT 3000
ENV HOSTNAME localhost
# Start the application
CMD ["node", "server.js"]
It also updated the NextJS config to add the “standalone” line
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
reactStrictMode: true,
swcMinify: true
}
module.exports = nextConfig
Then I built the image
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ docker build -t trogdor:0.1 .
[+] Building 126.2s (20/20) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 1.22kB 0.0s
=> [internal] load metadata for docker.io/library/node:18-alpine 1.7s
=> [auth] library/node:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load build context 17.8s
=> => transferring context: 1.23GB 17.7s
=> [deps 1/5] FROM docker.io/library/node:18-alpine@sha256:8d6421d663b4c28fd3ebc498332f249011d118945588d0a35cb9bc4b8ca09d9e 6.2s
=> => resolve docker.io/library/node:18-alpine@sha256:8d6421d663b4c28fd3ebc498332f249011d118945588d0a35cb9bc4b8ca09d9e 0.0s
=> => sha256:1e5a4c89cee5c0826c540ab06d4b6b491c96eda01837f430bd47f0d26702d6e3 1.26MB / 1.26MB 0.5s
=> => sha256:25ff2da83641908f65c3a74d80409d6b1b62ccfaab220b9ea70b80df5a2e0549 446B / 446B 0.4s
=> => sha256:8d6421d663b4c28fd3ebc498332f249011d118945588d0a35cb9bc4b8ca09d9e 7.67kB / 7.67kB 0.0s
=> => sha256:929b04d7c782f04f615cf785488fed452b6569f87c73ff666ad553a7554f0006 1.72kB / 1.72kB 0.0s
=> => sha256:ee77c6cd7c1886ecc802ad6cedef3a8ec1ea27d1fb96162bf03dd3710839b8da 6.18kB / 6.18kB 0.0s
=> => sha256:dd71dde834b5c203d162902e6b8994cb2309ae049a0eabc4efea161b2b5a3d0e 40.01MB / 40.01MB 2.3s
=> => extracting sha256:dd71dde834b5c203d162902e6b8994cb2309ae049a0eabc4efea161b2b5a3d0e 3.2s
=> => extracting sha256:1e5a4c89cee5c0826c540ab06d4b6b491c96eda01837f430bd47f0d26702d6e3 0.1s
=> => extracting sha256:25ff2da83641908f65c3a74d80409d6b1b62ccfaab220b9ea70b80df5a2e0549 0.0s
=> [deps 2/5] WORKDIR /app 0.6s
=> [deps 3/5] RUN apk add --no-cache libc6-compat python3 make g++ 17.9s
=> [runner 3/8] RUN addgroup --system --gid 1001 nodejs 0.8s
=> [runner 4/8] RUN adduser --system --uid 1001 nextjs 1.2s
=> [deps 4/5] COPY package.json package-lock.json ./ 0.0s
=> [deps 5/5] RUN npm ci 21.2s
=> [builder 3/5] COPY --from=deps /app/node_modules ./node_modules 8.5s
=> [builder 4/5] COPY . . 10.3s
=> [builder 5/5] RUN npm run build 50.5s
=> [runner 5/8] COPY --from=builder /app/public ./public 0.2s
=> [runner 6/8] COPY --from=builder /app/.next/standalone ./ 0.3s
=> [runner 7/8] COPY --from=builder /app/.next/static ./.next/static 0.0s
=> [runner 8/8] RUN chown -R nextjs:nodejs /app 3.5s
=> exporting to image 0.4s
=> => exporting layers 0.4s
=> => writing image sha256:db0d32ba31fc1abd2142c2c451d3b185682c5cba5a46833115cc328462291860 0.0s
=> => naming to docker.io/library/trogdor:0.1 0.0s
6 warnings found (use docker --debug to expand):
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 35)
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 55)
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 56)
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 23)
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 24)
- LegacyKeyValueFormat: "ENV key=value" should be used instead of legacy "ENV key value" format (line 34)
It started but wouldn’t serve traffice.
I updated the Dockerfile
# Stage 1: Dependencies
FROM node:18-alpine AS deps
WORKDIR /app
# Install dependencies needed for node-gyp
RUN apk add --no-cache libc6-compat python3 make g++
# Copy package files
COPY package.json package-lock.json ./
# Install dependencies
RUN npm ci
# Stage 2: Builder
FROM node:18-alpine AS builder
WORKDIR /app
# Copy dependencies from deps stage
COPY --from=deps /app/node_modules ./node_modules
COPY . .
# Set environment variables
ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_ENV production
# Build application
RUN npm run build
# Stage 3: Runner
FROM node:18-alpine AS runner
WORKDIR /app
# Set environment variables
ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1
# Create non-root user
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
# Copy necessary files from builder
COPY --from=builder /app/public ./public
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
# Set correct permissions
RUN chown -R nextjs:nodejs /app
# Switch to non-root user
USER nextjs
# Expose port
EXPOSE 3000
# Set environment variables
ENV PORT 3000
ENV HOSTNAME "0.0.0.0"
# Start the application
CMD ["node", "server.js"]
and next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
reactStrictMode: true,
swcMinify: true,
experimental: {
serverMinification: true,
},
httpAgentOptions: {
keepAlive: true,
},
}
module.exports = nextConfig
then tried again. This time it worked
I’ll now tag and push to Dockerhub so we can use in Kubernetes
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ docker tag trogdor:0.2 idjohnson/trogdor:latest
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ docker push idjohnson/trogdor:latest
The push refers to repository [docker.io/idjohnson/trogdor]
034bef2ff8dc: Pushed
d1580608322b: Pushed
e5259299187a: Pushed
37b4c3914698: Pushed
972cfacc80f3: Pushed
e256c77e17a2: Pushed
9304264a6b25: Pushed
82140d9a70a7: Mounted from library/node
f3b40b0cdb1c: Mounted from library/node
0b1f26057bd0: Mounted from library/node
08000c18d16d: Mounted from library/node
latest: digest: sha256:a4c816588af6e3b2673f56a980abc32a09e4168f1f780b6694a691c0e96e3c56 size: 2623
I’ll create a subdomain
$ az account set --subscription "Pay-As-You-Go" && az network dns record-set a add-record -g idjdnsrg -z tpk.pw -a 75.73.224.240 -n trogdor
{
"ARecords": [
{
"ipv4Address": "75.73.224.240"
}
],
"TTL": 3600,
"etag": "1152c738-e47e-4599-8004-a7fcc16b56ef",
"fqdn": "trogdor.tpk.pw.",
"id": "/subscriptions/d955c0ba-13dc-44cf-a29a-8fed74cbb22d/resourceGroups/idjdnsrg/providers/Microsoft.Network/dnszones/tpk.pw/A/trogdor",
"name": "trogdor",
"provisioningState": "Succeeded",
"resourceGroup": "idjdnsrg",
"targetResource": {},
"trafficManagementProfile": {},
"type": "Microsoft.Network/dnszones/A"
}
I then created a Deployment, Service and Ingress that can use the Azure DNS clusterIssuer
apiVersion: apps/v1
kind: Deployment
metadata:
name: trogdor-deployment
labels:
app: trogdor
spec:
replicas: 3
selector:
matchLabels:
app: trogdor
template:
metadata:
labels:
app: trogdor
spec:
containers:
- name: trogdor
image: idjohnson/trogdor:latest
ports:
- containerPort: 3000
env:
- name: HOSTNAME
value: "0.0.0.0"
resources:
limits:
memory: "512Mi"
cpu: "500m"
requests:
memory: "256Mi"
cpu: "250m"
---
apiVersion: v1
kind: Service
metadata:
name: trogdor-service
spec:
selector:
app: trogdor
ports:
- port: 80
targetPort: 3000
type: ClusterIP
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: azuredns-tpkpw
ingress.kubernetes.io/ssl-redirect: "true"
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: "true"
nginx.ingress.kubernetes.io/proxy-read-timeout: "3600"
nginx.ingress.kubernetes.io/proxy-send-timeout: "3600"
nginx.org/websocket-services: trogdor-service
name: trogdoringress
spec:
rules:
- host: trogdor.tpk.pw
http:
paths:
- backend:
service:
name: trogdor-service
port:
number: 3000
path: /
pathType: ImplementationSpecific
tls:
- hosts:
- trogdor.tpk.pw
secretName: trogdor-tls
Then deployed it
builder@DESKTOP-QADGF36:~/Workspaces/trogdor$ kubectl apply -f ./deployment.yaml
deployment.apps/trogdor-deployment created
service/trogdor-service created
ingress.networking.k8s.io/trogdoringress created
Soon I saw the splash page for this made up Company attrogdor.tpk.pw
Site Map
We can also export the site map to a CSV
Or Text
Page: **Home**
- Navbar
- Hero Header Section: Welcome to Trogdor - Ignite Your Passion for Burning
- Feature Section: Highlight the primary goal of engaging new members in social content
- Features List Section: Share tips and tricks on burning things, Highlight the joys of burning, Share how to find burnables
- Benefits Section: Encourage visitors to explore the benefits of being a part of the fire fanatic community
- Blog List Section: List of informative and engaging blog posts about burning and the fire industry
- Team Section: Meet the Trogdor team and their passion for fire and burning
- CTA Section: Encourage visitors to join the community and start burning things
- Footer
Let’s feed that into something like v0
Create a landing page for a company called Trogdor with a theme of fire and dragons. Clean art and light backgrounds. The focus should be on burning enthusiasts and fire starting.
The layout should look like:
Page: **Home**
- Navbar
- Hero Header Section: Welcome to Trogdor - Ignite Your Passion for Burning
- Feature Section: Highlight the primary goal of engaging new members in social content
- Features List Section: Share tips and tricks on burning things, Highlight the joys of burning, Share how to find burnables
- Benefits Section: Encourage visitors to explore the benefits of being a part of the fire fanatic community
- Blog List Section: List of informative and engaging blog posts about burning and the fire industry
- Team Section: Meet the Trogdor team and their passion for fire and burning
- CTA Section: Encourage visitors to join the community and start burning things
- Footer
I can now watch as V0 builds out a basic stie
This looks passable
I downloaded a zip of the source then added the V0 dependencies
builder@DESKTOP-QADGF36:~/Workspaces/trogdor-landing$ npm install -g pnpm
added 1 package in 1s
1 package is looking for funding
run `npm fund` for details
builder@DESKTOP-QADGF36:~/Workspaces/trogdor-landing$ npx shadcn@latest add "https://v0.dev/chat/b/b_q9SxviEyiwz?token=eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..Hq22pSwHSiZHfqKL.ZQttah6lbxquc-mk4eaJY7FmbYhm38J33oX4ci9HMaFYcr8EmnmsKheUEQk.jE83TIYSO7p0TIjKFk2EIg"
✔ Checking registry.
✔ Installing dependencies.
ℹ Skipped 3 files: (files might be identical, use --overwrite to overwrite)
- app/page.tsx
- components/ui/button.tsx
- components/ui/card.tsx
Please review v0-generated code before incorporating it into your project to ensure completeness and accuracy.
I can then use npm run dev
to test
builder@DESKTOP-QADGF36:~/Workspaces/trogdor-landing$ npm run dev
> my-v0-project@0.1.0 dev
> next dev
▲ Next.js 15.2.4
- Local: http://localhost:3000
- Network: http://10.255.255.254:3000
- Experiments (use with caution):
✓ webpackBuildWorker
✓ parallelServerCompiles
✓ parallelServerBuildTraces
✓ Starting...
✓ Ready in 1325ms
Claude for Images
I’m going to push Claude Code a bit. I really do not know if ti can do image creation, but it cannot hurt to ask
I can see it start to work out some inline images
Let’s see what $0.55 of Claude bought me
Actually, this is so bad I just have to show you as a slow scroll…
I can, of course, follow the same path of fixing up the images with various art generators.
Instead, let’s just sit and focus on this true masterpiece
Summary
Today we used Relume.io to build out a basic Landing page (it could have done more but not at the free tier) and then used a variety of Code Assistants to finish the job including Claude Code and Github Copilot.
We used Bing (Copilot) image generation, Google’s Imagegen3 via Gemini and Midjourney to create replacement images for the placeholders. Lastly, we containerized it and pushed it out to a URL for all to see:
We could use tools like Gemini Code Assist, Copilot and Claude Code to finish the site out - creating actual signup forms and blog posts. But I felt we got the idea and this would be enough to pitch as a first draft.
We also pulled the wireframe and paired that with v0 to build out a React and Tailwind example with Vercel’s UI Genai tool. I then let Claude Code attempt to create images which spurned the nightmare fuel above.
I should mention that I tried to use Midjourney to take that nightmarish Dragon image and make it into something real, but even those I found off-putting and rather unsettling:
I know there is more that Relume can do, including populating Figma. I could see it useful for a website creation team to create quick build outs. But then I have to compare that with patterns I’ve seen other AI coders use which is to build their own basic Landing page with Federated Identity and signup forms, etc. Then use that more functional prototype as their basis for new work. It’s certainly something to consider.
I hope you found something useful in the article. As always, feel free to reach out with comments and feedback.