Lightingale Documentation

Welcome to the documentation hub of the Lightingale Community. See the sidebar for the list of documentations available.

To see a list of active projects not included here, feel free to visit the project website for the whole list, or GitHub pages host for projects hosted on GitHub.

Site powered by mdBook.

Clearnet CDNs are generously provided by Cloudflare, GCoreLabs, CloudFront, CacheFly and Fastly free of charge.


For shorter descriptions, see Lightingale Services List.

  • Lavender: Reddit-like Fediverse instance for the MLP fandom and LTGC.
  • Liquestria: Invite-only semi-anarchy Minecraft survival multiplayer on mixnet.
  • Matrix services: Managed Matrix bridges and more.



  • Gel: ⛏ Rolling server bases, batteries included.
  • Hyacinth: 💨 Build web projects with speed.
  • Iceflakes: ❄️ Offline Linux installer images for everyone.
  • Nightglow: 🌙 Yet another Cloudflare WARP client wrapper.
  • shx: 📜 Bash/PDKSH shell action executor.
  • Stratus: ☕️ JavaScript runtime containers (Deno, Bun, Node.js).

Data sheets

  • midi-db: 🎹 Data concerning MIDI standards.
  • Raven: 💨 Lightning-fast intuitive typing.
  • SynPix: 👾 The open pixel font for embedded LCDs.


  • Ensemble: 🎶 A synth framework in Rust.


  • Floaty: ☁️ Prevent Caddy loopbacks... Without traceability.
  • Pulsewave Desktop: 🔊 Universal modularized cross-device audio connections (Linux, Windows, macOS).
  • Trampoline: 🥁 Chat sockets to Matrix bridge.
  • Usher: 🚸 Rolling sticky hash load balancing on Caddy.



  • Cotton: 💬 PSK-authenticated Minecraft chat socket.
  • Pulsewave Android: 🔊 Universal modularized cross-device audio connections (Android).


  • Berry: 🍇 Simple port exposure tunnel for stream entropy manipulation.
  • Bread: 📦 Unified framework to stream binary in blocks.
  • Crystal Quartz: 🎨 A colour palette generation system.
  • Ditzy: 📬 Reconstruct stateful sockets over stateless messages.
  • Eclipsed: 🔊 The Royal Canterlot Voice for SSE/EventSource.
  • Flitter: 🗂 A file viewer for the web, with minimal requirements.
  • Heartstrings: 📑 Create and modify lyrics and subtitles as quick as possible.
  • Inkwell: 📒 The grand central terminal / Le grand terminal central.
  • Leaflet: ⚠️ Stock Caddy error pages, free for anyone to use if kept credits.
  • Lightfelt: 🕸 A collection of JS snippets for the Web and Deno.
  • Mint: 🌱 Easy-to-configure load balancing serverless functions.
  • Minuette: ⏳ Intercept, inspect, orchestrate.
  • Octavia: 🎻 Event-driven multi-standard MIDI state-tracking library.
  • Painted Palette: 🎨 Painting palettes, one pixel at a time.
  • Parchment: 📃 Mark-down based client-side page generator.
  • Rochelle: 🔪 Stream chunk splitting.
  • Scope: 🔭 Easy-to-setup WireGuard meshing.
  • Silk: 🕸 Bringing the fandom together.
  • Snowy: ❄️ The BroadcastChannel polyfill for Firefox 29+ and Chrome 5+.
  • Track me, senpai!: 🍑 Just giving thanks to your visitor sharing their everything with you.
  • Twinkle Sprinkle: 📜 Task wait signals and simple WAL.
  • WingBlade: ☁️ One codebase, multiple runtimes.

Privacy policy

As of 6th Oct 2023, these terms are not yet in effect.

By using services provided by the Lightingale Community, you agree to the following terms.


Unless stated explicitly otherwise, the following policy will be applied to any web-based service run by the Lightingale Community.

TL;DR, we have access to all of the data the client implementation chooses to share with us, but unless an error is caused or you explicitly want us to, none of the data would be stored.


Below is the list of data accessible by us if provided, on the server-side without user interaction.

  • When accessing via clearnet, the IP address of your exit.
  • When accessing via clearnet, IP packet fingerprints. (e.g. TCP fingerprint, UDP fingerprint)
  • TLS connection fingerprint, when connected via TLS.
  • Standardized client-identifying headers, if provided. Visit MDN for more information. Below is a list of possible headers, and may not include all headers.
    • Accept: Which types of content is accepted by the client.
    • Accept-Encoding: Encoding schemes accepted by the client, usually compression algorithms.
    • Accept-Language: Languages expected by the client.
    • Authorization: Tokens proving client's identification.
    • Origin: The URL of request's origin.
    • Referer: The initiator URL of each request.
    • Sec-Fetch-Dest: The initiator type of each request.
    • Sec-Fetch-Mode: Mode applied on requests.
    • Sec-Fetch-Site: Relationship between requested resource and source.
    • User-Agent: Implementation identification string provided by the client.
    • X-Forwarded-For, X-Real-IP: If behind a reverse proxy, the connecting IP address observed by the reverse proxy. These headers are almost always stripped, spoofed or generalized on reverse proxies we have control of however.
  • Client hints, sent by Chromium-based browsers (e.g. Google Chrome). Below is a list of headers sent unconditionally by Chromium-based browsers. To prevent us from receiving these headers, please switch to a browser that isn't based on Chromium.
    • Sec-CH-UA: Array of implementation identification strings provided by the client.
    • Sec-CH-UA-Mobile: If the client runs on mobile platforms (e.g. Android, iOS).
    • Sec-CH-UA-Platform: The platform running the client, usually OS families.
  • All other headers clients choose to provide.
  • When the service involves server-side dynamically-generated content, basic cookies allowing said service to function properly.

We also have access to data you explicitly choose to share with us. They may be in cleartext or in their encrypted form.



  • Data explicitly stored by users will likely persist until takedowns.
  • During suspected infiltrations, we will use any information accessible to identify and exterminate unauthorized access. Data stored during this period will be removed as soon as related investigations are finished.
  • We do not share any information with any third-parties.
  • Data requests from individuals and law enforcement agencies will be assessed before any action is taken. See the data request section for details.


Unless overriden, these uses do not store data.

  • To deny access from clients we deem as unfit of service (WAF), we will use Origin, Referer, Sec-CH-UA, Sec-Fetch-Site, User-Agent, observed client IP address (if on clearnet/behind reverse proxies), IP packet fingerprints (if on clearnet) and TLS fingerprint.
  • To conserve bandwidth whenever we can, we will use Accept-Encoding.
  • To serve content to client's expectation, we will use Accept.
  • To distinguish between sessions if essential to the service client accesses, Authorization and/or basic cookies will be used.
  • To serve localized content in client's desired languages, we may use Accept-Language.


Data stored from these uses will be kept for at most 7 days.

  • Requests will be logged without observed IP addresses only upon causing non-critical software errors.


Data stored from these uses will be kept for at most 365 days.

  • Requests will be logged with observed IP addresses only upon causing critical software errors, or attempting to utilize known exploits.

Data access/removal request

  • Approved data requests will be fulfilled within 30 days since approval, in the form that's available to us. Encrypted data will be provided as-is, along with their respective decryption keys only if available.
  • Individuals can file requests for their data, and will be approved upon proving ownership.
    • In most cases, individuals have power to remove data on their own.
  • Law enforcement agencies can file requests for data. All data requests filed from law enforcement agencies will be made public.
    • Requests sent from law enforcement agencies will only be approved if all listed criteria are satisfied.
      • Belongs to a political body deemed as "full democracy" or "flawed democracy" by The Economist Democracy Index.
      • Provides sufficient information for proving their identity.
      • Belongs to the political body where related services are hosted, or can provide proof that affected users violated our acceptable usage policy.
    • Affected resources of fulfilled removal requests from law enforcement agencies will be marked as 451 Resource Aflame, along with the name of requested agency.
  • If the service's ability to continue operation becomes next-to-impossible due to a failed compliance from a rejected data request, we will wipe all data stored on our behalf and cease operation on said service. The same goes for the Lightingale Community itself.

Infrastructure providers

We extensively rely on Cloudflare for our infrastructure on the clearnet. If you do not want to go through Cloudflare, feel free to access our services through alternative means. Otherwise, a copy of privacy policy from Cloudflare could be obtained.

To improve availability and/or decrease cost on some of our services, we may also use other infrastructure providers. Check their respective privacy policies for details. Below is a list of providers we rely on.

  • AWS CloudFront, for CDN.
    • Anonymized/generalized data generated by AWS CloudFront are stored for 30 days by the provider.
  • AWS Lambda, for serverless computing.
    • Anonymized/generalized data generated by AWS Lambda are stored for 30 days by the provider.
  • CacheFly, for CDN.
    • Data generated by CacheFly are never stored.
  • Cloudflare, for DNS, CDN, WAF and edge serverless computing.
    • Identifying data generated by Cloudflare are stored for 24 hours by the provider.
    • Anonymized/generalized data generated by Cloudflare are stored for 30 days by the provider.
  • Deno Deploy, for edge serverless computing.
    • Anonymized/generalized data generated by Deno Deploy are stored for 30 days by the provider.
  • Fastly, for CDN and edge serverless computing.
    • Data generated by Fastly are never stored.
  • GCoreLabs, for CDN.
    • Anonymized/generalized data generated by GCoreLabs are stored for 30 days by the provider.

Access denial


If you're accessing any Lightingale service from a VPN, chances are you're already blocked by us, but will get unblocked if with mixnets like Tor, or encrypted proxies. This is intentional.

We strongly support privacy and anonimity, while also highly detest the idea of fattening any commercial VPN vendor. VPNs do not offer privacy or security on the Internet in any way, let alone either anonimity or anti-censorship, and in no way any of them contribute to the effort of developing either anti-censorship or concealing technology to truly liberate the masses. As such, we've long since decided to take direct action, actively identifying and fingerprinting VPNs, while advising people to switch to real solutions instead.


We identify some client programs as high-risk, and block requests from those programs if identified.


I'm using a VPN, what should I do?

To put it simply, please stop using a VPN to access us.

If you're familiar with accessing services hosted on mixnets, you can access our services via alternative means. Or if you don't want to go through the hassle, please disconnect from your VPN, and if you have access to either exit/outproxy-enabled mixnet (e.g. Tor, I2P (I2Pd is recommended if you are comfortable with command line), Lokinet) or encrypted proxies, use them instead.

What if I'm blocked wrongly?

Within 18 hours, please contact us and provide your Cloudflare Ray ID in your unblocking appeal. After we've verified that you did indeed not connect from a VPN, you'll be unblocked as soon as possible. However, if you used a client program we deem as high-risk, we will reject your appeal immediately.

Could you stop blocking VPNs?


Acceptable Usage Policy

These terms do not yet have legal liabilities, however they are enforced.

Underlined terms should have definitions available in the Definitions section.


  • Child pornography: Depictions of underage humans or underage characters resembling humans.
  • Underage: Below 18 years old.

Disallowed use

AUP does not cover cases where reasons of policy enforcements are explained.

  • Reselling any of our public services, which is free-of-charge for all.
  • Breaching the awareness scope defined by projects/services.
  • Scanning us or to scan others (e.g. port scanning).
  • Gaining unauthorized resource access.
  • Degrading the performance of our servers (e.g. flooding).
  • Violating others privacy (e.g. doxxing).
  • Impersonating existing identities without stating satire status.
  • Exploiting stolen identities.
  • Distributing unsolicited data (e.g. spam).
  • Scamming.
  • Hate speech (e.g. racism, xenophobia).
  • Promotion of self-harm (e.g. suicide).
  • Harming others physically or psychologicaly (e.g. torture threats, death threats, harassement).
  • Engaging in distribution of illegal substances, human organs, guns and etc.
  • Promoting, encouraging and/or beautifying any of the following topics.
    • Crimes against humanity (e.g. massacre).
    • Terrorism, its practices and exercising organizations.
  • Distributing content matching any of the following criteria, without explicit warning to the target audience.
    • Malware.
    • Phishing content.
    • Pornography.
  • Distributing and storing content matching any of the following criteria.
    • Child pornography.
    • Pornography without consent of involved parties.
  • Defaming us without any validated proof.

