cycling-presence
v1.0.0
Published
Cycle Discord rich presence with a tiny, library-agnostic timer. Seyfert + discord.js adapters included.
Maintainers
Readme
60_000 ms. A loop. A healthier bot profile.
[● now playing] ──▶ [♪ listening] ──▶ [◉ watching] ──▶ [⚑ competing] ──▶ loops forevercycling-presence
Cycle rich presence for your Discord bot on a silent timer.
tiny - zero deps - seyfert + discord.js
the problem
Presence code is boring, repetitive, and always the same shape:
setTimeout(() => client.gateway.setPresence({ activities: [{ name: "Listening to lofi" }] }), minutes * 1000);cycling-presence wraps the loop so you only write the lineup.
install
bun add cycling-presence
npm install cycling-presenceusage
import { CyclingPresence, seyfertPresence, playing, listening, streaming } from "cycling-presence";
await client.start();
new CyclingPresence({
presences: [
playing("Nazha Music"),
listening("Nazha Radio"),
streaming("Absurd Cafe", "https://twitch.tv/knownasrazi"),
watching(`${serverCount} servers`), // build it dynamically each cycle? see below
],
setPresence: seyfertPresence(client),
interval: 60_000,
status: "online",
}).start();Works with discord.js too:
import { CyclingPresence, discordJsPresence } from "cycling-presence";
new CyclingPresence({
presences: ["Playing with slash commands", listening("lo-fi vibes")],
setPresence: discordJsPresence(client), // discord.js >=14
interval: 45_000,
}).start();live data
The onCycle hook runs before each change - perfect for up-to-date server counts:
const cp = new CyclingPresence({
presences: [playing("with /slash"), listening("the radio")],
setPresence: seyfertPresence(client),
onCycle: (presence) => {
// presence.activity.name is already finalized; index is the second arg
},
});
cp.set(0); // force the first one nowapi
| member | does |
| ------ | ---- |
| new CyclingPresence(options) | engine instance |
| .start() | apply first + cycle every interval ms |
| .stop() | pause rotation |
| .next() | manually advance one step |
| .set(index) | jump to a specific presence |
| .add(...) | append to the lineup |
| .clear() | wipe the lineup |
| .current | the active presence (or null) |
| .running / .length | state |
| .destroy() | stop + clear |
activity builders
| shorthand | Discord type | notes |
| --------- | ------------ | ----- |
| playing(name) | playing | |
| streaming(name, url) | streaming | url required |
| listening(name) | listening | |
| watching(name) | watching | |
| competing(name) | competing | |
Or pass raw objects - full control:
{
activity: { name: "a custom state", type: 5 },
status: "dnd",
}options
| option | default | meaning |
| ------ | ------- | ------- |
| interval | 60_000 | ms between changes |
| random | false | shuffle instead of in order |
| status | - | fallback user status applied to every presence |
| setPresence | required | how the presence reaches Discord |
| onCycle | - | (presence, index) => void |
development
git clone https://github.com/knownasrazi/cycling-presence.git
cd cycling-presence
bun install
bun test
bun run build
bun run lintlicense
set the playlist. forget the loop.
