Welcome to
PromptNest Docs
Everything you need to understand, run, extend, and contribute to PromptNest — a community-driven platform for sharing, discovering, and remixing AI prompts.
What is PromptNest?
PromptNest is a full-stack, community-powered prompt-sharing platform built entirely with vanilla JavaScript, HTML, CSS, and Firebase. It was designed from the ground up to be beginner-friendly — no build tools, no bundlers, no frameworks — just open files you can run directly in a browser after connecting your own Firebase project. Despite its simplicity, it is packed with production-grade features including real-time search, an authenticated voting system, private collections, a live leaderboard, and a one-click "Send to AI" integration.
The idea behind PromptNest is straightforward: AI prompts have become one of the most valuable pieces of intellectual content on the internet, yet there is no clean, distraction-free place for everyday people to share and rediscover the best ones. PromptNest fills that gap. Users can browse an ever-growing feed of community prompts, filter them by category (Coding, Social Media, Education, Fun), search in real time, vote on the ones they find most useful, save their favourites into personal private collections, and send any prompt directly to Claude, ChatGPT, Gemini, Perplexity, or any custom AI tool — all in a single click.
Authentication is handled through Firebase Google Sign-In, so there are no passwords to manage. Every interaction — likes, dislikes, saves, edits — is persisted in Firestore, Google's serverless NoSQL cloud database, which means your data is live and globally consistent the moment it is written. The frontend never talks to a traditional server; the browser talks directly to Firebase via the Firebase JavaScript SDK.
firebase.js. No API keys are ever committed to the code — you replace the placeholder values with your own before running.Our Vision
The internet is in the middle of a profound shift. Generative AI has gone from a curiosity to an indispensable daily tool for millions of people, and the quality of output these tools produce is almost entirely determined by the quality of the instruction you give them — the prompt. A great prompt is the difference between a generic, forgettable response and a precise, genuinely useful one. Prompts are, in a very real sense, programs written in natural language. They encode expertise, context, intent, and nuance in a form that any AI model can execute.
Despite this, prompt knowledge remains fragmented. The best prompts are hidden in private notes apps, buried in Discord servers, trapped in individual ChatGPT histories, or shared as screenshots on Twitter. There is no central, beautiful, searchable library where a developer can find a prompt that will help them debug faster, where a teacher can find prompts that will help their students learn, or where a marketer can find prompts for social media copy that actually converts. PromptNest is our answer to that problem.
Our vision is to build the GitHub of AI prompts — a living, breathing, community-curated library of high-quality instructions for AI systems. Just as GitHub democratised access to code, PromptNest aims to democratise access to prompt expertise. Beginners should be able to find prompts that immediately make their AI experience better. Experts should be able to share their hard-won prompt engineering knowledge with the world and get credit for it. And everyone should be able to build on each other's work, remixing and improving prompts the way open-source contributors iterate on code.
We also believe deeply in openness and simplicity. PromptNest is intentionally built without heavyweight frameworks or complex deployment pipelines. A student learning to code should be able to open the files, read through them, and understand exactly what is happening. Every function is named clearly, every data flow is documented, and every design decision is made with the next developer in mind. The goal is not just a product — it is also a reference implementation that shows how much you can build with just a browser, a text editor, and a free Firebase account.
Quick Start
Getting PromptNest running locally takes under five minutes. There is no npm install, no build process, and no server to configure. All you need is a Firebase project, a text editor, and a browser. Follow the steps below precisely and you will have a fully working instance of PromptNest pointed at your own Firestore database.
Step 1 — Create a Firebase Project
Navigate to console.firebase.google.com and click Add project. Give it a name (e.g. "promptnest"), disable Google Analytics if you prefer, and click Create project. Once the project is provisioned, you will land on the project dashboard.
Step 2 — Register a Web App
On the project dashboard, click the </> (Web) icon to register a new web application. Give the app any nickname you like (e.g. "promptnest-web") and click Register app. Firebase will display a firebaseConfig object containing your apiKey, projectId, authDomain, and other identifiers. Copy this entire object — you will need it in the next step.
Step 3 — Paste Your Config
Step 4 — Enable Google Authentication
In the Firebase Console, go to Build → Authentication → Sign-in method and enable Google. Set a public-facing project name and a support email address when prompted. Save the changes. This is the only sign-in provider PromptNest uses.
Step 5 — Create a Firestore Database
Go to Build → Firestore Database and click Create database. Select Start in test mode for initial development (you will tighten the rules later), choose a region close to your users, and click Done. The database will be provisioned within a few seconds.
Step 6 — Apply Security Rules
Navigate to Firestore → Rules and paste the rules from the Security Rules section of this documentation. Publish the rules.
Step 7 — Open index.html
Open index.html in any modern browser. PromptNest will load, connect to your Firebase project, and be fully operational. For the best development experience, use the Live Server extension in VS Code, or any static file server such as python -m http.server.
file:// in some browsers due to CORS restrictions. Always serve the files through a local server (localhost) or deploy to a hosting provider like Firebase Hosting or Netlify.Tech Stack
PromptNest was deliberately built with the smallest, most accessible technology footprint possible. The goal was to produce a genuinely full-featured product that a beginner could read, understand, and modify without first needing to learn React, Next.js, Webpack, TypeScript, or any other layer of abstraction. Every dependency is loaded from a CDN at runtime — there is no package.json, no node_modules, and no build step of any kind.
| Layer | Technology | Version | Role |
|---|---|---|---|
| Frontend Language | Vanilla JavaScript (ES2020+) | Native | All application logic, DOM manipulation, event handling, state management |
| Markup | HTML5 | Native | Page structure and semantic layout for all 4 pages |
| Styling | CSS3 with Custom Properties | Native | Entire design system, dark theme, responsive layout, animations |
| Database | Cloud Firestore | v10 compat | Storing prompts, votes, collections, collection items |
| Authentication | Firebase Authentication | v10 compat | Google Sign-In, session management, user profile |
| Hosting (optional) | Firebase Hosting | — | Static site deployment with SSL and global CDN |
| Display Font | Syne | Google Fonts | All headings, titles, buttons |
| Body Font | DM Mono | Google Fonts | Body text, code, metadata, labels |
The decision to use Firebase was made deliberately. Firestore provides real-time data, atomic batch writes, server-side timestamps, and generous free-tier quotas (50,000 reads/day, 20,000 writes/day, 1 GB storage on the Spark plan). For a community prompt-sharing site, these limits are more than sufficient for a project with hundreds of daily active users. Firebase Authentication eliminates the need to build any login infrastructure — OAuth with Google takes two function calls. The compat SDK (v10) was chosen over the tree-shakable modular SDK because it requires zero build tooling and works directly in a <script> tag.
File Architecture
The project follows a flat multi-page architecture. Each HTML page is a self-contained document that loads its own page-specific JavaScript file. Shared functionality — Firebase initialisation and authentication — is split into two files (firebase.js and auth.js) that are loaded before the page-specific scripts on every page. The single shared stylesheet (style.css) contains the complete design system for all pages.
Script Load Order
Every page loads scripts in the same order: firebase.js first, then auth.js, then the page-specific script. firebase.js dynamically loads the Firebase SDK from the Google CDN, initialises the app, and fires a custom DOM event called firebase-ready when complete. Page scripts listen for this event before running any Firestore queries. auth.js listens for firebase-ready and then calls onAuthStateChanged(), firing a second event called auth-changed with the current user (or null) as its payload. This event-driven boot sequence guarantees that no script ever calls Firestore before the SDK is ready.
Database Schema
PromptNest uses five Firestore collections. Firestore is a document-oriented database — each collection holds documents, and each document is a map of key-value pairs. There are no joins, no foreign keys, and no schemas enforced by the database itself. Document IDs are either auto-generated by Firestore or deterministically constructed by the application (as in votes and collection items) to guarantee uniqueness and enable idempotent writes.
prompts
| Field | Type | Description |
|---|---|---|
| title | string | Short, descriptive title of the prompt (max 80 chars) |
| content | string | Full prompt text (max 1000 chars) |
| category | string | One of: Coding, Social Media, Education, Fun |
| likes | number | Total like votes. Updated via FieldValue.increment() |
| dislikes | number | Total dislike votes. Updated via FieldValue.increment() |
| copies | number | Number of times the Copy button has been clicked |
| userId | string | Firebase Auth UID of the prompt author |
| author | string | Display name of the author at time of publishing |
| createdAt | Timestamp | Server-side creation timestamp |
votes
Document ID format: {promptId}_{userId} — deterministic, so only one vote doc per user per prompt can ever exist in the database, making duplicate votes physically impossible at the storage level.
| Field | Type | Description |
|---|---|---|
| promptId | string | ID of the voted-on prompt |
| userId | string | Firebase Auth UID of the voter |
| voteType | string | "like" or "dislike" |
| updatedAt | Timestamp | Last updated (set with merge:true, so switching votes overwrites) |
collections
| Field | Type | Description |
|---|---|---|
| userId | string | Owner's Firebase Auth UID |
| name | string | User-chosen name for the collection |
| createdAt | Timestamp | When the collection was created |
collectionItems
Document ID format: {promptId}_{collectionId} — ensures the same prompt cannot be saved twice into the same collection.
| Field | Type | Description |
|---|---|---|
| collectionId | string | ID of the parent collection |
| promptId | string | ID of the saved prompt |
| userId | string | Owner's Firebase Auth UID |
| addedAt | Timestamp | When the item was added to the collection |
Security Rules
Firestore Security Rules are server-side access control policies that run before any read or write reaches your database. Even though PromptNest has no traditional backend server, these rules ensure that unauthenticated users cannot write data, that users cannot vote twice, and that private collections are visible only to their owner. Copy the rules below into Firebase Console → Firestore → Rules and publish.
All Features
PromptNest ships with a comprehensive set of features across four pages. Below is the complete feature inventory as of version 4.0, along with which file implements each one.
| Feature | Where | Status |
|---|---|---|
| Browse all prompts (newest first) | index.html + script.js | Live |
| Real-time search (title, content, category) | index.html + script.js | Live |
| Category filter pills | index.html + script.js | Live |
| Add new prompt (auth required) | index.html + script.js | Live |
| Edit own prompt | index.html + script.js | Live |
| Delete own prompt | index.html + script.js | Live |
| Like / Dislike (one vote per user) | script.js + Firestore | Live |
| Copy to clipboard + copy counter | script.js | Live |
| Full-screen prompt preview modal | script.js / leaderboard.js | Live |
| Send to AI (Claude, ChatGPT, Gemini, Perplexity, Custom) | script.js / leaderboard.js | Live |
| Save to private collection | script.js + Firestore | Live |
| Google Sign-In / Sign-Out | auth.js + firebase.js | Live |
| User profile page (stats, prompts) | profile.html + profile.js | Live |
| Change display name (updates all prompts) | profile.js | Live |
| Change profile picture | profile.js | Live |
| Collections accordion with rename/delete | profile.html + profile.js | Live |
| Remove prompt from collection | profile.js | Live |
| Leaderboard — Top Liked tab | leaderboard.js | Live |
| Leaderboard — Top Copied tab | leaderboard.js | Live |
| Leaderboard category filter | leaderboard.js | Live |
| Top Contributors ranking | leaderboard.js | Live |
| Mobile-responsive layout | style.css | Live |
| Loading spinners on all async ops | All pages | Live |
| Toast notifications (success / error) | All pages | Live |
| Optimistic UI updates on votes | script.js | Live |
| XSS prevention (escapeHTML) | All page scripts | Live |
The Voting System
The voting system is one of the most carefully engineered parts of PromptNest because it must satisfy several competing requirements simultaneously: it must be fast (instant UI feedback), accurate (no duplicate votes, no lost votes), consistent across devices (the same vote state regardless of which device you log in from), and robust under failure (if the network request fails, the UI should roll back cleanly).
How it Works
Every vote is stored as a Firestore document in the votes collection. The document ID is deterministically constructed as {promptId}_{userId}. This is the key insight: because the document ID encodes both the prompt and the user, there is physically only one slot in the database where a user's vote on a specific prompt can live. Writing a second vote to the same slot simply overwrites the first — it does not create a second record. This makes duplicate votes structurally impossible, not just logically prevented.
When a user clicks Like or Dislike, the application immediately updates the local state and re-renders the cards (optimistic update), making the UI feel instant. It then sends a Firestore batch write — a single atomic operation that updates both the prompt's counter field and the user's vote document at the same time. If the batch succeeds, the optimistic update is confirmed. If it fails (e.g. network error), the previous values are restored and an error toast is shown.
The Infinite-Like Bug (Fixed in v4)
Previous versions had a subtle race condition: getPrompts() would call renderPrompts() before loadUserVotes() had finished. This meant cards were initially rendered showing no vote state for the logged-in user — so clicking Like appeared to work even if the user had already voted, and a page refresh would reset the counter in the UI. The fix in v4 ensures that loadUserVotes() is always awaited inside getPrompts() before renderPrompts() is called, so the very first render always reflects the correct voted state. Additionally, a votingLocks Set prevents spamming the Like button while a Firestore write is in-flight.
likes, increments dislikes, and updates the vote document in a single batch — no double-counting is possible.Collections
Collections are personal, private folders that let signed-in users organise their saved prompts. No other user — not even the prompt's original author — can see your collections. They exist purely for your own organisation. You can create as many collections as you want, name them anything (e.g. "Coding helpers", "Marketing copy", "My favourites"), save any prompt from the public feed into them, rename them at any time, remove individual prompts from them, or delete entire collections when you no longer need them.
Collections are implemented across two Firestore collections. The collections collection stores the collection metadata (name, owner, creation date). The collectionItems collection stores the individual saved-prompt relationships. The item document ID is {promptId}_{collectionId} — deterministic, so the same prompt cannot be accidentally saved twice into the same collection. All collection reads and writes are protected by Firestore Security Rules that enforce owner-only access, meaning a user can only query their own collections, never anyone else's.
On the Profile page, your collections are displayed in an accordion — each collection is a collapsible section. Clicking on a collection name expands it and lazily loads the prompts inside it on first open, avoiding unnecessary Firestore reads on page load. Each saved prompt shows a Copy button for instant clipboard access and a Remove (✕) button to detach it from the collection without deleting the original public prompt.
Send to AI
The "Send to AI" feature is the most directly useful thing PromptNest does. Clicking the 🤖 AI button on any card (or the "Send to AI" button inside the prompt preview modal) opens a modal with tiles for every major AI assistant. Clicking a tile does two things simultaneously: it copies the prompt text to your clipboard, and it opens the AI platform in a new browser tab. On platforms that support URL-based prompt injection (ChatGPT and Perplexity), the prompt is automatically pre-filled in the chat input. On platforms that do not (Gemini and Claude), the prompt is still in your clipboard so you can paste it immediately with Ctrl+V / Cmd+V.
| Platform | URL Strategy | Auto-fill |
|---|---|---|
| 🟠 Claude | claude.ai/new?q=... | Yes |
| 🟢 ChatGPT | chat.openai.com/?prompt=... | Yes |
| 🔵 Gemini | gemini.google.com/app | Clipboard |
| 🟣 Perplexity | perplexity.ai/?q=... | Yes |
| ✏️ Custom | User-supplied URL | Clipboard |
The Custom tile lets you add any AI tool that is not in the default list — Mistral, Llama, Cohere, or any internal company AI platform. You enter the AI's name and its base URL, and PromptNest will open it in a new tab while keeping the prompt in your clipboard. Custom platform preferences are not currently persisted between sessions, but this is planned for a future update.
Key Functions
Every public function in PromptNest follows a consistent naming convention. Functions that talk to Firestore are async. Functions that only manipulate the DOM are synchronous. Functions that open or close UI elements are named open* / close*. Below is a reference of the most important functions and where to find them.
| Function | File | Description |
|---|---|---|
| getPrompts() | script.js | Fetches all prompts ordered newest-first. Awaits loadUserVotes() before rendering. |
| renderPrompts() | script.js | Applies category filter + search query to the in-memory list and builds cards. |
| buildCard(prompt) | script.js | Constructs and returns a single prompt card DOM element with all event listeners attached. |
| castVote(id, type) | script.js | Handles like/dislike. Uses votingLocks to prevent spam, optimistic update, and batch commit. |
| addPrompt() | script.js | Validates form, writes new prompt to Firestore, prepends to local list. |
| editPrompt() | script.js | Reads the edit modal fields and updates the Firestore document in place. |
| deletePrompt(id) | script.js | Prompts for confirmation, deletes from Firestore, removes from local list. |
| saveToCollection() | script.js | Writes a collectionItem document with merge:true to prevent duplicates. |
| loginUser() | auth.js | Opens the Google Sign-In popup via Firebase Auth. |
| logoutUser() | auth.js | Signs the current user out of Firebase. |
| getCurrentUser() | auth.js | Returns the currently signed-in Firebase user object, or null. |
| updateAuthUI(user) | auth.js | Toggles the login button / user chip based on auth state. Works on all pages. |
| saveDisplayName() | profile.js | Updates Firebase Auth profile + batch-updates author field on all user's prompts. |
| setupAvatarChange() | profile.js | Reads a chosen image file, converts to base64, saves as Firebase Auth photoURL. |
| loadCollections() | profile.js | Fetches all collections for the current user and renders the accordion. |
| getLeaderboard() | leaderboard.js | Fetches top 100 prompts ordered by likes from Firestore. |
| escapeHTML(str) | All scripts | Sanitises a string for safe innerHTML insertion. Prevents XSS attacks. |
Changelog
A full history of every version of PromptNest, from the initial prototype to the current release. Each version built on the last, adding features in a deliberate order: first a working foundation, then authentication, then rich interactions, then social features, then advanced personal organisation tools.
copies field tracked on every prompt. Fixed the long-standing infinite-like race condition by moving loadUserVotes() inside getPrompts() before the initial render. Added votingLocks Set to prevent double-click spam. Updated Firestore security rules to include collections and collectionItems collections.FAQ
Answers to the questions that come up most often when setting up and extending PromptNest.
file:///, the browser's origin is null, which is not an authorised domain. The fix is to serve the files through a local web server. The easiest options are: the Live Server VS Code extension (right-click index.html → "Open with Live Server"), Python's built-in server (python -m http.server in the project directory), or Node's npx serve. You also need to add localhost to the list of authorised domains in Firebase Console → Authentication → Settings → Authorised domains.
<option> to the category <select> in the Add Prompt and Edit Prompt modals in index.html. Second, add a corresponding filter <button> with a data-category attribute to the filter pills in index.html and leaderboard.html. Third, optionally add a colour variant for the new category badge in style.css, following the same pattern as the existing .card-badge[data-cat="Coding"] rules. That's all — no backend changes needed.
orderBy with a where clause, and it also requires a single-field index for ordering by non-default fields like copies. If you see an error in the browser console mentioning "The query requires an index", Firestore will include a direct link in the error message that you can click to auto-create the required index in your Firebase Console. Index builds typically take 1-2 minutes. The leaderboard.js code already handles this gracefully — if the copies index is not ready, it falls back to sorting the liked list client-side by the copies field.
maxlength attributes) and are visible via the live character counter that appears below the textarea. They are easy to change — just update the maxlength attribute in the HTML and adjust the counter label text in the JavaScript. There is no server-side enforcement beyond Firestore's 1 MB per-document limit, which you are extremely unlikely to hit with text-only prompts.
Project Team
PromptNest is a student-led passion project. It began as a personal side project to solve a real problem — the difficulty of finding and reusing great AI prompts — and grew into a full-featured platform through iterative development across four major versions. The project is open to contributions from anyone who wants to add features, fix bugs, improve the documentation, or extend the design system.
This project was built in an unconventional way: every line of code was written collaboratively between a human product owner and Claude, Anthropic's AI assistant. The human defined the requirements, made the design decisions, caught bugs, and steered the product direction. Claude translated those requirements into working code, fixed issues, refactored for clarity, and maintained consistency across the growing codebase. The result is a demonstration that ambitious web applications can be built without deep programming expertise, as long as you know what you want to build and can communicate it clearly.