Terms of Service

This agreement will become legally binding once Lightingale Community becomes a legally-registered non-profit organization.

As of 6th Oct 2023, these terms are not yet in effect.

In this agreement...

  • The term "you" or "your" refer to "the user".
  • The term "we", "us" or "our" refer to Lightingale Community itself and its members.
  • The term "service" or "services" refer to publicly-available listed services hosted on behalf of Lightingale Community. The list is available here.

By accessing content or using the services provided by the Lightingale Community, you agree to the following terms. Specific services will apply amendments to fit their specific needs.

Any material changes to these terms will be publicly notified via our Mastodon and our Telegram channel at least 7 days prior. If you wish to exercise your right to reject such changes, you can file complaints to us, or stop using the service altogether.


  • We reserve the right to modify the service, including but not limited to changing certain features and updating the related software.

  • We reserve the right to terminate your access to some or all of our services.

  • We may deny access to certain services based on the geographic location of your immediate connection.

  • We will attempt to prevent disruptions, defects and losses of data in our offered services, but despite our best efforts, we do not and can not guarantee availability of all times, and we are not responsible for materials served by us. Our service comes with absolutely no warranty, to the extent permitted by applicable law. You are solely responsible for your use of service.

The service

This section is defined in different services we offer to the public.


Lightingale Community is powered fully by and produces FOSS, fit under the definition set by the Free Software Foundation. Further acknowledgements may be made in README files when we use software projects that require them.

Our content

Except for software, unless stated otherwise explicitly, content belongs to us is licensed under CC BY-NC-SA 4.0 License. Our members hold the rights of content they produced.

Your content

This section applies to services offering UGC.

You hold the rights to your own content, but you give us a license when submitting your content to us. Upon submission, you permit us to do the following to your submitted content. These terms are world-wide, non-exclusive, royalty-free, transferrable and perpetual.

  • To store and display your content, you permit us to use, copy, store, distribute your content in ways consistent with your use of the services.
  • To adapt your content for use of different platforms by different users with various backgrounds, you permit us to monitor, modify, translate and reformat your content.
  • For public availability, you permit us to publish, publicly perform, or publicly display your content, if you've chosen to make it visible to others.
  • To allow our services to work as intended, you permit us to sublicense your content.

We reserve the right to block, remove or wipe your content if in breach with these terms or other terms in effect.

Acceptable usage

As a user of services offered by us, you agree to adhere to our acceptable usage policy. Violations of AUP will result in a termination, and may result in your data made available to law enforcement agencies.

We encourage you to report abuses of our services with proof. We accept reports made via email at abuse (at) ltgc (dot) cc.


This section is subject to changes as our legal status changes.

We are not responsible for fulfilling any additional requirement attached to the donations made to us.

Applicable law

This section is subject to change as our legal status changes.

This section is subject to change as our legal status changes.

Legal contacts may be filed via email to legal (at) ltgc (dot) cc. We do not have a physical location available.

UGC Availability

To prevent Lightingale Community from getting blocked as a whole in certain countries, we've been forced to restrict or deny direct access from those countries. A restricted service coverage would've been marginally better than nothing at all.

We offer two levels of UGC services: high-liberty and restricted. Levels are separated by the measures avalable to the users, and users' ability to freely express whatever they desire. Some countries may have been denied direct access from high-liberty UGC services, but not restricted ones.

If you've been redirected to this page, we have no choice but to offer our deepest apology.


Preferred technologies

Languages and runtimes


Operating systems

Virtualization and containerization


Used technologies

Technologies listed here have some of our projects using them. None of the technologies listed below are a preference, although project can freely choose to use them.

Languages and runtimes

Virtualization and containerization


Avoided technologies

Technologies listed here will have their usage be discouraged and avoided. However, projects can still develop for them only if necessary. Software already developed with these technologies can also be deployed.

Languages and runtimes

Operating systems


Banned technologies

Usage of technologies listed here are entirely banned within LTGC. Bans do not extend to members themselves.



Content encoding

None of the encodings listed are involved with patent concerns.

Usage Encoding Extension
Rasterized image JPEG XL .jxl
WebP .webp
Vector image SVG .svg
Lossy audio Opus .opus
Vorbis .ogg
AAC-LC .m4a .aac
Lossless audio WavPack .wv
FLAC .flac
Web compression Brotli .br
gzip .gz
Bundle compression xz .xz .txz
bzip2 .bz2 .tbz2
lzip .lz .tlz
Font WOFF2 .woff2

Read below for further details.

Rasterized image encoding


As WebP is properly supported in every browser built for systems newer than Windows XP, and it offers better quality-to-size ratio than all JPEG encoders, it is considered the best fallback format. However, as JPEG XL exists as an all-around better universal image format, lossy images should also be encoded with JPEG XL whenever possible.

Compared to all other image formats, JPEG XL offers jawdropping image fidelity, unmatched quality-to-size ratio, proper progressive loading and better responsiveness. The cherry on top of JPEG XL would be its ability to losslessly transcode from existing JPEG files, offering about 20% size reduction with cheap JPEG lossless bitstream reconstruction, which paves its way to be a backwards-compatible drop-in replacement for image storage and distribution.

MozJPEG-fronted JPEG XL encoding hasn't been tested yet.

Codec Use Params
JPEG XL Delivery cjxl -d 2.2 -e 4 -p
Archival cjxl -d 1.1 -e 4 -p
WebP Delivery cwebp -m 5 -psnr 56
Archival cwebp -m 5 -q 99

The full feature set comparison chart is available on Cloudinary.

Battle of the image codecs!


WebP Lossless should always be offered when lossless image codecs are required. JPEG XL Lossless should only be offered alongside when it proves to be smaller than WebP in a case-by-case scenario.

Audio encoding


When high sampling rates are required, choose Vorbis. When support for the Apple ecosystem is required, choose AAC-LC. Otherwise use Opus under all possible scenarios, but beware that Opus only supports sampling at 48kHz.

Below are the suggested bitrates under different scenarios, when encoding stereo audio content under either 44.1kHz or 48kHz. Audio content should be encoded with constrained variable bitrate (CVBR).

The AAC-LC encoder in question is libfdk_aac, being the best FOSS AAC-LC encoder out there. The only AAC-LC encoder better than libfdk_aac is Apple's Audio Toolbox, which is proprietary and not in consideration.


Keep in mind that the scenario under "basic" indicates that, all audio content encoded with provided parameters should be virtually undistinguishable from LAME-encoded MP3 files at 192kbps.


Streaming lossless audio is generally considered a bad idea.

When web support isn't planned, or the target platforms aren't severely underpowered, WavPack is the recommended codec for storing lossless audio. Recommended encoding parameters for the official CLI util: wavpack -hhvx -x 3



Brotli should be preferred over gzip at all times. Static low-entropy content (e.g. plain text files) should always be pre-compressed, with or without the original uncompressed file available.

For static precompression, the original file can be omitted when the space is constrained, serving only precompressed blobs. When compatibility with other infrastructure isn't in consideration, precompressed gzip files can also be omitted, although it's not recommended in most cases.

Algorithm Use Params
Brotli Real-time brotli -4
Precompression brotli -q 11
gzip Real-time gzip -4
Precompression zopfli --i25


bzip2 should be the default bundle compression algorithm, unless either lzip or xz is proven to be better in a case-by-case scenario. Quality should always set to 9, unless a lower quality value is proven to yield a better result for smaller files.

Due to platform differences, xz should be avoided for automation scripts that may install compression algorithms on the fly.


As practically all modern browsers support the WOFF2 font format, all required TrueType and OpenType fonts must be served as WOFF2 files instead. If for unspecified reasons that original files must be served, always consider precompression and avoid storing uncompressed files.


Lavender is a friendly discussion lounge for both the My Little Pony fandom and LTGC, powered by the magic of Lemmy. No matter what you are, be a pony, dragon, hippogriff or draconnequus, you're welcome here!

Lavender adheres to the general Terms of Service and Acceptable Usage Policy.

The incubator thread can be viewed here.



The service can be accessed from the addresses listed below.


Read Lavender panels.

Account registration

Alpha phase

Lavender is still in the alpha phase. During the alpha phase...

  • Only people already having a presence on Fediverse can apply for account registration. You must fulfill any criteria listed below.
    • Have an account on one of the listed public instances for more than 14 days, with at least 7 posts in total.
    • Have an account on any public Fediverse instances for more than 14 days, with at least 7 posts in total, and the identity relates to the My Little Pony fandom.
    • Be a member of the Lightingale Community.


Alpha phase

Lavender is still in the alpha phase. During the alpha phase...

  • Only accounts on the instance itself can apply to become a moderator.
  • Only with two or more

Lavender Panels

Lavender currently organizes the following panels.

Best of Fedi Pones

Artists new to the Fediverse often complain about not reaching enough audiences. So what's the solution? Well, with a weekly panel promoting pony artworks published on the Fediverse, of course!

Organized by a group of Fediverse enthusiasts from the My Little Pony fandom, Best of Fedi Pones seeks to bring what the Fediverse has to offer to everyone enjoying the creativity from the pony fandom. Better together!

Source code: Codeberg

Artwork submission

Submitting artworks will get them included in the issues of Best of Fedi Pones if not denied. All submitted artworks, unless violating AUP, will be also referenced by the MLP English Lavender community.

Submitting artworks

Best of Fedi Pones has been directly integrated into the Fediverse since issue 10. Submission only requires the inclusion of #weeklypony tag while also mentioning @[email protected]. Works both when posting yourself and replying to others.

Inclusion denial

Submissions will be denied if they match at least one of criteria listed below.

  • Is not SFW.
  • Is generated by neural networks. Inspired by or assisted with NN doesn't count.
  • Not posted by the artist themself.
  • Violates LTGC AUP.
  • Was posted for longer than 14 days to the deadline of the target issue.

Voting and issuing

Voting of each submission is done in a room accessible to all panel organizers. While the room is bridged to Discord and Telegram, only votes from Matrix and Discord are counted due to technical limitations.

Each eligible voter can part one ⭐️(:star:) emoji to give a submission an upvote. Submissions with high vote count will be ordered first, and submissions sharing the same vote count have their exact order determined by the hash of the origin URL. No downvotes are available.

Voting of each issue generally begins at 12:00 UTC +0 on every Saturday, and ends at 18:00 UTC +0 on the next day. The dataset should be available shortly after the voting ends, and any organizer can release the issue with the dataset.

To prevent accusations of theft, except for the cover art, all submission images must be hotlinked from source. Cover art is generally selected among the submission with the top 60% vote count, entirely by the organizer posting the issue with their own preferences. However, it's advised to avoid featuring the same artist within the span of 9 issues, and artists new to the Fediverse are advised to be preferred.

Matrix services

Lightingale Community has been hosting Matrix services for ease of communication, ever since the community's early days in 2021.


We run a Synapse homeserver for hosting all of our bridges and for internal communication. Only members of the Lightingale Community can apply for accounts on the homeserver.


As long as adhereing to the Acceptable Usage Policy, members on our homeserver can freely use any of the bridges we host.


Managed bridges to the following platforms are offered by us.

Group chat

The following bridges support both group chats and direct messages.

Direct message

The following bridges only support direct messages.

