Aether | She/Her | 24

Aether | She/Her | 24

✧ THE FOREST GUIDE ✧

New to the Forest? Tap to explore the guide

Welcome, wanderer. Every path leads somewhere special. ♡

Requests

Have a character, CSS or Lorebook request? Share your request here.

Characters

Discover the characters and creations waiting in the forest.

Message Board

Leave a friendly note, a little encouragement, or a message for Aether.

Waiting List

Take a peek at the creations waiting their turn.

My Janitor Link

Visit my Janitor profile to explore my Characters.

✧ WELCOME TO ✧

The Request Grove

Where stories and ideas take root.

Whispers of the Forest

Leave a little magic among the leaves...

Messages are reviewed before appearing.

✧ The Whispering Grove ✧

Gathering whispers...
✦ May the forest keep your secrets and your kindness ✦
(function(){ const SUPABASE_URL = 'https://pgawnbkxtclczmccodje.supabase.co'; const SUPABASE_ANON_KEY = 'sb_publishable_4H3dCxI5Jz7JyiySgT8CdQ_Nq3p6jSJ'; const root = document.getElementById( 'aether-forest-board' ); const $ = id => root.querySelector('#' + id); const status = $('forest-status'); const posts = $('forest-posts'); const form = $('forest-form'); let visitor; try { visitor = localStorage.getItem( 'aether_forest_visitor' ); if (!visitor) { visitor = crypto.randomUUID(); localStorage.setItem( 'aether_forest_visitor', visitor ); } } catch(e) { visitor = crypto.randomUUID(); } async function api(path, options = {}) { const r = await fetch( SUPABASE_URL + '/rest/v1/' + path, { ...options, headers: { apikey: SUPABASE_ANON_KEY, ...(options.body ? {'Content-Type': 'application/json'} : {}), ...(options.headers || {}) } } ); if (!r.ok) { throw new Error( 'The forest could not connect (' + r.status + ').' ); } return r.status === 204 ? null : r.json(); } function element(tag, cls, value) { const e = document.createElement(tag); if (cls) { e.className = cls; } if (value !== undefined) { e.textContent = value; } return e; } /* ========================================== LOAD APPROVED MESSAGES ========================================== */ async function load() { posts.textContent = 'Gathering whispers...'; try { const rows = await api( 'forest_messages?select=id,name,message,created_at,hearts&order=created_at.desc&limit=50' ); posts.replaceChildren(); if (!rows.length) { posts.textContent = 'The grove is quiet. Be the first to leave a whisper!'; return; } rows.forEach(p => { const card = element('article', 'post'); const head = element('div', 'post-head'); head.append( element('span', 'post-name', '❀ ' + p.name), element( 'time', 'post-time', new Date(p.created_at).toLocaleDateString() ) ); const msg = element( 'p', 'post-message', p.message ); const heart = element( 'button', 'heart', '♡ ' + p.hearts ); heart.type = 'button'; heart.setAttribute( 'aria-label', 'Heart message from ' + p.name ); heart.addEventListener( 'click', async () => { heart.disabled = true; try { const added = await api( 'rpc/forest_heart', { method: 'POST', body: JSON.stringify({ p_message_id: p.id, p_visitor_id: visitor }) } ); if (added) { p.hearts++; heart.textContent = '♥ ' + p.hearts; } else { heart.textContent = '♥ ' + p.hearts + ' · already loved'; } } catch(e) { heart.textContent = 'Try again'; } finally { heart.disabled = false; } } ); card.append(head, msg, heart); posts.append(card); }); } catch(e) { posts.textContent = e.message + ' Check your Supabase setup.'; } } /* ========================================== SUBMIT NEW MESSAGE ========================================== */ form.addEventListener( 'submit', async e => { e.preventDefault(); const name = $('forest-name').value.trim(); const message = $('forest-message').value.trim(); if (!name || !message) return; const btn = form.querySelector('button'); btn.disabled = true; status.textContent = 'Sending your whisper...'; try { await api( 'rpc/forest_post', { method: 'POST', body: JSON.stringify({ p_name: name, p_message: message }) } ); $('forest-message').value = ''; status.textContent = '✦ Your whisper was received! It will appear once approved.'; } catch(err) { status.textContent = err.message + ' Please try again.'; } finally { btn.disabled = false; } } ); /* ========================================== REFRESH MESSAGES ========================================== */ $('forest-refresh').addEventListener( 'click', load ); load(); })();
✧ WELCOME TO ✧

The Enchanted Archives

Every world begins with a story waiting to be discovered.
☾ ✧ ✦

WAIT LIST

Where every story awaits its turn

✧ CURRENT QUEUE ✧

☾ A Little Note ✧

Every tale takes time to bloom.
Please be patient while your request
makes its way through the enchanted grove.

Once your turn arrives, you shall be contacted beneath the stars.

/* ========================================== EDIT YOUR WAIT LIST HERE Change usernames, requests, and statuses ========================================== */ const waitlistPeople = [ { username: "Available Slot", request: "Any Request", status: "open" }, { username: "Available Slot", request: "Any Request", status: "open" }, { username: "Available Slot", request: "Any Request", status: "open" }, { username: "Available Slot", request: "Any Request", status: "open" }, { username: "Available Slot", request: "Any Request", status: "open" } ]; /* ========================================== ORIGINAL AUTOMATIC QUEUE SYSTEM ========================================== */ const queue = document.getElementById("ew-queue"); const statusLabels = { progress: "☾ IN PROGRESS", waiting: "⌛ WAITING", open: "✦ OPEN" }; if (queue) { queue.replaceChildren(); waitlistPeople.forEach((person, index) => { const slot = document.createElement("div"); slot.className = "ew-slot"; const number = document.createElement("div"); number.className = "ew-number"; number.textContent = String(index + 1).padStart(2, "0"); const details = document.createElement("div"); details.className = "ew-details"; const name = document.createElement("div"); name.className = "ew-name"; name.textContent = person.username; const type = document.createElement("div"); type.className = "ew-type"; type.textContent = person.request; details.append(name, type); const status = document.createElement("div"); const validStatus = Object.prototype.hasOwnProperty.call( statusLabels, person.status ) ? person.status : "waiting"; status.className = "ew-status " + validStatus; status.textContent = statusLabels[validStatus]; slot.append(number, details, status); queue.appendChild(slot); }); }
✧ WELCOME TO ✧

The Completed Sanctuary

Every story brought to life, every wish given a world of its own.
✧ WELCOME TO ✧

The Character Sanctuary

Every soul has a story waiting to unfold.

✧ WELCOME TO ✧

The Fandom Collection

Where beloved worlds and extraordinary stories intertwine.
✧ MEET THE CHARACTERS ✧
✧ WELCOME TO ✧

The Cinanara Series

Where magic, destiny, and extraordinary souls intertwine.
✧ WELCOME TO ✧

The Stand Alone Collection

Every character holds a world of their own.

✧ WELCOME TO ✧
The Enchanted Atelier
✿✧◆✧✿
Where imagination is woven into every design.
✿✧✿