zkbro

Creating a text-wall

2025-10-24 21:30

A while back I wanted to add a guestbook for my website. After stumbling across yourworldoftext which is not a guestbook in the traditional sense (warning - some crude writing in there, it's been bombed by all walks of life), it gave me some ideas. I thought my own version would be a fun little project to whack up. So after a bit of research (mainly via ChatGPT), and trial and error, I got my text-wall of sorts up and running:

I'm really happy with how it has turned out. It gives writers a little more freedom than the standard guestbook, adds to the style of my website and reflects my interest in geekery. It's an absolute pleasure loading up and seeing new messages, text art, links to personal blogs. I never know what to expect.

There are a couple of posts on there that show some interest in setting one up themselves. Below I'll attempt to explain how I did it if anyone is interested. Note, there are actual sites that do the whole thing for you - walloftext - and probably a better job of it, but if you're like me and want to take matters in your own hands, then below is how I did it. If anyone creates one of these, please share me your link. I'd love to see your variation.

Note: This does use JavaScript, so won't work on users' browsers with JS disabled.


How to do it

There are essentially two parts to this:

Supabase

Set up a free Supabase account

Supabase is an open source PostgreSQL database development platform. This is new territory for me. I have literally just used it for this project, so can't really comment much on it other than it has a free tier suitable for this project, it is open source, and it works.

Create a free account

Prepare project and database

Create a new project:

In the left menu go to the SQL Editor and enter and run the following code:

create table text_wall (
    id serial primary key,
    content text default ''
);

-- Insert initial empty content
insert into text_wall (id, content) values (1, '');

Now in Database --> Tables a new table called text_wall appears:

Secure and set authentication policy

Go to Authentication --> Policies and Enable RLS (row level security) and Create policy on the text_wall table with the following criteria:

Copy URL and API key

Go to Project Settings --> Data API and copy the URL to a text file. This will be needed in the HTML soon.

Go to Project Settings --> API Keys and copy the anon public key to a text file. This will also be needed in the HTML.

HTML

Copy the following HTML into index.html (or whatever you want to call it), and modify lines 10 and 11 with the text copied above:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>zkbro's text wall</title>
    <script type="module">
        import { createClient } from 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js/+esm'

        const SUPABASE_URL = "https://your-supabase-url.supabase.co";
        const SUPABASE_ANON_KEY = "your-anon-key";

        const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
        const textArea = document.getElementById("textwall");

        async function fetchText() {
            let { data, error } = await supabase
                .from("text_wall")
                .select("content")
                .eq("id", 1)
                .single();
            
            if (error) console.error("Error fetching:", error);
            else textArea.value = data.content;
        }

        async function updateText(content) {
            let { error } = await supabase
                .from("text_wall")
                .update({ content })
                .eq("id", 1);

            if (error) console.error("Error updating:", error);
        }

        fetchText();

        textArea.addEventListener("input", () => {
            updateText(textArea.value);
        });

        supabase
            .channel('realtime:text_wall')
            .on('postgres_changes', { event: 'UPDATE', schema: 'public', table: 'text_wall' }, (payload) => {
                textArea.value = payload.new.content;
            })
            .subscribe();

    </script>
    <style>
        body {
            font-family: Monospace;
            white-space: pre-wrap;
            word-wrap: break-word;
            margin: 0;
            padding: 20px;
            height: 100vh;
            background: #222222;
            color: #fd9353;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        textarea {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            border: none;
            background: transparent;
            color: inherit;
            font-family: inherit;
            font-size: 1.2em;
            resize: none;
            outline: none;
            overflow: auto;
            padding: 20px;
            white-space: pre;
        }
    </style>
</head>
<body>
    <textarea id="textwall" placeholder="Text-wall loading..."></textarea>
</body>
</html>

I've just left my own styling in there for the moment. You do you.

Test

If you load the HTML file into a web browser you should be able to write text, which will load straight into the single cell in your Supabase table (viewable in Table editor). Refreshing the browser window should retain the text.

Copy HTML to a hosting provider

Although I host my website on neocities, I am still on the free tier, which has a more "strict content security policy", meaning it rightly so blocks some backend stuff that is happening (not that mine is doing anything bad, but being tighter on security on the free tier probably keeps people from exploiting neocities).

That is why I am currently hosting my text-wall on Codeberg pages. Codeberg is essentially a git forge, and like GitHub has a "pages" feature to publish websites from repositories. If you aren't familiar with git, it might be a bit tricky, but the instructions are over at codeberg.pages.

There are many other webhosting options out there. Try something new. Why not?


So that's it. Not a great deal to it really - a single cell in a database and a HTML file - but I do like that I can give visitors to my site a bit of freedom in how they want to write. It's plain text, yet I see a lot of character seep through. Love it.

Some future improvements