> ## Documentation Index
> Fetch the complete documentation index at: https://docs.rbxweb.net/llms.txt
> Use this file to discover all available pages before exploring further.

# Codes Drop Portals

> Drop a magic portal in a random channel — a random eligible member wins a UGC item code, delivered in a private thread.

Codes Drop Portals is a moderator-run giveaway "campaign". The bot drops a clickable **magic portal** in a random channel from a list you choose. The first member to click *activates* it, others *join* within a short window, and the bot runs a suspenseful "checking entries → finding cheaters → selecting winner" sequence before handing one random eligible member a UGC item **code** in a private thread. It keeps dropping at random intervals until every code is claimed.

Open **Dashboard → Activity → Codes Drop Portals**.

<Info>
  This feature is **free** and requires **Moderator** access. Only one campaign can run per server at a time.
</Info>

## Lifecycle

<Steps>
  <Step title="Paste your codes & pick channels">
    In the **Portal & Codes** card, list the drop channels and paste your item codes (one item per line — see below). Configure every portal state (message, image, footer), timing, eligibility, winner thread, and logging in the cards beneath.
  </Step>

  <Step title="Press Start Campaign">
    The bot saves your settings, loads the codes, and begins dropping portals. The **Campaign & Codes** panel at the top of the view shows the live status, the channels in use, and the codes tracker.
  </Step>

  <Step title="Members activate & join">
    The portal appears in a random channel. The first click opens it; others join within the **join window**. If nobody clicks, the portal hops to another channel after the **move** timeout.
  </Step>

  <Step title="A winner is drawn">
    After the suspense steps, the bot applies the role gate and per-member cap, picks a random eligible member, claims one random available code, and delivers it in a **private thread** (inviting the winner, the server owner, and any extra users you listed). Members who don't win, are missing the required role ("burned"), or hit the code cap ("smashed") get a themed private message.
  </Step>

  <Step title="Repeat until codes run out">
    The next portal drops after a random interval — sooner when nobody won. When the last code is claimed the campaign completes automatically.
  </Step>
</Steps>

Use `/codes_drop_portals_control` in Discord to see the running campaign and stop it with a one-click red button.

## Item codes format

Paste one item per line in the **Item Codes** box. Put the item name first, then a colon, then the codes separated by commas:

```
Sword of Fire: ABC-123, DEF-456, GHI-789
Magic Hat: JKL-901, MNO-234
Golden Wings: PQR-567
```

The dashboard shows a live `N items · M codes` counter and flags problems as you type. Each code may be **up to 40 characters**; duplicate codes, empty items, and malformed lines are rejected. Codes are loaded into the campaign when you press **Start Campaign**, and are only ever visible to dashboard managers (in the tracker) and to the winner (in their thread).

## Portal & Codes card

<ResponseField name="Enable" type="toggle">
  Master toggle for the feature on this server.
</ResponseField>

<ResponseField name="Drop Channels" type="channel list (required, up to 15)">
  Portals appear in a random channel from this list and hop between them until activated.
</ResponseField>

<ResponseField name="Item Codes" type="textarea (required)">
  The items and codes to give away, in `Item: code1, code2` format (one item per line). Max 40 characters per code.
</ResponseField>

<ResponseField name="Random code selection" type="toggle (default on)">
  Each winner gets a random code from the pool. Turn off to hand codes out top-to-bottom in your pasted order — all of the first item's codes in sequence, then the second item's, and so on.
</ResponseField>

## Portal Embed

Every portal **state** — the message, colour, image and footer members see at each step of a drop — is editable in a row of tabs, each one a full WYSIWYG message/embed editor (Variables, Markdown, Emoji, Timestamp, Preview, Restore default, Clear — with author, fields, thumbnail, and **Random color** support). States are always embeds — they carry the state image, colour, and (on the drop) the **Activate** button — so there is no plain-message toggle in these tabs.