Known issues


  • Due to some unknown bug in Caddy, requests with bodies larger than 1000 KiB will be cut off by Caddy without emitting errors. This will cause some media messages fail to upload, and in turn, get bridged.
    • This is an issue plaguing all of the web infrastructure within LTGC for quite some while now.
  • Animated stickers on certain platforms may only get their first frame be bridged, due to varying media codec support on different platforms.
  • Double-bridged replies may not work on certain platforms.
  • The bridge may become unresponsive when overloaded. You can help us relieve this problem via donations!


  • Reactions aren't bridged from Telegram.
  • The Telegram bridge suffers from downtimes caused by Python, the underlying runtime. It has to be manually rebooted.
  • The Telegram bridge will randomly become unresponsive for no other reason than the underlying Python runtime.
  • Bot messages from Telegram cannot be bridged to other platforms, per Telegram's restriction.
  • Senders from other platforms cannot be transparently bridged to Telegram, requiring embedding their display names as message content.


  • Due to Discord validating time-sensitive HMAC codes on attachment URLs, media from Discord cannot be bridged currently.
    • This was fixed on 27th March 2024, where a combination of active and passive media proxying was deployed.
  • Some of the animated stickers were vector images encoded in custom-defined JSON files. As a result, none of the services other than Discord recognizes them.

Bridging service

FLOSS projects

If applied and approved, we will offer free bridging services to the approved FLOSS projects.

MLP fandom communities

We offer free bridging services to the approved communities within the MLP fandom after approval.

Not-for-profit entities

We offer free bridging services to not-for-profit entities after approval.

Matrix media repo services

Active Discord media proxy

As Discord began requiring expiring HMAC validations on media attachments, the Discord bridge now switches to an active proxying approach, before reuploading/re-serving re-encoded optimized media attachments becomes viable. Files delivered via this new approach will be served at

Passive Discord media proxy

Due to MSC3860 being unsupported on homeservers without conformation of the Matrix 1.7 specification, homeservers will not recognize, the public redirecting Discord media repo. To circumvent this, we offer a custom cached Discord media proxy at instead for use of bridges, however it will likely be shut down to public access if we notice it getting abused.

After Discord implemented expirations on media attachment links with HMAC validation, the media proxy now only serves non-attachment files, like avatars, stickers and custom emojis. Since passive media proxy is less costly to run than active media proxies, it's used whenever possible.


Ditzy is a transport-agnostic universal multi-message encoding scheme, allowing stateful bidirectional communications regardless of the statefulness of the underlying transport. With the state of the reconstructed tunnel fully decoupled from the underlying transport, possibilities are endless. How Ditzy performs is entirely dependent on implementation.

This project is inspired by Tor HTTP Meek, MIDI 1.0 and QUIC.

💌 Feel your messages delivered safely by your trustworthy Ponyvillan mailmare!

The first draft was written on 18th Nov 2021, with the next iteration on 5th Feb 2023. The current draft is written on 29th June 2023.


  • State of tunneled connections are decoupled from their underlying transports
  • Seamless connection migration on connection losses and IP changes
  • Total control over frame transmission

Use cases

  • Bidirectional communication through incapable infrastructure (e.g. CDNs, request reflectors)
  • Stablizing communication over unstable networks
  • Replacing QUIC where UDP communication is not feasible
  • Connection multiplexing
  • Connection splitting


Reference implementation API docs



The underlying transport interface to be used by DitzyStream. Connection management and congestion control happens here.

This interface needs to implement the following public methods to let DitzyStream function properly.

DitzyDriver {
	send(): WritableStream, // Where data gets sent out
	onmessage: ReadableStream, // Where data gets received


The master stream, where underlying sockets gets multiplexed and de-multiplexed. Individual sockets can be established with DitzySocket or DitzyPipe.

DitzyStream {
	driver: DitzyDriver, // The underlying driver
	pipe(): DitzyPipe, // Creates a new connection
	sock(): DitzySocket, // Creates a new connection


The raw interface sending data to and receiving data from as streams.

DitzyPipe {
	i: ReadableStream,
	o: WritableStream,


A WebSocket-like interface to send messages to and receive messages from.

DitzySocket {
	readyState: Number <readonly>,
	textOnly: Boolean,
	send(msg: Uint8Array|String),
	close(): null,
	onclose: Uint8Array|String,
	onmessage: Uint8Array|String,
	onopen: null

Binary encoding format



Originally, Meek is a technique emulating stateful connections over HTTP, utilized by Tor for its pluggable transports. It is now generalized to refer to any technique reconstructing stateful connections, regardless of the statefulness of underlying transport.


MIDI is a standard for real-time communication between devices. It's originally designed for musical instruments, but has found its places in other fields requiring synchronization and/or automation as well, such as stage lighting systems.

Variable Length Value

Variable Length Value (VLV) is a way of encoding integer values to multiple bytes, utilizing as many bits inside as they want. With VLV, integer values can be as large as they want.

VLV is defined as a part of Standard MIDI File (SMF) Format Specification.

A VLV can take multiple bytes, and all data encoded are stored in Big-Endian format. VLV bytes use the bit before actual values of each byte to indicate whether or not to continue decoding, and the rest to carry actual values.

Examples below.

BitsValue (hex)Value (binary)VLV (binary)VLV (hex)
6430100001101000001 000000114103


QUIC is a general-purpose transport running on top of UDP, seeking to be a replacement over traditional TCP. It offers various advantages over traditional TCP, with the most notable ones being seamless connection migration and reduced communication latency.



Each Ditzy message is formed by directly combining multiple frames together. The structure of each frame is as follows.

1#CommandsCommand ID
1~7(7-bit VLV)Socket ID
1~4(7-bit VLV)Frame ID
1+(7-bit VLV)Payload length
0+(any)Payload data

Socket ID

The socket ID is randomly selected between 0 and 281474976710655 (0xffffffffffff, 248 - 1).

Frame ID

The frame ID is iterated from 0 to 268435455 (0xfffffff, 228 - 1) on the side where connections are initiated. When 268435455 is reached, the message ID is expected to roll back to 0.


IDs between 0 (0x00) and 31 (0x1f) are reserved for core functionalities. Extenstions are free to utilize any ID between 32 (0x20) and 255 (0xff).

Different commands have different support levels. To meet a certain support level, features of the indicated level must be implemented.

0Socket close1
1Socket open1
2Socket aftertouch2
4Full message send1
5Message acknowledge1
7Implementation exclusive3
8Partial message send3
9Partial message send complete3

0: Socket close

Can be initiated bidirectionally.

Response should be exactly the same as request.

Closes a connection. Payload can be used to carry optional arbitrary error messages.

1: Socket open

Can be initiated bidirectionally.

Response should have the same frame ID as request.

Opens a connection. Payload is used to define suggested Socket timeout in milliseconds optionally.

(Optional) If sent from the receiving end, the value contains would be the final timeout value used in the connection.

2: Socket aftertouch

Can be initiated bidirectionally.

Response should have the same frame ID as request.

Challenges a connection. Often used to implement Socket latency tests.

Payload is prefixed with a VLV7 value indicating challenge type, with all remaining bytes containing challenge details.

  • 0: Latency test and keep-alive. No manipulation details field.

3: Jump

Can be initiated bidirectionally.

No responses are needed for jumps, but the receiving end should synchronize frame IDs.

Sends a junk frame. The receiving end should ignore jump messages.

4: Full message send

Can be initiated bidirectionally.

Use type 5 (message acknowledge) to send acknowledgements with the same frame ID.

Sends a full message.

5: Message acknowledge

Can be initiated bidirectionally.

Sends acknowledgements of messages. Additional acknowledgements of tail frame IDs are all encoded via VLV7.

6: Error

Can be initiated bidirectionally.

No response is needed for errors, but the receiving end should synchronize frame IDs.

Sends arbitrary errors without closing the connection.

7: Implementation exclusive

Can be initiated bidirectionally.

Response should have the same frame ID as request.

Implementation exclusive binary commands.


Floaty is a Caddy plugin implementing customizable rolling random IDs on a per-host basis, providing easy access via placeholders in Caddy.

Uses include:

  • Loopback prevention
  • Multi-hop debugging
  • Forced time-based rolling sticky hash wherever needed

All with little to no traceability, if the rolling duration is set correctly.



In the global section, set Floaty to run before request header processing.

	order floaty before header

In any of the server blocks, use the floaty directive to prepare the respective rolling random IDs. The syntax is as follows.

floaty [length [rollDuration]] [{
	[fieldId [length [rollDuration]]]

Whenever Floaty is initialized, the placeholder http.floaty would become available within that server block, where placeholders from HTTP handlers are accessible.

Generated ID lengths can be any value between 4 and 96, and out-of-bound values will be clamped into this range. By default, length is set to 8. Longer IDs may cause excessive resource usage.

Roll duration can be set to any value above 10 seconds with millisecond precision, if supported by the Go duration syntax. It's set to 15 minutes by default. A lower rolling duration may cause excessive resource usage.

When a request is received, Floaty will attempt to check if any of the needed request IDs have expired. Only when expired upon receiving a request, will Floaty begin to regenerate a new ID. This will add a little bit of overhead to each request, however it will prevent unnecessary ID rerolls when not in use.


Adding a response header with a default Floaty ID:

http://:8080 {
	header X-Floaty {http.floaty}

Adding a request header with a Floaty ID to reverse proxies, while blocking requests with a matching Floaty ID:

http://:8080 {
	floaty {
		instance_id 12 10m
		source_id 12 5m
	@directLoopback {
		header X-Previous-Hop {http.floaty.instance_id}
	@indirectLoopback {
		header X-Source-Hop {http.floaty.source_id}
	respond @directLoopback "Loopback denied" 403
	respond @indirectLoopback "Loopback denied" 403
	reverse_proxy {
		header_up X-Previous-Hop {http.floaty.instance_id}
		header_up ?X-Source-Hop {http.floaty_source_id}


⛏ Rolling server bases, batteries included.

Gel is a set of scripts to quickly prepare supported base Linux distributions for use in cloud, aiming to lessen the burden interacting with servers. For Alpine Linux, it comes with a simple OpenRC wrapper to get several systemctl commands working for OpenRC.

Gel is never intended to be used as a base image for containers, as the ease-of-use provided by Gel has little sense to exist in base container images.

Gel is extensively used throughout Lightingale Community's infrastructure.


Gel comes with two flavours for each supported base distribution: slim and full.

The full flavour targets all sorts of servers. Unless storage is severely constrained, this is the flavour to go for.

The slim flavour targets container hosts and VM hosts, which barely gets interacted directly, but still requires the ease-of-use found in Gel. It can also be used in other scenarios, if the full flavour contains packages you'd like not to be present on your system.

Full list

SlimFullNameLXC ready?
slimalpalpineAlpine StableNo
slimdebdebianDebian StableYes
slimsuseopensuseopenSUSE TumbleweedNo
slimleapleapsuseopenSUSE LeapYes
slimrockrockyRocky LinuxYes

Usage & Security

Read here.



For bare-metal, virtual machines and LXC containers. Do not run native install scripts other than on new machines.

  1. On any of the supported distros, make sure curl is available.
  2. Execute sh <(curl -Ls
  3. Connect to the SSH with ssh -p 1122 <serverIP>. User passwords won't change, but SSH settings will. See the SSH section for details.


Container images are only offered as a convenient way of inspecting the installations.

  1. Spin up one of the available Gel flavours.
    1. Images are available on the Docker Hub if you want to save time. Use podman pull<flavour> to pull the images.
    2. Or feel free to build the image yourself with ./shx up <flavour>.
  2. Connect to the SSH with ssh -p 1122 [email protected]. The default password is root.

Additional considerations

Alpine Linux

Gel needs the community repo to be enabled in order to function.

openSUSE Leap

doas is not available on the platform. The regular sudo is used instead.

LXC installation


apt install lxc


zypper in lxc

Rocky Linux/AlmaLinux

dnf install lxc


apk add lxc lxcfs lxc-download lxc-bridge


Privilege elevation

To reduce attack surface, Gel will attempt to replace sudo with doas from OpenBSD. By default, only the root user is allowed to use the doas command.

To allow other users to execute the doas command as root, append the following directives to a new line in /etc/doas.conf.

permit keepenv <user> as root

Make sure there is a trailing new line at the end of /etc/doas.conf. If not, doas command will not work.


The SSH settings will be changed with a relatively more secure one, except for permitting password logins to prevent you from losing access with an unfinished setup.

After finishing the automated Gel setup, do the following to secure your SSH access.

  1. If the password of the root user wasn't set by you, change it to a stronger one.
  2. Add a custom new user, which would be used for SSH logins.
  3. As the newly-created custom user, add the public keys used for SSH authorization.
  4. Keep the current SSH session active, and login as the new user to ensure access to machine is not lost.
  5. Allow the new user to use the doas command and verify. See the Privilege elevation section for details.
  6. Add the new user to the sshuser group, added automatically by the setup script. Example: usermod -aG sshuser <user>.
  7. In /etc/ssh/sshd_config, do the following.
  • Set PermitRootLogin from yes to no.
  • Uncomment AllowGroups and DenyGroups.
  • (optional) Change the listening port from 1122 to another.
  1. Restart sshd with systemctl restart sshd.


Octavia is an event-driven multi-standard MIDI state-tracking library.


  • Free, libre and open-source, under GNU LGPL v3.0.
  • Behaves like a real MIDI module.
  • Developed with Firefox and an open Web in mind.
  • Supports 8 ports, 128 channels, 512-voice polyphony maximum.
  • Built-in support of several standards, multiple plug-in cards, and tons of devices.
  • Tells when MIDI programming errors are spotted, reducing chances of faulty programming.
  • Available in JavaScript (browser and Deno).
  • No modification required to run in Tor Browser, Bromite and LibreWolf.
  • Wide support of bank mapping and bitmaps via midi-db.

Dev Talks

We're now hosting a new place to handle development talks! If you don't have a GitHub account, or just prefer to report bugs or give suggestions in a more casual way, feel free to chat with us with links below!

Further documentation

Support table


SysEx documentation

API documentation

Audio Effects

Audio effects

Octavia supports tracking a range of audio effects applied on supported targets. For maximum compatibility, Octavia has seven available slots reserved for effect sends, which correspond to reverb, chorus, variation and four insertions in order.

Each slot isn't dedicated to what that slot is primarily used for, but rather allocated and controlled by the CC registers they are assigned to by default (cc91, cc93, cc94, cc16-19). For example, the variation slot (cc94) is taken away by delay effects when in GS mode, while the reverb and chorus slot could be taken away by any effect desired in X5DR or NS5R mode.

Due to varied setups, each effect also isn't just bound to the CC registers they are assigned to. They can also listen on other CC registers, or even multiple if they wish.

Comparison table

Singular effect


Yamaha XGGS ReverbGS InsertionKORG AI²
Hall (1, 2, M, L)Hall (1, 2)Hall (1, 2)Hall (normal,
ensemble, concert)
Room (1-3, S, M, L)Room (1-3)Room (1, 2)Room (normal,
Stage (1, 2)Stage (1, 2)Stage
Plate (XG, GM)PlatePlate (wet, dry)
Delay (LCR, LR)DelayDelay (stereo)Delay (stereo)
Cross DelayPanning DelayDelay (3-tap, 4-tap,
mod, 3D, trem.c.)
Delay (cross, dual, tap 1-3)
Early Reflection
(1, 2)
Early Reflection
Gate (forward, reverse)Gate (forward, reverse,
sweep 1-2)
White Room
Karaoke (1, 2, 3)


Yamaha XGGS ChorusGS InsertionKORG AI²


Yamaha XGGS DelayGS InsertionKORG AI²


Yamaha XGGS InsertionKORG AI²

Dual effect


  • X: Yamaha XG
  • G: Roland GS
  • A: KORG AI²

RPN/NRPN values

RPN/NRPN values

Implementation Table

MIDI Implementation Chart

Function Recognized Remarks
Basic Channel Default ✓ 1-16
Changed ✓ 1-16 Supports up to 128 channels.
Note number 0-127
Mode Default 3
Messages ✓ 3, 4
Velocity Note on ✓ 9nV=1-127
Note off ✓ 9nV=0 8n
Aftertouch Key ✓
Channel ✓
Pitchbend ✓ 0-24 semitone steps
14-bit resolution
Control Change 0 ✓ MSB Bank Select
1 ✓ Modulation
2 ✓ Breath
4 ✓ Foot
5 ✓ Portamento Time
6 ✓ MSB (N)RPN Data Commit
7 ✓ Volume
8 ✓ Balance
10 ✓ Pan
11 ✓ Expression
12 ✓ General-purpose effect
13 ✓ General-purpose effect
16 ✓ General-purpose sound
17 ✓ General-purpose sound
18 ✓ General-purpose sound
19 ✓ General-purpose sound
32 ✓ LSB Bank Select
38 ✓ LSB (N)RPN Data Commit
64 ✓ Sustain (Hold)
65 ✓ Portamento
66 ✓ Sostenuto
67 ✓ Soft Pedal
Store only
68 ✓ Legato
Store only
69 ✓ Hold 2
Store only
70 ✓ Timbre Variation
Store only
71 ✓ Resonance
72 ✓ Release Time
73 ✓ Attack Time
74 ✓ Brightness
75 ✓ Decay Time
76 ✓ Vibrato Rate
77 ✓ Vibrato Depth
78 ✓ Vibrato Delay
84 ✓ Portamento Control
91 ✓ Reverb
92 ✓ Tremelo
93 ✓ Chorus
94 ✓ Variation
95 ✓ Phaser
96 ✓ Data Increment
97 ✓ Data Decrement
100 ✓ LSB RPN
101 ✓ MSB RPN
120 ✕ All Sound Off
121 ✓ All Controllers Reset
123 ✓ All Notes Off
124 ✕ Omni Off
Same as cc123
125 ✕ Omni On
Same as cc123
126 ✓ Mono
127 ✓ Poly
128 ✓ Dry level (internal)
129 ✓ VL Breath Strength (internal)
130 ✓ VL Pressure (internal)
131 ✓ VL Embouchure (internal)
132 ✓ VL Tonguing (internal)
133 ✓ VL Scream (internal)
134 ✓ VL Breath Noise (internal)
135 ✓ VL Growl (internal)
136 ✓ VL Throat Formant (internal)
137 ✓ VL Harmonic Enhancer (internal)
138 ✓ VL Damping (internal)
139 ✓ VL Absorption (internal)
140 ✓ VL Filter (internal)
141 ✓ VL Amplitude (internal)
142~149 ✓ DX Carrier Level 1~8 (internal)
150~157 ✓ DX Modulator Level 1~8 (internal)
Program Change 0-127
System Exclusive General MIDI ✓
General MIDI rev. 2 ✓
Roland GS ✓
Roland SD ✓
Roland C/M ✓
KORG N1R ✓ Redirected to NS5R
KORG 05R/W ✓
KAWAI GMega ✓ Also known as KAWAI K11
ALESIS NanoSynth ✕
System Common Song position ✕
Song select ✕
Tune ✕
System RealTime Clock ✕ No action defined
Start ✕ No action defined
Continue ✕ No action defined
Stop ✕ No action defined
Aux messages Local ON/OFF ✕
Active Sense ✕ No action defined

SysEx Instructions

Supported SysEx Instructions

  • ✓: Supported
  • -: Partially supported
  • ✕: Not supported
  • ?: Unknown
  • (blank): N/A

Mutual instructions

System reset✓✓✓✓✓✓✓✓✓
Master setup✓✓✓✓✓✓✕✓✓
Reverb setup✓✓✓✓✓✓✓✓
Chorus setup✓✓✓✓✓✓✓✓
Variation setup?✓✓
Part setup?✓✓✓✓✓✓✓✓
EFX / insertion-✓³-✓
Bitmap display¹✓✓✓
Text display²✓✓✓✓
Drum setup?✓✓✓✕✕✓✕✕✕
  1. Support in GS is called "frame draw", and with multi-page support.
  2. Called "letter display" in XG, and "text insert" in GS.
  3. GS only has "delay" effect occupying the space of variation setup.

Device-specific instructions

Roland MT-32

  • Temporary Patch Setup
  • Temporary Drum Setup
  • Temporary Timbre Setup
  • Device Patch Setup
  • Device Timbre Setup
  • Patch Memory Write
  • Timbre Memory Write
  • System

Yamaha MU1000

  • A/D Part Setup
  • A/D Mono/Stereo
  • System

Yamaha PLG-100SG

  • Master Setup
  • Part Setup
  • PhoneSEQ Setup
  • Lyrics Information Setup

Yamaha PLG-150DX

  • Master Setup
  • Part Setup
  • DX Voice Param
  • DX Voice Additional Param

Yamaha PLG-150VL

  • Master Setup
  • Current Voice Parameters
  • Part Setup

Roland SC-88

  • Single/dual Mode


  • All Program Dump
  • All Combi Dump
  • Extended Multi Dump


  • Mode Switch
  • All Program Dump
  • All Combi Dump
  • Extended Multi Dump


Supported targets

General support table

The following list of targets have their support by Octavia status presented in a table. A target can be a model, a plugin board, a lineup, or a standard.

A supported standard may also have a list of specific target models listed.

For specific SysEx support range, refer to Supported SysEx Instructions;

  1. Octavia implements XG level 3.0 or later, and XG version 2.0 or later.

Specific targets

Roland MT-32


Roland GS

SC-88 ProL✓

Yamaha TG


Yamaha XG


state.mjs API

All constants and interfaces documented here are guaranteed to work, and very likely not subject to further changes.


MIDI modes

Octavia is compatible with a range of modes on MIDI synthesizers. A list of supported modes to their respective keys is available below.

  • ?: The default "nothing" mode. Octavia will try to detect the correct mode.
  • gm: General MIDI mode.
  • gs: Roland GS mode.
  • xg: Yamaha XG mode. Compatible with TG-100 and TG-300.
  • g2: General MIDI Level 2 mode.
  • sd: Roland SD mode.
  • mt32: Roland MT-32 mode.
  • ns5r: KORG NS5R mode. Compatible with NX5R, and has limited compatibility with KORG N1R and N5.
  • x5d: KORG X5D(R) mode. Compatible with AG-10.
  • 05rw: KORG 05R/W and KORG X5 mode. Compatible with AG-10.
  • k11: Kawai GMega and Kawai K11 mode.
  • sg: Akai SG mode.
  • krs: KORG KROSS 2 mode.
  • s90es: Yamaha S90 ES mode.
  • motif: Yamaha Motif ES mode.

MIDI event types

  • 8: Note off
  • 9: Note on
  • 10: Note aftertouch, a.k.a. polyphonic aftertouch
  • 11: Channel controller change
  • 12: Channel program change
  • 13: Channel aftertouch
  • 14: Channel pitch bend
  • 15: System exclusive message





General MIDI Extended

GME, short for General MIDI Extended, is a standard based off General MIDI level 1, which emphasizes on slightly extending the ability of General MIDI while not being too demanding. General MIDI Extended can be considered as a summarization of the common functionality among all GM-compatible synthesizers, and should be the baseline of all contemporary General MIDI-compatible synthesizers.


Any GME-compliant synthesizer must adhere all requirements listed below.

  • Has at least 24 oscillators available simultaneously (polyphony), which must either be...
    • At least 24 fully dynamically allocated oscillators for both melodic and percussion sounds.
    • At least 16 dynamically allocated oscillators for melodic sounds, 8 for percussion sounds.
  • Supports all 16 MIDI channels, which...
    • Can play arbitrary number of voices within the polyphony limit.
    • Can change to a different instrument.
    • Channel 10 is set to percussion by default.
  • Correctly responds to listed required events, CC and RPN.
  • Has all voices listed in the required voice list.
  • Has drum kits following the required drum note mapping.
  • Correctly responds to required System Exclusive messages.

Voice list

Drum voices

Drum kits will reside on MSB 124, and all level 1 kits will also reside on MSB 120.

The above portion is not yet decided.

PC#Drum Kit NameLevel
000Standard Kit1
001Standard Kit 22
002Standard Kit 34
003Standard Kit L/R5
008Room Kit1
009Hip Hop Kit3
010Jungle Kit3
011Techno Kit4
012Dark Room Kit5
013House Kit4
014Techno Kit High4
015Techno Kit Low4
016Power Kit/Rock Kit1
017Rock Kit 23
018Rock Kit 34
019R&B Kit4
024Electro Kit1
025Analog Kit1
026Analog Kit 23
027Dance Kit3
028Rave Kit5
030Apogee Kit4
031Perigee Kit4
032Jazz Kit2
033Jazz Kit L/R5
040Brush Kit1
041Brush Kit 24
048Orchestra Kit1
049Ethnic Kit2
050Sakura Kit5
051China Kit5
052Asian Kit3
053Orchestra Kit Y5
054Gamelan Kit5
055Gamelan Kit 25
056SFX Kit2
057SFX Kit Y2
058SFX Kit Y 22
060SFX Kit 25
064Percussion Kit2

Melodic voices


PC#Voice Name
000Grand Piano
001Bright Grand Piano
002Electric Grand Piano
003Honky-tonk Piano
004Electric Piano
005Chorused Electric Piano

Chromatic percussion

PC#Voice Name
010Music Box
014Tubular Bells
  1. Some implementations may swap Dulcimer out with Santur.


PC#Voice Name
016Drawbar Organ
017Percussive Organ
018Rock Organ
019Church Organ
020Reed Organ
021French Accordion
023Tango Accordion


PC#Voice Name
024Nylon Acoustic Guitar
025Steel Acoustic Guitar
026Jazz Electric Guitar
027Clean Electric Guitar
028Muted Electric Guitar
029Overdriven Guitar
030Distortion Guitar
031Guitar Harmonics


PC#Voice Name
032Acoustic Bass
033Fingered Bass
034Picked Bass
035Fretless Bass
036Slap Bass 1
037Slap Bass 2
038Synth Bass 1
039Synth Bass 2

Solo strings/orchestra

PC#Voice Name
044Tremelo Strings
045Pizzcato Strings

Ensemble strings/orchestra

PC#Voice Name
048Ensemble Strings
049Ensemble Slow Strings
050Synth Strings 1
051Synth Strings 2
052Choir Aahs
053Voice Oohs
054Synth Voice
055Orchestra Hit


PC#Voice Name
059Muted Trumpet
060French Horn
061Brass Section
062Synth Brass 1
063Synth Brass 2


PC#Voice Name
064Soprano Saxophone
065Alto Saxophone
066Tenor Saxophone
067Baritine Saxophone
069English Horn


PC#Voice Name
075Pan Flute
076Blown Bottle

Synth lead

PC#Voice Name
080Square Wave Lead
081Sawtooth Wave Lead
082Synth Calliope Lead
083Chiffer Lead
084Charang Lead
085Voice Lead
086Fifth Sawtooth Lead
087Bass & Lead

Synth pad

PC#Voice Name
088New Age Pad1
089Warm Pad
090Poly Synth Pad
091Choir Pad
092Bowed Glass Pad
093Metal Pad
094Halo Pad
095Sweep Pad
  1. Or "Fantasia Pad".

Synth melodic sound effects

PC#Voice Name
096Ice Rain
102Echo Drops


PC#Voice Name


PC#Voice Name
112Tinkle Bell
114Steel Drums
116Taiko Drum
117Melodic Tom
118Synth Drum
119Reverse Cymbal

Sound effects

PC#Voice Name
120Guitar Fret Noise
121Breath Noise
123Bird Tweet
124Telephone Ring
  1. Can be optionally extended as a menu voice, with examples including Stadium!!! in KORG AI2 lineup.

Drum note mapping

  • Regular: Required.
  • Italic: Optional. If not defined, the note will behave the same as in Standard Kit.
  • ←: Same as Standard Kit.
PC# 0 1 8 16 24 25 32 40 48
Kit Standard Kit Standard 2 Kit Room Kit Power/Rock Kit Electro Kit Analog Kit Jazz Kit Brush Kit Orchestra Kit
# Note
35 B~1 Tight Kick Tight Kick 2 ← Rock Tight Kick Electro Tight Kick Analog Tight Kick Jazz Tight Kick Jazz Tight Kick Jazz Kick
36 C~2 Kick Kick 2 Room Kick Rock Kick Electro Kick Analog Kick Jazz Kick Brush Kick Concert Bass Drum
37 C#2 Side Stick ← ← ← ← Analog Side Stick ← ← ←
38 D~2 Snare Snare 2 Room Snare Rock Snare Electro Snare Analog Snare Jazz Snare Brush Tap Concert Snare Drum
39 Eb2 Hand Clap ← ← ← ← ← Jazz Hand Clap Brush Slap Castanet
40 E~2 Tight Snare Tight Snare 2 Room Tight Snare Rock Tight Snare Electro Tight Snare Analog Tight Snare ← Brush Swirl Concert Snare Drum
41 F~2 Floor Tom Lo ← Room Floor Tom Lo Rock Floor Tom Lo Electro Floor Tom Lo Analog Floor Tom Lo Jazz Floor Tom Lo Brush Floor Tom Lo Timpani F
42 F#2 Hi-Hat Closed Hi-Hat Closed 2 Room Hi-Hat Closed Room Hi-Hat Closed Hi-Hat Closed 2 Analog Hi-Hat Closed Jazz Hi-Hat Closed Brush Hi-Hat Closed Timpani F#
43 G~2 Floor Tom Hi ← Room Floor Tom Hi Rock Floor Tom Hi Electro Floor Tom Hi Analog Floor Tom Hi Jazz Floor Tom Hi Brush Floor Tom Hi Timpani G
44 Ab2 Hi-Hat Pedal Hi-Hat Pedal 2 ← ← ← Analog Hi-Hat Closed Hi ← Brush Hi-Hat Pedal Timpani G#
45 A~2 Low Tom ← Room Low Tom Rock Low Tom Electro Low Tom Analog Low Tom Jazz Low Tom Brush Low Tom Timpani A
46 Bb2 Hi-Hat Open Hi-Hat Open 2 Room Hi-Hat Open Room Hi-Hat Open Hi-Hat Open 2 Analog Hi-Hat Open Jazz Hi-Hat Open Brush Hi-Hat Open Timpani A#
47 B~2 Mid Tom Lo ← Room Mid Tom Lo Rock Mid Tom Lo Electro Mid Tom Lo Analog Mid Tom Lo Jazz Mid Tom Lo Brush Mid Tom Lo Timpani B
48 C~3 Mid Tom Hi ← Room Mid Tom Hi Rock Mid Tom Hi Electro Mid Tom Hi Analog Mid Tom Hi Jazz Mid Tom Hi Brush Mid Tom Hi Timpani C
49 C#3 Cymbal Crash 1 ← ← ← ← Analog Cymbal Crash ← Brush Cymbal Crash Timpani C#
50 D~3 High Tom ← Room High Tom Rock High Tom Electro High Tom Analog High Tom Jazz High Tom Brush High Tom Timpani D
51 Eb3 Cymbal Ride 1 ← ← ← ← ← ← Brush Cymbal Ride Timpani D#
52 E~3 Chinese Cymbal ← ← ← Reverse Cymbal ← ← ← Timpani E
53 F~3 Bell Ride ← ← ← ← ← ← Brush Bell Ride Timpani F 2
54 F#3 Tambourine ← ← ← ← ← ← ← ←
55 G~3 Cymbal Splash ← ← ← ← ← ← ← ←
56 Ab3 Cowbell ← ← ← ← Analog Cowbell ← ← ←
57 A~3 Cymbal Crash 2 ← ← ← ← ← ← ← Concert Cymbal 2
58 Bb3 Vibraslap ← ← ← ← ← ← ← ←
59 B~3 Cymbal Ride 2 ← ← ← ← ← ← ← Concert Cymbal
60 C~4 Bongo Hi ← ← ← ← ← ← ← ←
61 C#4 Bongo Lo ← ← ← ← ← ← ← ←
62 D~4 Muted Conga Hi ← ← ← ← Analog Conga Hi ← ← ←
63 Eb4 Open Conga Hi ← ← ← ← Analog Conga Mid ← ← ←
64 E~4 Conga Lo ← ← ← ← Analog Conga Lo ← ← ←
65 F~4 Timbale Hi ← ← ← ← ← ← ← ←
66 F#4 Timbale Lo ← ← ← ← ← ← ← ←
67 G~4 Agogo Hi ← ← ← ← ← ← ← ←
68 Ab4 Agogo Lo ← ← ← ← ← ← ← ←
69 A~4 Cabasa ← ← ← ← ← ← ← ←
70 Bb4 Maracas ← ← ← ← Analog Maracas ← ← ←
71 B~4 Short Whistle Hi ← ← ← ← ← ← ← ←
72 C~5 Long Whistle Lo ← ← ← ← ← ← ← ←
73 C#5 Short Guiro ← ← ← ← ← ← ← ←
74 D~5 Long Guiro ← ← ← ← ← ← ← ←
75 Eb5 Claves ← ← ← ← Analog Claves ← ← ←
76 E~5 Woodblock Hi ← ← ← ← ← ← ← ←
77 F~5 Woodblock Lo ← ← ← ← ← ← ← ←
78 F#5 Muted Cuica ← ← ← ← ← ← ← ←
79 G~5 Open Cuica ← ← ← ← ← ← ← ←
80 Ab5 Muted Triangle ← ← ← ← ← ← ← ←
81 A~5 Open Triangle ← ← ← ← ← ← ← ←
82 Bb5 Shaker ← ← ← ← ← ← ← ←
83 B~5 Jingle Bell ← ← ← ← ← ← ← ←
84 C~6 Bell Tree Bar Chimes ← ← ← ← ← ← ←

Events, CC and RPN



Except System Exclusive messages, the first byte of each MIDI event defines the event type and target channel. The first four bits define the event type, with the last four bits defining the target channel.


80x8Note off
90x9Note on
100xaNote aftertouch (PAT)
110xbControl change
120xcProgram change
130xdChannel aftertouch (CAT)
140xePitch bend
150xfSystem messages

System message types

2400xf0System Exclusive (Start of Exclusive)No
2470xf7System Exclusive (End of Exclusive)No
2540xfeActive sensingYes
2550xff(Line invalid) Meta eventsNo


Control Changes



00x00MSB Bank Select0-127No
320x20LSB Bank Select0-127No
60x06MSB Data Commit0-127No
380x26LSB Data Commit0-127No
980x62LSB NRPN0-127No
990x63MSB NRPN0-127No
1000x64LSB RPN0-127No
1010x65MSB RPN0-127No
960x60RPN Increase0-127No
970x61RPN Decrease0-127No


50x05Portamento Time0-127No
640x40Sustain (Hold)0-127No
650x41Portamento Switch0-127No
670x43Soft Pedal0-127No
720x48Release Time0-127No
730x49Attack Time0-127No
750x4bDecay Time0-127Yes
760x4cVibrato Rate0-127Yes
770x4dVibrato Depth0-127Yes
780x4eVibrato Delay0-127Yes
840x54Portamento Source0-127No
910x5bEffect (Reverb)0-127No
920x5cEffect (Tremelo)0-127Yes
930x5dEffect (Chorus)0-127No
940x5eEffect (Variation)0-127No
950x5fEffect (Phaser)0-127No


1200x78All Sound Off0No
1210x79Reset All Controllers0No
1230x7bAll Note Off0No
1240x7cOmni Off0Yes
1250x7dOmni On0Yes


Registered Parameter Numbers

Non-registered Parameter Numbers


This section is optional.

System Exclusive

Painted Palette

Painted Palette is a headless bot implemented purely in JavaScript, which helps pixel placements on r/place. It is developed for the My Little Pony factions, but can work for any other faction with modification.

If the codebase isn't modified, in auto mode, Painted Palette runs on a defensive stance by default - as long as pixels covered by the template aren't badly damaged, it barely activates. If in manual mode, Painted Palette only places pixels when the user commands or schedules a pixel placement.


  • Extremely fast to build, fast and easy to deploy for anyone. IT prowness is not a problem.
  • No dependency compiling before running.
  • Fully-unattended automated updates.
  • Relatively low on resources.
  • Native support for multi-account deployments. (less than 10 per IP address)



Node.js on Windows does not respect proxy settings. If proxies are needed, switch to Deno instead.

With an acceptable Internet connection, the whole installation process should not take more than 20 seconds. On POSIX systems, the figure is even lower.

If you're up for the task, feel free to contribute, and expand our horizon of OS support!


  1. Download the latest version of
  2. Extract to an appropriate folder of your liking.

Linux, Android, macOS

  1. Ensure bash, curl and unzip are available.
  2. Assign export VARIANT=node.
  3. Make sure you have either Node.js 18 or Node.js 19 installed.
  4. Run bash <(curl -Ls



Despite our efforts on bot detection evasion, when not in manual mode, running the bot on your main is generally considered a bad idea. Please use disposable alts when in auto mode.

For more advanced usage, please refer to command line docs.

Windows (default GUI only)

  • Double-click webui.cmd, and click on the link it provides. Should point to by default.
    • If the browser displays an error page, run winFix.cmd first, then restart gui.cmd to see if the problem goes away.

Linux, Android, macOS

  • Run ./palette-bot batch, and click on the link it provides.
  • Do you have Tor installed on your system? If yes and you're using Deno, run ./palette-tor batch to use it without the tedious configuration process!
  • Are you running Painted Palette with Deno on Linux? If yes, run ./palette-proxy batch to connect to public proxy pools with ease!

Windows (CLI)

  • Open a terminal session where webui.cmd is located.
  • Run with .\node.exe node.js <arguments>.


  • Clone the repo via git clone palette.
  • Switch into oci via cd ./palette/oci.
  • Run docker-compose up -d if on Docker, or podman-compose up -d if on Podman.

Open Source

Painted Palette is a piece of open-source software, licensed under GNU GPL 3.0.

Source code: GitHub

Web UI


Command line

The Windows build does not ship with a helper like ./palette-bot . As such, please replace ./palette-bot with node node.js or deno run --allow-read --allow-write --allow-net deno.js .

With Deno or Bun, if you need to specify custom proxies, define the https_proxy environment variable (e.g. https_proxy= There are direct proxy integrations available on Linux and Android, which can be used by replacing ./palette-bot with either ./palette-proxy for public proxy pools, or ./palette-tor for Tor.

Environment variables

  • BIND_ADDRESS: Define a bind address. Do not include ports.
  • HTTP_PROXY: Used by Deno and Bun to connect to upstream proxies.
  • HTTPS_PROXY: Same as above. Must be the same as HTTP_PROXY.
  • NO_UPDATE: Set to 1 to disable the automatic updater.
  • PORT: Set the port PP listens for REST API calls. Used in ./palette-bot ctl.
  • SLEEP: Set to 1 to behave as if ./palette-bot ctl sleep is run.
  • TEMPLATE_URL: Customize the pointer URL.

./palette-bot help

Prints help messages.

./palette-bot paint

Deprecated and not recommended. Paint on Reddit with given credentials.

Format: ./palette-bot paint <username> <password> <otp>


  • Direct login: ./palette-bot paint myCoolName myGoodPassword
  • Direct login with 2FA codes: ./palette-bot paint myCoolName myGoodPassword 114514

./palette-bot pixel

Removed. Paint on VKontakte with given credentials.

Same format as ./palette-bot paint.

./palette-bot test

Deprecated and not recommended. Paint on the test server with given credentials.

Same format as ./palette-bot paint.

./palette-bot batch

Start a batch mode server for account management, complete with Web UI and REST API.

Since version 0.0.16, manual mode became the default - pixel placements require user interaction, and only a single account is allowed.

Format: ./palette-bot batch <port>

./palette-bot ctl

Send commands to a running batch server. Define the target port which the batch server listens on with the environment variable PORT.

Format: ./palette-bot ctl <subcommand> <...args>


r/place 2023


Information on this page is outdated.

Written on 22nd June 2023


r/place 2023 did not happen on 1st April or 23rd June.

You know the drill: r/place 2023 is coming. So we prepared a list of FAQs, for you as a brony/pegasister to bootstrap your knowledge!

What is r/place?

r/place is a social experiment run by Reddit, where every participant gets to place coloured pixels with a defined cooldown. With itself categorized as a form of "pixel battle", it is by far the largest pixel battle held across the globe.

With only the power of a single person, not much could be created. However, with the power of factions, there's no such thing as "impossible"!

Why should I participate?

Although r/place isn't an annual event, Reddit held r/place last year (2022) also. And last year, we suffered dozens of raids, most of them lost due to a lack of firepower, and were able to recover solely because attackers went inactive eventually, either due to sleeping or due to recess between raids. We hope we could stop the same from happening again.

We prepared for r/place in advance this year, but with multi-account and automated pixel placement banned in the main faction, all while protests regarding Reddit APIs going in full swing, the expected firepower looks even dimmer. Despite the ongoing Reddit API fiasco, we desperately need everyone we can hopefully get, to extend our firepower as much as possible for all possible defense. Please consider participating the event!

When is it expected to happen?

On 23rd June 2023, Reddit's anniversary before its IPO. The exact time may vary, but it is rumored to happen at around 13:00 UTC.

How do I participate as a My Little Pony fan?

Lucky for us, a group of enthusiastic bronies established a faction before r/place even began, which became the main MLP faction of r/place 2023. But unlucky for us, said faction recently got splintered.

Why the splinter?

The initial trigger was an announcement on 18th June, regarding ban on all forms of automatic pixel placement, alongwith joining an unknown alliance called "P3ACE".

The ban alone did directly result in the creation of a faction, but it was a series of indications and later dealings sending the splinter onto a seemingly irreversible course: lack of transparency regarding joining the alliance, single parties meddling and forced the join, reluctance of communication regarding multi-account and automated pixel placement, with certain mods outright shunning and diverting arguments, all while removing downvotes on that specific announcement. All these enraged some parties, setting the splinter in stone.

The current splinter does not dwindle the firepower MLP as a whole possesses, as both use the very same template.

What about the pros and cons of automated pixel placements?


  • Relatively low resource consumption, good for low-end devices
  • Does not require you to stare at a screen and clicking your mouse for hours end
    • Does not hinder you from your work
    • Allows you to sleep as usual


  • If only with automated placements, one cannot experience the event to its fullest
  • Shamed by some people
  • "Does not believe in friendship"

How do existing implementations of automation fit?

  • Browser overlay: Auto-clicker is removed, and tab freeze circumvention became borked. Auto-focus and automatic colour picking still exist, but every pixel placement now requires user interactions.
  • PonyPixel (Python headless): Retired.
  • Painted Palette (JavaScript headless): A seperate manual-only mode is planned, but is largely unhindered.

How should I join the factions?

With the main faction prohibited discussions regarding several topics, the splintered-off faction offers a supplemental and more libre place where said topics are likely not forbidden. If you are fine with all the bureaucracy issues in the main faction, and agrees to stare at a screen for hours to place every single pixel manually, you can join the main faction. Otherwise, joining the splintered-off faction is much recommended.

Since Painted Palette by itself is a somewhat independent project, it has an additional place for dev talks unrelated to the splinter.


💨 Lightning-fast intuitive typing.

Target scripts



m17n is an IME library for mapped stream conversion of characters. To develop schemas for m17n, read the database tutorial.

m17n is included in both IBus (Intelligent Input Bus) and fcitx5.


  • Get the required .mim files.
  • Check if the IME framework of your system supports m17n. Most Linux desktop distros with IBus has m17n support included by default.
  • Check if directory ~/.m17n.d/ exists for the current user. If not, create it via mkdir ~/.m17n.d/.
  • Copy the .mim files you want to use to ~/.m17n.d.
  • Restart your IME framework.
    • If on IBus, run ibus restart.



No input methods on Android support m17n currently. For its possible support on Android, please check out the issue in the fcitx5-android project.


Rime is an IME framework for implementing custom input schemas for different languages. To develop schemas for Rime, read here (machine translation required).

Rime is supported on Linux via IBus, Windows and macOS. Platform support is extended with forks, e.g. for fcitx5 (fcitx-rime), Android (Trime) and iOS (Hamster, iRime).

The official Rime documentation is only available in Orthodox Chinese.


  • Get the required .yaml files. Check for files ending in .schema.yaml, .dict.yaml and .custom.yaml.
  • Copy the .yaml files to ~/.config/ibus/rime/.
  • (Optional) Customize the new schema as you see fit.
  • Enable the new schema in ~/.config/ibus/rime/default.custom.yaml.
  • Redeploy Rime via touch ~/.config/ibus/rime/; ibus restart.


  • Get the required .yaml files. Check for files ending in .schema.yaml, .dict.yaml and .custom.yaml.
  • Copy the .yaml files to %APPDATA%\\Rime.
  • (Optional) Customize the new schema as you see fit.
  • Enable the new schema in %APPDATA%\\Rime\\default.custom.yaml.
  • Redeploy Rime via start menu or right-click menu of the taskbar icon.






Key map


aا (a)ا (a)ا (a)
bب (b)ب (b)ب (b)
pÙ¾ (p)Ù¾ (p)
tت (t)ت (t)ت (t)
TÙ¹ (á¹­)
Cث (ṯ)ث (s)
jج (j)ج (j)ج (j)
cچ (c)چ (ch)
hح (ḥ)ح (h)
Kخ (ḫ)خ (x)خ (x)
dد (d)د (d)د (d)
Dڈ (ḍ)
Zذ (ḏ)ذ (z)
rر (r)ر (r)ر (r)
Rڑ (ṛ)
zز (z)ز (z)ز (z)
Xژ (zh)ژ (zh)
sس (s)س (s)س (s)
xش (š)ش (ś)ش (sh)
Sص (ṣ)ص (s)
Jض (ḍ)ض (z)
vØ· (á¹­)Ø· (t)
Vظ (ẓ)ظ (z)
eع (ʿ)ع (')
Gغ (ġ)غ (ġ)غ (gh)
fف (f)ف (f)ف (f)
qق (q)ق (q)ق (q)
kك (k)ک (k)ك (k)
gÚ¯ (g)Ú¯ (g)
lل (l)ل (l)ل (l)
mم (m)م (m)م (m)
nن (n)ن (n)ن (n)
Nں (◌̃)ڭ (ng)
oه (h)ه (FA), ہ (UR) (h)ھ (h)
wو (w)و (w/ū)ۋ (w)
HÚ¾ (-h)
uء (ʾ)ء (')ئ
iي (y)ی (y/ī)ي (y)
yے (ē)ە (e)
ى (ā)
و (o)
ۇ (u)
ۆ (ö)
ۈ (ü)
ې (ë)
ى (i)


Letters with hamza

Aآ (ā)آ (ā)
أ (ʾa/ʾu)
إ (ʾi)


Arabic and Persian numerals have separate codepoints, despite only three of them (4, 5, 6) look different. Urdu numerals share the same codpoint as the Persian ones, but three of them (4, 6, 7) should look different with proper language settings.

0Ù Û°Ù 


English phonetic alphabets

As per effort of decreasing the learning curve as much as possible, all English phonetical alphabets share the same set of key map.

Included alphabets

British English Phonetic Alphabet

BEPA is an adaptation of International Phonetic Alphabet, optimized to represent the sounds of British English, and by extension all of its variants.

Shavian alphabet

The Shavian alphabet is a constructed alphabet aims to permit efficient writing and spelling for British English Received Pronunciation.

Deseret alphabet


Due to a lack of several vowels, there are no plans to support the Deseret alphabet as of yet.

The Deseret alphabet is a constructed alphabet developed to be used in an English-language spelling reform for American English.

Key map

Keys are ordered via BEPA.


Vowels require at most two keys.

Short vowels

e ehɛ𐑧𐐯bet
Ee EEe𐑧𐐯bet
i ihɪ𐑦𐐮fit
o ohɒ𐑪𐐱hot
a ahʌ𐑳𐐲cut
u uhʊ𐑫𐐳cook
E Ehə𐑩𐐲lover

Long vowels




Shavian compatibles



None of the consonants require two keys.

Voiceless-voiced pairs


Aspirated, nasal and etc



These characters will only be present in their respective alphabets, and will be null-routed in others.

xˈN/AN/APrimary stress in BEPA/IPA.
XˌN/AN/ASecondary stress in BEPA/IPA.
ax ex ix ox uxN/A·N/ANaming dot in Shavian.

Key map

Some letters in traditional Mongolian may have multiple codepoints and mappings, this is reserved for different pronunciations of the identical-looking letters.


| U+ | Keymap | IPA | Mongolian | Manchu | Sibe | Todo | | -- | -- | -- | -- | -- | -- | | 1820 | a | ɑ | ᠠ | ᠠ | ᠠ | ᠠ | | 1821 | e | ə | ᠡ | ᡝ | ᡝ | ᡄ | | 1822 | i | i | ᠢ | ᡳ | ᡞ | ᡅ | | 1823 | o | ɔ | ᠣ | ᠣ | ᠣ | ᡆ | | 1824 | u | ʊ | ᠤ | ᡡ | ᡡ | ᡇ | | 1825 | O | o | ᠥ | | | ᡈ | | 1826 | U | u | ᠦ | ᡠ | ᡠ | ᡉ | | 1827 | E | e | ᠧ | | | | | 185F | I | ɨ | | ᡟ | ᡟ | | | 1843 | `` | ː | | | | ᡃ |


1830ssá °á °á °á °


1801``᠁N/AEllipsis for Mongolian.
1802``᠂N/AComma for Mongolian.
1803``᠃N/AFull stop for Mongolian.
1804``᠄N/AColon for Mongolian.
1807``N/A᠇A bare tooth. "Glottal stop" letter; "Sibe syllable boundary marker" (SSBM).
1808``N/A᠈Comma for Manchu.
1809``N/A᠉Full stop for Manchu.
180A``᠊᠊Letter stem (Nirugu).
180B``᠋᠋Free variation selector 1.
180C``᠌᠌Free variation selector 2.
180D``᠍᠍Free variation selector 3.
180E``᠎N/ADisjoint tail in Mongolian.
180F``᠏᠏Free variation selector 4.
200C``‌‌Zero-width joiner (ZWJ).
200D``‍‍Zero-width joiner (ZWJ).
202F``  Narrow non-breaking space (NNBSP).


🔪 Stream chunk splitting.

Licensed under GNU LGPL 3.0. Named after Roach (Rochelle) in Cooking Roach and A Meal Fit for a King by Bucking Nonsense.


Text emitter


Static properties

  • SPLIT_UTF_8: Split by UTF-8. Also used by encodings like Shift JIS.
  • SPLIT_UTF_16LE: Split by UTF-16LE.
  • SPLIT_UTF_16BE: Split by UTF-16BE.


new TextEmitter(stream: ReadableStream, splitMode: Number, label: String);
  • stream: The source stream of strings to read from.
  • splitMode: How to determine valid line feed (0x0a) and carriage return (0x0d) characters. Valid values are listed as SPLIT_* static properties.
  • label: One of the valid labels. Not implemented.




When a raw chunk is received from the stream.



When the stream or the emitter closes.



When the emitter encounters a critical error.



When a line of text becomes available, but decoding failed. Returns the raw bytes.



When a line of text becomes available before decoding begins. Returns the raw bytes.

Raw line data will be flushed from buffer when the stream closes unexpectedly.



When a line of text becomes available. Returns the decoded line of text.



Not implemented.

Boolean: TextEmitter.closed

If the text emitter is closed.



Not implemented.

undefined: TextEmitter.close()

Close the current stream.


📜 Bash/PDKSH shell action executor. A replacement for npx, deno task and etc.

All actions for shx should be written for Bash.

Supported shells

  • AT&T ksh93
    • Directory traversal does not work on ksh93 due to incorrect IFS behaviour.
    • Cannot be used as a runner.
  • Bash
  • Zsh


shx [<action> [<arguments>]]

Scripts will be run with Bash when present. If not, they'll be run with any supported shell.

Standard utilities

shx comes with a collection of QoL standard utilities.

  • amend: Update and amend the current commit, then push to remote.
  • build: A placeholder action for projects using shx to build themselves.
  • commit: Create a new commit, then push to remote.
  • echob: Printing bold text in the terminal.
  • push: A combination of shx build and shx commit.
  • release: Bundle build results into an archive. Configurable (upcoming).
  • sh: Spawn a Nix-powered shell with all development dependencies met.
  • tag: Tag the current commit, then push the tag to remote.
  • which: Fallback for environments not offering a which command.


Silk is an attempt to unify timelines of the MLP fandom on the Fediverse. It is achieved by merging all public timelines of instances with Mastodon-compatible APIs, and accounts that followed this account if on other instances. To avoid stressing tracked servers and accounts, WebSocket and SSE connections are utilized whenever possible, with caches enforced.

By bringing the MLP fandom on the Fediverse together, we attempt to make the Fediverse an appealing place for bronies and pegasisters alike, without any grip from a commercial entity. Find interesting people, discover content creators, anything is possible.

Don't know what Fediverse is? In laymen's terms, it's a cluster of inter-connected servers supporting a semi-decentralized social network. It has no single controlling entity, rendering takeover attempts happened to the blue bird impossible. But those are just words, why not join the Fediverse to experience it first-hoof?

Don't know which server to join? A list of servers is available here!

  • Inclusion: What's included in the timeline, and which server to join.
  • Moderation: How we moderate the merged timeline.
  • Usage: How to use Silk Web.
  • API: How to use Silk API.

Technical implementation

The list of servers to merge timelines can be customized, while moderation on specific users are implemented with existing Mastodon features. Accounts muted by the hook account are excluded from any self-service exemptions, while ones blocked by the hook account are excluded from the timeline altogether.

Hook accounts

The primary hook account is used for storing moderation information. Other instances usually do not need a hook account to be set up to read the local timeline.

Not every instance has its public timeline open to everyone though. As such, additional hook accounts are required on these instances.

Below is the list of hook accounts.

Open Source

Silk is a piece of open source software, licensed under GNU AGPL 3.0 or later.

If ready for public use, source code would be available on GitHub.

Content Inclusion


Silk will attempt to merge public timelines on all servers listed below.


The following instances have posts' content warning set as-is.

CW by default

Due to differences of the server rules, all of the following instances have posts' content warning enabled by default to comply the moderation rules.

Excluded instances

  • Pone.Social ( (removed due to incorrect configuration on the instance)

Requesting instance inclusion

We're open to include more instances to the list. If you host an instance which satisfies the following criteria, please contact us to have your instance included. We will assess before the final inclusion.

  • MLP-themed
  • Not a roleplay instance
  • Not supported by advertisement

Manual account inclusion

If your account isn't on any of the instances listed above, and said instance isn't mainly for the MLP community, you can follow the hook account to get yourself included manually. The hook account may also follow some accounts to have the same effect, mainly when said accounts do not have the ability to follow anyone (e.g. Equestria Daily).

Timeline Moderation

To grant as many members in the MLP community a pleasant experience as possible, we are enforcing a series of moderation rules on the merged timeline.

The rules are set on the basis of least intervention. They may change without prior notice, but we try our best to keep everyone notified.

Account exclusion

Accounts matching any criteria below will be excluded from the merged timeline altogether.

  • Nearly always advertise presence on other platforms without mingling on the Fediverse
  • Vent account
  • Promotion of self-harm
  • Promotion of hate speech, incl. racism, xenophobia, etc
  • Owner involved in harming of other individuals
  • Regularly not putting materials unsuitable for minors behind content warnings
  • Having no connection to the MLP fandom whatsoever

Instance auto-CW

Instances that permit accounts with the aforementioned criteria will get put behind content warnings by default.

Instance auto-CW exemption per-account

If you are on a server with content warning automatically enabled in the timeline, you can exempt yourself from the auto-CW status by following the hook account, as long as you follow the following rules. However, matching any criteria listed before will get your auto-CW exemption status revoked, or even entirely excluded.

Silk API

All APIs are assumed to be hosted at if without further clarification.


GET /nr/silk/servers

Grab a list of included servers, along with their auto-CW status.

Returns an array of Server objects.

GET /nr/silk/timeline

Fetches a list of posts already stored on the server.

Returns an array of Post objects.

WS/SSE /rt/silk/timeline

If there are changes made to the timeline, this endpoint will push such changes to the clients.

Sents EventWrapper objects regardless of connection type.

Data structure


	"event": <String>, // "set", "delete", "ack"
	"data": <Post|String|null>


	"domain": "",
	"cw": false,
	"active": true


Except for Post.card and properties shown as null here, the data structure of Post objects have been pinned down.

Data of an example post is shown below.

	"id": "110464545243574580",
	"uri": "",
	"url": "",
	"tags": [{
		"name": "mlp",
		"url": ""
	"emojis": [{
		"code": "flutteryay",
		"url": "",
		"static": "",
		"inPicker": true
	}, {
		"code": "ajsmug",
		"url": "",
		"static": "",
		"inPicker": true
	"card": null,
	"poll": {
		"id": "49940",
		"atExpire": 1685560245796,
		"expired": false,
		"multiple": false,
		"sumVote": 0,
		"sumVoter": 0,
		"options": [{
			"title": "Don't choose",
			"sumVote": 0
			"title": "Don't choose either",
			"sumVote": 0
		"emojis": []
	"atNew": 1685555194757,
	"replyPost": "110464545243574580",
	"replyUser": "109524364471531266",
	"cwReal": false,
	"cwText": "",
	"access": "public",
	"lang": "en",
	"sumReply": 1,
	"sumBoost": 3,
	"sumFav": 3,
	"atEdit": 1685555194758,
	"text": "<p>Day 7: The Church. (final)</p>",
	"boost": null,
	"app": {
		"name": "Web",
		"site": ""
	"user": {
		"id": "109524364471531266",
		"username": "thatonegib",
		"acct": "thatonegib",
		"dispName": "Gib Riel-Delano",
		"locked": false,
		"bot": false,
		"discoverable": true,
		"group": false,
		"note": "<p>He/Him.<br />&quot;Road to hell is paved with good intentions&quot;<br />♥️ <br /><span class=\"h-card\"><a href=\"\" class=\"u-url mention\">@<span>AlzMarioWolfe</span></a></span><br /> 💜 <br />@DamienInTheDark<br /> 04 Oct 2019<br />Comms CLOSED</p>",
		"url": "",
		"avatar": "",
		"avatarStatic": "",
		"header": "",
		"headerStatic": "",
		"sumPost": 58,
		"atLastPost": "2023-05-31",
		"noIndex": false,
		"emojis": [],
		"roles": [],
		"fields": [{
			"name": "Look through my Gallery!",
			"value": "<a href=\"\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\"></span><span class=\"invisible\"></span></a>",
			"atVerify": null
		}, {
			"name": "Help me make a living!",
			"value": "<a href=\"\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\"></span><span class=\"invisible\"></span></a>",
			"atVerify": null
		}, {
			"name": "Watch the sauce get made!",
			"value": "<a href=\"\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"ellipsis\"></span><span class=\"invisible\">NkH4abuBFoFhyg</span></a>",
			"atVerify": null
		}, {
			"name": "Obligatory Twatter link",
			"value": "<a href=\"\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://</span><span class=\"\"></span><span class=\"invisible\"></span></a>",
			"atVerify": null
		"atNew": 1671148800000,
		"sumFan": 25,
		"sumSub": 5
	"media": [{
		"id": "110464545127306536",
		"type": "image",
		"url": "",
		"preview": "",
		"remote": null,
		"previewRemote": null,
		"text": null,
		"meta": {
			"original": {
				"width": 1015,
				"height": 2042,
				"size": "1015x2042",
				"aspect": 0.4970617042115573
				"width": 338,
				"height": 680,
				"size": "338x680",
				"aspect": 0.4970588235294118
		"alt": "Alt text example",
		"blurhash": "USAAX:WFMtogouocMyWBjXa$f,jZIUWBxukC"
	"ats": [{
		"id": "110377043343501824",
		"username": "silk",
		"url": "",
		"acct": "silk"
	"handle": "@[email protected]",
	"rid": "[email protected]"

Service Usage

For ease of use, Silk provides an API and a web frontend.


Please refer to API.

Web frontend

The web frontend is expected to become publicly available at

If you have internal access, you might also be able to try it out at (NXDOMAIN expected).


A BroadcastChannel polyfill for Firefox 29+ and Chromium 5+, implemented with SharedWorker.

Snowy will not be active if BroadcastChannel already exists.


  • Place snowy.js under the root directory of your website.
    • If snowy.js needs to be placed somewhere else, set self.SNOWY_PATH to where snowy.js resides.
  • Run bc.js in your page to start the polyfill.


👾 The open pixel font for embedded LCDs.

SynPix is a union effort of GFHK-SDGM, PoneyClairDeLune and JayB.


Unicode Blocks

  • Latin-9
  • Some additional Latin alphabets, see below for details
  • IPA (U+0250 - U+029F, upcoming in version 0.3)
  • U+02C6 - U+02CF
  • Monotonic Greek (lacking some bare diacritics)
  • Cyrillic (only Russian, Ukrainian and pre-1918 Russian currently, see below for upcoming updates)
  • Armenian (upcoming in version 0.3)
  • Hebrew (basic letters only, no full Yiddish support yet)
  • Georgian (upcoming in version 0.3)
  • Cherokee (upcoming)
  • Runes (upcoming in version 0.3)
  • Tai Le (upcoming in version 0.3)
  • New Tai Lüe (upcoming)
  • Roman numerals (U+2160 - U+2165)
  • Bagua symbols (upcoming in version 0.3)
  • Astronomical symbols (upcoming in version 0.3)
  • Zodiac symbols
  • Coptic (upcoming in version 0.3)
  • CJK radicals supplement (partial complete)
  • Kangxi radicals (except 9 characters “⼢⼮⿋⿎⿏⿐⿒⿔⿕”)
  • CJK symbols and punctuation (、。々〇「」)
  • “Hangzhou” numerals
  • Hiragana (missing 3 characters “ぎぱぽ”)
  • Katakana (missing 5 characters “パヷヸヹヺ”)
  • Bopomofo
  • Hangul compatibility jamo (done for modern jamos)
  • CJKV Ideographs (see below for details)
  • Lisu (Fraser alphabet) (upcoming in version 0.3)
  • Phags-pa (upcoming)
  • Full-width ASCII (upcoming in version 0.3)
  • Half-width katakana
  • Half-width Hangul
  • Various currency symbols (partial complete, ¢£¥€¢£¥)
  • Gothic (upcoming?)

EU Official Languages

  • Bulgarian (done in basic Cyrillics)
  • Croatian (upcoming in version 0.3, no tone marks yet)
  • Czech (upcoming in version 0.3)
  • Danish (done in Latin-9, except Ǿǿ, which is done in 0.3)
  • Dutch (done in Latin-9, except digraph IJij, which is done in 0.3)
  • English (done in ASCII)
  • Estonian (done in Latin-9)
  • Finnish (done in Latin-9)
  • French (done in Latin-9)
  • German (done in Latin-9, except uppercase ẞ, which is done in 0.3)
  • Greek (currently monotonic only)
  • Hungarian (upcoming)
  • Irish (done in Latin-9 for modern orthography, old orthography upcoming)
  • Italian (done in Latin-9)
  • Latvian (upcoming in version 0.3)
  • Lithuanian (upcoming in version 0.3)
  • Maltese (upcoming in version 0.3)
  • Polish (upcoming in version 0.3)
  • Portuguese (done in Latin-9)
  • Romanian (upcoming in version 0.3)
  • Slovak (upcoming in version 0.3)
  • Slovene (upcoming in version 0.3, no tone marks yet)
  • Spanish (done in Latin-9)
  • Swedish (done in Latin-9)

Latin Alphabets

For the official languages of the European Union, refer to the list above.

  • Serbo – Croatian (Latin) (upcoming in version 0.3)
  • Esperanto (upcoming in version 0.3)

Romanization Systems

  • Hànyǔ PÄ«nyÄ«n

Cyrillic Alphabets

  • Russian
  • Ukrainian (Ґґ Єє Іі Її)
  • Pre-1918 Russian (four extra letters: Іі Ѣѣ Ѳѳ Ѵѵ)
  • Bulgarian
  • Belarusian (Іі, Ўў, upcoming in version 0.3)
  • Serbo – Croatian (Cyrillic) (Ђђ Јј Љљ Њњ Ћћ Џџ, upcoming in version 0.3, no tone marks yet)
  • Macedonian (Ѓѓ Ѐѐ Ѕѕ Ѝѝ Јј Љљ Њњ Ќќ Џџ, upcoming in version 0.3)
  • Mongolian (Cyrillic) (Ó¨Ó© Ò®Ò¯, upcoming in version 0.3)
  • Kazakh (Cyrillic) (Әә Ғғ Ққ Ò¢Ò£ Ó¨Ó© Ò°Ò± Ò®Ò¯ ÒºÒ» Іі, upcoming in version 0.3)
  • Uzbek (Cyrillic) (Ўў Ққ Ғғ Ò²Ò³, upcoming in version 0.3)
  • Kyrgyz (Ò¢Ò£ Ó¨Ó© Ò®Ò¯, upcoming in version 0.3)
  • Tajik (Ғғ Ó¢Ó£ Ққ Ó®Ó¯ Ò²Ò³ Ò¶Ò·, upcoming in version 0.3)

CJKV Ideographs

As of version 2023m27a, we currently have about 516 (?) unrepeated glyphs, 606 if counted the repeated ones.


Track me, senpai!

Exploiting reverse psychology to convince people switch to privacy-friendly browsers. Uses a combination of server-side detection and cookie storage.


Just deploy the page and the appropriate detection method.

Server-side detection

Server-side detection should not breach any privacy law, as the visitor is already supplying every possible information to the server.


header Accept-CH "sec-ch-ua-full-version,ua-full-version,sec-ch-ua-full-version-list"
@chromeVictims {
	header "Sec-CH-UA-Full-Version-List" *Chrom*
	not header "Cookie" *track-me-senpai*
	not path /track-me/*
@otherVictims {
	header "Sec-CH-UA" `*"Google Chrome"*`
	header "Sec-CH-UA" `*"Microsoft Edge"*`
	header "Sec-CH-UA" `*"Edge"*`
	header "Sec-CH-UA" `*"Opera"*`
	header "Sec-CH-UA" `*Arc*`
	not header "Cookie" *track-me-senpai*
	not path /track-me/*
redir @chromeVictims "/track-me/?src={uri}"
redir @otherVictims "/track-me/?src={uri}"

Client-side detection

Client-side detection may breach privacy laws. It will be developed if requested.


WingBlade is an abstraction layer targeting multiple JavaScript runtimes simultaneously. No TypeScript support is considered.

Projects utilizing WingBlade are expected to write web-oriented platform-agnostic code. For the most part, unless a better measure is found, WingBlade adheres to the Deno API scheme.


Open Source

Silk is a piece of open source software, licensed under GNU LGPL 3.0 or later.

Source code is available on the following code hosting services.




Report the amount of CPU cores.


Number: WingBlade.rt.cores



Exit the current runtime with given status code. 0 by default.


undefined: WingBlade.rt.exit(Number: code = 0);



Report memory usage of the current runtime. All values are in bytes.


MemoryUsage: WingBlade.rt.memory
	external: Number, // Memory associated with JS objects outside of the JS isolate.
	free: Number, // The size of available RAM.
	heapTotal: Number, // The total size of the heap of the JS engine.
	heapUsed: Number, // The size of the heap used by the JS engine.
	rss: Number, // Resident Set Size, aka memory occupied in RAM.
	total: Number // The total size of the RAM.



Indicate whether or not the current runtime is only allowed network access during triggering.

Useful for serverless functions.


Boolean: WingBlade.rt.networkDefer



Report the current operating system. Examples include windows, darwin and linux.


String: WingBlade.rt.os



Indicate whether or not the current runtime executes persistent sessions. If reports false, the runtime will only be activated upon triggering, and will be destroyed when the triggered tasks finish.

Useful for serverless functions.


Boolean: WingBlade.rt.persist



Report the name of the current runtime WingBlade runs on. Examples include Node, Deno and Bun.


String: WingBlade.rt.variant



Report the version of the current runtime WingBlade runs on.


String: WingBlade.rt.version

Environment variables


WingBlade.env can also be used as a normal JavaScript Object.



Return an environment variable, and supply a fallback value if given.


?String: WingBlade.env.get(String: key, ?String: fallbackValue);



Set an environment variable with given value.


undefined: WingBlade.env.set(String: key, String: value);



Remove an environment variable.


undefined: WingBlade.env.delete(String: key);



Indicate whether or not an environment variable exists.


Boolean: WingBlade.env.has(String: key);



Return a snapshot of all current environment variables as an Object.


Object: WingBlade.env.toObject();



Read the whole file as Uint8Array.


Promise<Uint8Array>: path, Object<ReadFileOptions>: opt);

Read Deno.ReadFileOptions for the opt params.



Write the whole Uint8Array as a file.


Promise<undefined>: WingBlade.file.write(String: path, Uint8Array: data, Object<WriteFileOptions>: opt);

Read Deno.WriteFileOptions for the opt params.




Return a random integer between 0 (inclusive) and a value given (exclusive).


Number: WingBlade.util.randomInt(Number: cap);



Sleep for a given amount of time (in milliseconds).


Promise<undefined>: WingBlade.util.sleep(Number: ms, ?Number: maxAdd = 0);


Web services



Start a web server with a handler function.


WebServer: WingBlade.web.serve(AsyncFunction<Response>: handler, ?ServeInit: opt = {});

Read ServeInit@std/http/server for more details.


let handler = async function (Request: request, ConnInfo: connInfo) {
	return new Response();



Upgrade the incoming request to a WebSocket connection.


UpgradedWebSocket: WingBlade.web.acceptWs(Request: req, UpgradeWebSocketOptions: opt);


	response: Response, // The upgrade response for the client
	socket: WebSocketServer // Server-side WebSocket


	protocol: String,
	idleTimeout: Number

Read Deno.UpgradeWebSocketOptions for details.



Upgrade the incoming request to a Server-sent Event (EventSink) connection.


UpgradedSSE: WingBlade.web.acceptSSE(Request: req);


	response: Response, // The upgrade response to the client
	socket: EventSink // Server-side EventSource

Web Stream

Quick ReadableStream convertion


If the stream exploits the same ArrayBuffer to emit chunks, at least on Deno, all of the readings will error out.

The Deno implementation may take twice as much RAM usage as on other runtimes.






Stream behaviour modification



Apply chunk-size normalization to the attached stream.

The chunk first gets written to the normalized buffer, and if the buffer exceeds the target chunk size, a normalized chunk will get emitted. If the attached stream closes, all remaining data in the buffer will also be emitted.


let object = new ChokerStream(Number: maxChunkSize = 1024, Boolean: alwaysCopy = false);
ChokerStream {
	alwaysCopy: Boolean, // Read-only. Disables zero-copy when available if set to true.
	chunk: Number, // A positive integer defining the normalized chunk size.
	source: ReadableStream, // Get the choked readable stream.
	sink: ReadableStream, // Read-only. The attached readable stream source.
	attach: function () {} // Attach to a readable stream source.