| Tab              | When it shows                                                                                                                                                                                                                                                                                    |
| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Portal appears   | The clickable "dust appeared" drop message                                                                                                                                                                                                                                                       |
| Portal opened    | After someone activates it — supports `{activated_by}` and the `{closing_in}` live countdown                                                                                                                                                                                                     |
| Winner selection | On the portal message when the draw ends — supports `{survivor}` and `{participants}`; its colour, image and footer also show during the closing suspense steps                                                                                                                                  |
| Portal log       | The public summary posted to the drops-log channel after each draw — supports `{portal_channel}`, `{portal_status}`, `{survivor}` and `{participants}`. Greyed out (non-selectable) until a **Public drops log channel** is picked in the Logging card; without one the post is skipped entirely |
| Did not win      | Private message to members who lost                                                                                                                                                                                                                                                              |
| Burned           | Private message to members missing the required role                                                                                                                                                                                                                                             |
| Smashed          | Private message to members who hit the code cap                                                                                                                                                                                                                                                  |

Each tab ships prefilled with the game's original copy and animated image — edit anything, or press **Restore default** to reset that tab. Leaving an image blank simply sends the embed without one.

Footers are yours: the drop / opened / Winner selection / Portal log tabs prefill `🔷 Max codes/user: {codes_per_member}`, `🔷 Portal ID: {portal_id}` and `🔷 Codes left: {codes_left}`, with the bot's avatar as the default footer icon — delete a line (or the icon) and it simply isn't shown. Selecting a **Required Role** under the first tab automatically adds `🔒 Role Required: {required_role}`. The campaign tokens `{portal_id}`, `{codes_left}`, `{codes_per_member}`, `{required_role}` (greyed out in the Variables popup until a role is selected), `{server}` and `{member_count}` resolve in **every** tab — see [Placeholders](/placeholders).

Eligibility lives in a compact strip under the first tab's editor:

<ResponseField name="Required Role" type="role picker (optional)">
  When set, members without the role are "burned" and cannot win. There is no separate switch — selecting a role enables the requirement, clearing it disables it.
</ResponseField>

<ResponseField name="Codes per member" type="number">
  The maximum number of codes a single member can win in this campaign. `0` = unlimited. Members who have hit the cap are "smashed".
</ResponseField>

<Note>
  When the **Portal & Codes** master toggle is off, every other card on the page (including presets and Start Campaign) is greyed out and non-editable. The campaign tracker stays active so a running campaign can still be ended.
</Note>

<Note>
  **The form is a compose-and-launch surface.** Every value resets to its default whenever you enter the menu or refresh the page — your composed settings are captured in the campaign snapshot when you press **Start Campaign**, and running campaigns are never affected. To keep a configuration for later, use **Save as Preset** and bring it back with **Fill from Preset**.
</Note>

## Timing

<ResponseField name="Join window (seconds)" type="number">
  How long members have to join after the portal is activated.
</ResponseField>

<ResponseField name="Move portal after (seconds)" type="number">
  If nobody activates the portal in this time, it is deleted and re-posted in another random channel.
</ResponseField>

<ResponseField name="Drop interval min / max (minutes)" type="number">
  After someone wins, the next portal drops after a random time in this range.
</ResponseField>

<ResponseField name="No-winner retry min / max (minutes)" type="number">
  When nobody wins, the bot retries sooner using this (usually shorter) range.
</ResponseField>

<ResponseField name="Suspense delays (seconds)" type="number">
  The "checking entries", "finding cheaters", and "selecting winner" steps each pause for the configured number of seconds for dramatic effect.
</ResponseField>

## Winner Thread

<ResponseField name="Winner Message" type="WYSIWYG editor (requires {code})">
  The message posted in the winner's private thread, composed in the full WYSIWYG message/embed editor — image and footer included (the winner gif and the `🔷 Portal ID: {portal_id}` footer ship as editable prefills). Flip the **Embed** toggle for a plain message instead. Supports placeholders — see [Placeholders](/placeholders): `{user}`, `{user_name}`, `{item}`, `{code}`, `{portal_id}`, `{codes_left}`, `{server}`. **`{code}` is required** (shown in red in the Variables popup) — it's how the winner receives their code, so the campaign won't start without `{code}` somewhere in the message (the default template is `Congrats {user}! 🎉 You made it through the portal!` / `{item}: {code}`). The only thing the game adds automatically is a **Jump to the portal** link.
</ResponseField>

<ResponseField name="Thread Channel" type="channel picker (optional)">
  The channel the private thread is opened under. Leave empty to use the channel the portal dropped in.
</ResponseField>

<ResponseField name="Auto-archive" type="dropdown">
  How long the thread stays active before archiving (1 hour, 1 day, 3 days, or 7 days).
</ResponseField>

<ResponseField name="Also invite (user IDs)" type="user-ID list (up to 10)">
  Extra staff auto-added to every winner thread. The winner and server owner are always added.
</ResponseField>

## Logging

<ResponseField name="Public drops log channel" type="channel picker (optional)">
  Posts a public summary of each drop (winner + item, **never the code**) — the message is editable in the **Portal log** tab of the Portal Embed card. Without a channel, no log is posted and the tab is greyed out.
</ResponseField>

<ResponseField name="Show next-drop time in public log" type="toggle (default on)">
  Includes the "Next portal appearing \<in N>" countdown in the `{portal_status}` token of the Portal log message.
</ResponseField>

<ResponseField name="Staff mod-log channel" type="channel picker (optional)">
  A verbose, staff-only log of each drop including the delivered **code**, remaining counts, and who was burned/smashed. Every drop is also written to the server's per-guild log file (with the winner and code) for auditing.
</ResponseField>

<Note>
  Both log messages are delivered through a **channel webhook** under the bot's own name and avatar — webhook sends have their own rate-limit budget, sparing the bot's request quota. This needs the **Manage Webhooks** permission (included in the standard invite); without it the bot falls back to a normal message.
</Note>

<Note>
  **Portal images must be on a public URL.** Default portal images are served by the bot's API host (`web_public_url` in `settings_bot.json`, default `api.rbxweb.net`). Discord cannot fetch `localhost`, so during local testing the default images render in Discord only if `web_public_url` points at a publicly reachable host. Custom URL / library images you set yourself work as long as they're public.
</Note>

## Campaign & Codes panel

The panel at the **top** of the view is the live control centre for a running campaign:

* **Status** — a pill shows *Idle*, *Running*, or *Paused*, alongside the campaign code, start time, and next-drop time. Each campaign has its own code — the first five digits of your server id followed by four random digits (e.g. `887614827`) — shown in the dashboard and on the portal embed footer (as **Portal ID**).
* **Channels in use** — which channels drops appear in (shown as *Random from #a, #b…* when several are selected, or *#channel (fixed)* for a single one), plus the winner-thread, public drops-log, and staff mod-log channels.
* **Pause Drops / Resume Drops** — temporarily halt drops without ending the campaign (the live portal is removed and no new portals drop while paused), then resume dropping the remaining codes. While paused you can't start a second campaign — resume or end this one first.
* **End Campaign** — terminate the campaign entirely. Unclaimed codes stay in the tracker for auditing.

### Recent Campaigns

Below the live status is a **Recent Campaigns** list — the last few campaigns for your server as collapsible items, newest first. The server keeps **up to 6 campaigns** (the running one plus the five most recent finished ones); older campaigns and their codes are removed automatically when you start a new one.

Each item shows the campaign code, its status badge (*Running* / *Paused* / *Ended* / *Completed*), when it ran, and a `claimed / left / total` summary with a usage bar. Expand an item to see that campaign's **codes tracker**: every code with its status (`available` / `claimed`) and who won it, with filter (all / available / claimed) and sort controls. The tracker paginates — pick **10 / 25 / 50 / 100** per page. Ended campaigns stay listed so you can audit which codes went out.

Finished campaigns also have a **delete** (trash) button on their row to remove that record and all of its codes from the history. The currently-running campaign can't be deleted — end it first.

## Presets (Premium)

<Info>
  Saving and filling Codes Drop Portals presets requires **Premium** tier — the same as Embed Builder and Competition presets. Free servers see the preset bar with an upgrade prompt.
</Info>

Use **Save as Preset** (next to *Save Settings*) to store the current configuration — channels, every portal-state editor, timing, eligibility, winner thread, and logging — as a reusable named preset. The **Fill from Preset** bar at the top lets you load a saved preset back into the form, then tweak and save or start. Presets store the configuration only, not the item codes (those are pasted fresh per campaign). The number of presets you can save depends on your tier.

## Slash commands

<ResponseField name="/codes_drop_portals_control" type="moderator">
  Shows the running campaign (status, campaign code, started time, codes claimed/remaining, next drop) in an ephemeral embed with a red **Stop Campaign** button. Stopping removes the live portal and ends the campaign; unclaimed codes stay in the tracker.
</ResponseField>

<Note>
  The bot needs **Manage Messages** (to move/clear the portal button) and **Create Private Threads** (to deliver winner codes). These are included in the standard invite permissions — no extra setup is required.
</Note>
