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.

Services

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.

Projects

POSIX Shell

  • 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.

Rust

  • Ensemble: 🎶 A synth framework in Rust.

Go

  • Floaty: ☁️ Prevent Caddy loopbacks... Without traceability.

Java

Kotlin

JavaScript

  • 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.
  • Ink Stone: 🖼 Modify font files with ease.
  • 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.
  • Rosegap: 🌹🌙 Pleasant ads without compromises.
  • 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.

Default

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.

Accessible

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.

Use

General

  • 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.

Low-importance

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.

Medium-importance

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.

High-importance

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

VPN

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.

Client

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

FAQ

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?

No.

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.

Definitions

  • 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.

Disclaimer

  • 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.

Software

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.

Donation

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, it's likely that you have been denied direct access to our UGC service, and we have no other choice but to offer our deepest apology.

List of countries affected

Denied from high-liberty and restricted UGC services

  • AE: United Arab Emirates
  • AF: Afghanistan
  • AZ: Azerbaijan
  • BD: Bangladesh
  • BH: Bahrain
  • BT: Bhutan
  • BY: Belarus
  • CN: China
  • CU: Cuba
  • DJ: Djibouti
  • DZ: Algeria
  • EG: Egypt
  • ER: Eritrea
  • ET: Ethiopia
  • GT: Guatemala
  • HN: Honduras
  • KH: Cambodia
  • KZ: Kazakhstan
  • IL: Israel
  • IN: India
  • IQ: Iraq
  • IR: Iran
  • LA: Laos
  • LB: Lebanon
  • LY: Libya
  • MM: Myanmar
  • NI: Nicaragua
  • NK (KP): North Korea
  • OM: Oman
  • PK: Pakistan
  • PS: Palestine
  • RU: Russia
  • RW: Rwanda
  • SA: Saudi Arabia
  • SD: Sudan
  • SL: Sri Lanka
  • SO: Somalia
  • SY: Syria
  • TJ: Tajikstan
  • TM: Turkmenistan
  • TR: Turkey
  • UZ: Uzbekistan
  • VE: Venezuela
  • VN: Vietnam
  • YE: Yemen

Denied from high-liberty UGC services

  • BO: Bolivia
  • CD: Democratic Republic of Congo
  • CM: Cameroon
  • GQ: Equatorial Guinea
  • HK: Hong Kong
  • KG: Kyrgyzstan
  • JO: Jordan
  • KW: Kuwait
  • LS: Lesotho
  • MA: Morocco
  • MX: Mexico
  • PE: Peru
  • PH: Philippines
  • SG: Singapore
  • SS: South Sudan
  • SV: El Salvador
  • UG: Uganda

Technologies

Preferred technologies

Languages and runtimes

Networking

Operating systems

Virtualization and containerization

Miscellaneous

Used technologies

Technologies listed here may have been used by some of our projects. None of the technologies listed below are a preference, though project can freely choose to use them.

Languages and runtimes

Virtualization and containerization

Miscellaneous

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

Miscellaneous

Banned technologies

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

Frameworks

Virtualization and containerization

Miscellaneous

Content encoding

None of the encodings listed are involved with patent concerns.

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

Read below for further details.

Rasterized image encoding

Lossy still

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.

Things to take notice of:

  • mozJPEG-fronted JPEG, while offering a good choice for backwards-compatibility, shouldn't be used unless necessary when size is a consideration. mozJPEG is generally superseded by jpegli.
  • AVIF offers an advantage on size, when progressive support, boundary artifacts and codec performance (slower than all others multiple times) aren't in consideration.
  • AVIF is observed to have fewer observable artifacts for images with a simpler shading.
  • The reference AVIF settings provide a balancing point between JXL -d 1 and JXL -d 2.
  • jpegli for JPEG from the JPEG XL team provides a reasonable front for backwards-compatible JPEG XL encoding. The estimated file size on fronted JPEG XL files are around 82.5% of the original JPEG files.

Explanations of image encoding uses:

  • Delivery: Size-first with generally-acceptable quality.
  • Delivery+: Balance between size and quality.
  • Near-lossless: Shaving as much size as possible, while still being mostly indistinguishable, even when zoomed in at 200%.
UsesSSIMULACRA2ButteraugliDSSIM
Delivery802.00.0008
Delivery+851.00.0004
Near-lossless90+0.4-0.0001-

The size ratio values listed below approach expectations on a large scale, based on experiments conducted on a relatively large scale with non-photographic images modelling 15.6% lossy inputs. Lossless inputs induce better (smaller) expectations, while lossy inputs tip the balance in reverse. Photograpic images will generally have a better (smaller) ratio than non-photographic images, but individual images may still yield greatly varied results.

Codec Use Params Ratio
JPEG XL Delivery (quality) cjxl -j 0 -d 2 -e 7 -p --progressive_dc 1 8.52%
Delivery (speed) cjxl -j 0 -d 2 -e 4 -p --progressive_dc 1 -
Delivery+ cjxl -j 0 -d 1 -e 7 -p --progressive_dc 1 14%
Near-lossless cjxl -j 0 -m 1 -d 0.2 -e 7 32.6%
WebP Delivery (quality) cwebp -m 5 -psnr 56 -qrange 90 99 21.2%
Delivery (speed) cwebp -m 5 -q 95 16.8%
Delivery+ cwebp -m 5 -q 99 -
Near-lossless cwebp -near_lossless 60 62.3%
JPEG Delivery cjpegli -d 1 -p 2 16.8%
AVIF Delivery [effort=4,lossless=false,Q=90] 15.7%

The full feature set comparison chart is available on Cloudinary.

Battle of the image codecs!

Lossless still

JPEG XL lossless and WebP lossless are mostly on par, either could be the better solution at times. For compatibility reasons, WebP lossless should always be offered, while JPEG XL lossless could be offered only when the resulting file is smaller than that of WebP lossless. AVIF lossless is currently consistently worse than either JPEG XL or WebP, as such it's not recommended at all.

Do not enable progressive encoding for JPEG XL lossless, or the resulting file will be several times bigger than PNG files.

CodecParametersRatio
JPEG XLcjxl -j 0 -d 0 -e 770.2%
WebPcwebp -m 6 -lossless78.1%

Lossy animated

Lossy animated WebP is the current baseline for animated image sequences, while lossy animated AVIF offers the best quality against others by a wide margin. Lossy animated JPEG XL doesn't offer a significant advantage against WebP, and is currently beaten by AVIF.

Audio encoding

Lossy

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.

CodecBasicStreamBalancedGenericQuality
Opus96kbps144kbps160kbps192kbps256kbps
Vorbis128kbps160kbps192kbps224kbps320kbps
AAC-LC128kbps160kbps192kbps224kbps320kbps

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

Lossless

Streaming lossless audio is generally considered a bad idea due to high bandwidth usage. It's generally more useful for archival purposes.

You should choose FLAC when...

  • Browser support is needed.
  • The target is severely underpowered.
  • The target only supports FLAC for lossless audio compression.

You should choose WavPack when...

  • You need a smaller file.
  • Higher bit depth is needed (more than 24).
CodecParameters
WavPackwavpack -hhvx -x 3
FLACflac -V8 -e --no-padding -f

Additional considerations:

  • If you do not intend to distribute high bit-depth lossless audio, but the input you have is of high bit-depth, you can re-sample it to somewhere between 16-bit (-96 dB) and 24-bit (-144 dB). Use --pre-quantize=16 for WavPack.

Compression

Web

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 dynamic content compression, zstd at level 8 consumes significantly less than the resources used for Brotli, all the while outperforming Brotli in terms of output size.

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. zstd isn't suitable for static precompression, as even at compression level 22 it falls behind Brotli at its highest compression level. However, a recommendation is still available for reasonable reference. Zopfli is an alternative compressor for gzip, which --i1 outperforms gzip even at level 9, however only --i1 and --i2 are recommeded for general use.

The table below provides a quick reference of levels and estimated size reduction by use case.

Algorithm Use Params Reduction
Ratio
Brotli Dynamic brotli -4 69.64%
Static brotli -q 11 73.41%
Zstd Dynamic zstd -7 69.82%
Static
(not recommended)
zstd -19 72.92%
gzip Dynamic gzip -4 66.48%
Static zopfli --i1 68.08%

On a case-by-case basis, Compression Tester could be used to see algorithms in action. For a more comprehensive comparison, Morotti's Compression Results could be used.

Bundle

lzip is the de-facto standard of bundle compression, featuring good compression ratio with data recovery abilities. Quality should always set to 9, unless a lower quality value is proven to yield a better result for smaller files, or time constraints are set.

bzip2 or xz should only be considered for compatibility purposes.

Font

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.

Region and DC codes

Datacentre codes

DC CodeCountryLocationNative Form
VIEATViennaWien
MELAUMelbourne, Victoria
SYDAUSydney, New South Wales
ANRBEAntwerp, FlandersAnvers, Flamande / Antwerpen, Vlaanderen
GHIBESaint-Ghislain, Hainaut, WalloniaSaint-Guilagne, Hénau, Walonnie
SOFBGSofiaСофия
TORCAToronto, Ontario
YBNCABeauharnois, QuebecBeauharnois, Québec
YHZCAHalifax, Nova Scotia
YULCAMontreal, QuebecMontréal, Québec
YVRCAVancouver, British Colombia
YWGCAWinnipeg, Manitoba
YYCCACalgary, Alberta
GVACHGenevaGenève
ZRHCHZurichZürich
DUSDEDusseldorf, North Rhine-WestphaliaDüsseldorf, Nordrhein-Westfalen
FALDEFalkenstein, BavariaFalkenstein, Bayern
FRADEFrankfurt, HesseFrankfurt, Hessen
LBGDELimburg, HesseLimburg an der Lahn, Hessen
MUCDEMunich, BavariaMünchen, Bayern
NUEDENuremberg, BavariaNürnberg, Bayern
BCNESBarcelona, CataloniaBarcelona, Cataluña
MADESMadrid
HELFIHelsinki, UusimaaHelsinki, Uudenmann
HMXFIHamina, Kotka-Hamina, Kymenlaakso
GVSFRGravelines, Dunkirk, Nord, Hauts-de-FranceGravelines, Dunkerque, Nord, Hauts-de-France
LILFRLille, Nord, Hauts-de-France
MRSFRMarseille, Bouches-du-Rhône, Provence-Alpes-Côte d'Azur
PARFRParis, Île-de-France
RBXFRRoubaix, Nord, Hauts-de-France
SXBFRStrasbourg, Bas-Rhin, Grand Est
BHXGBBirmingham, West Midlands, England
CVTGBCoventry, West Midlands, England
CWLGBCardiff, South Glamorgan, WalesCaerdydd, De Morgannwg, Cymru
LONGBLondon, Greater London, England
MANGBManchester, Greater Manchester, England
MDHGBMaidenhead, Berkshire, England
NWPGBNewport, Gwent, WalesCasnewydd, Gwent, Cymru
PSMGBPortsmouth, Hampshire, England
RDTGBRedditch, Worcestershire, England
HKGHKHong Kong香港
HKWHKTsuen Wan, Tsuen Wan, New Territories新界荃灣區荃灣
HTKHKTseung Kwan O, Sai Kung, New Territories新界西貢區將軍澳
BUDHUBudapest
JKTIDJarkata, Java, Indonesia
DUBIEDublin, LeinsterBaile Átha Cliath, Cúige Laighean
MILITMilan, LombardyMilano, Lombardia
ROMITRome, LazioRoma, Lazio
TRNITTurin, PiedmontTurin, Piemont / Torino, Piemonte
INZJPInzai, Chiba千葉県印西市
OSKJPŌsaka大阪府
TYOJPTökyö東京都
CCNKOChuncheon, Gangwon江原特別自治道春川市
ICNKOIncheon仁川廣域市
SOLKOSeoul서울特別市
LUXLULuxembourgLëtzebuerg
KIVMDChisinauChișinău
KULMYKuala Lumpur
AMSNLAmsterdam, North HollandAmsterdam, Noord-Holland
DRTNLDronten, Flevoland
EEMNLEemshaven, Het Hogeland, Groningen
HAGNLThe Hague, South HollandDen Haag, Zuid-Holland
HRLNLHaarlem, North HollandHaarlem, Noord-Holland
MPLNLMeppel, Drenthe
NLWNLNaaldwijk, South HollandNaaldwijk, Zuid-Holland
RTMNLRotterdam, South HollandRotterdam, Zuid-Holland
WMRNLWormer, North HollandWormer, Noord-Hooland
OSLNOOslo
TRFNOSandefjord, Vestfold og Telemark
GDNPOGdansk, PomeranianGdańsk, Pomorskie
WAWPOWarsaw, MasovianWarszawa, Mazowieckie
LISPTLisbonLisboa
EKTRUYekaterinburg, SverdlovskЕкатеринбург, Свердловская область
KHVRUKhabarovsk, Khabarovsk KraiХабаровск, Хабаровский край
KZNRUKazan, TatarstanКазань, Татарстан
MOWRUMoscowМосква
OVBRUNovosibirsk, Novosibirsk OblastНовосибирск, Новосибирская область
SPTRUSaint PetersburgСанкт-Петербург
VVORUVladivostok, Primorsky KraiВладивосток, Приморский край
STOSEStockholm
TNPSETjoernarp, ScaniaTjörnarp, Skåne
SGPSGSingapore
SGGSGJurong West, West Region西區裕廊西
SGSSGSimei, Tampine, East Region東區淡賓尼四美
ISTTRIstanbul, Marmaraİstanbul, Marmara Bölgesi
CHWTWChanghua County彰化縣
TPETWTaipei City臺北市
DNKUADnipro, Dnipropetrovsk OblastДніпро, Дніпропетровська область
HRKUAKharkiv, Kharkiv OblastХарків, Харківська область
IEVUAKyivКиїв
ASHUSAshburn, Virginia
ATLUSAtlanta, Georgia
BUFUSBuffalo, New York
CBLUSCouncil Bluffs, Iowa
CHIUSChicago, Illinois
CLBUSColombus, Ohio
DALUSDallas, Texas
DENUSDenver, Colorado
DLSUSThe Dalles, Wasco County, Oregon
EWRUSNewark, New York
FETUSFremont, California
FQCUS(Vint Hill,) Fauquier County, Virginia
HIOUSHillsboro, Portland, Oregon
HONUSHonolulu, HawaiiHonolulu, Hawaiʻi
HSTUSHouston, Texas
JAXUSJacksonville, Florida
LASUSLas Vegas, Nevada
LAXUSLos Angeles, California
MIAUSMiami, Florida
MSPUSMinneapolis, Minnesota
NYCUSNew York City, New York
PHXUSPhoenix, Arizona
PORUSPortland, Oregon
SCCUSSecaucus, New Jersey
SEAUSSeattle, Washington
SFOUSSan Francisco, California
SJCUSSan Jose, California
SLCUSSalt Lake City, Utah
SNUUSSanta Clara, California
STLUSSt. Louis, Missouri
TPAUSTampa, Florida
USBUSMoncks Corner, South Carolina

Versioning

Semantic versioning

Visit semver.org for more information.

Decaday versioning

Inspired by Minecraft's snapshot versioning appraoch, decaday versioning is used for projects releasing snapshots, where the versioning follows the YYYYdDDx, where YYYY denotes the full year, d can either be d or m in different projects (due to historical mistakes...), DD denotes the decaday of the year, and x denotes the ever-increasing alphabetical index of snapshot versions.

"Decaday" is a way of dividing months to three roughly equal portions, where it usually tries to group 10 days as a "decaday". In a typical month, the 1st to the 10th day belongs to the first decaday, the 11th to the 20th belongs to the second, and the 21st to the 30th belongs to the third. If a month has 31 days, the 31st day belongs to the third decaday. This approach avoids the problem of different choices in a week's starting point.

Take 2023d30b as an example. 2023 means the snapshot was released in 2023, 30 means the snapshot was released between 21st October and 31st October, and b indicates the version was released as the second snapshot between the time period.

Project origins

What led to LTGC projects?

  • Thestral: "Is oblivious user authentication possible?"
  • Nightglow: "Ugh the official Cloudflare WARP client is so crappy and I don't need that much functionality anyways!"
  • Scope: "No existing meshed WireGuard orchestration fits our needs!"
  • Octavia: "Can I make a better MIDI visualizer?"
  • shx: "I hate Node.js but I need something like npx."
  • SynPix: "Emulated screens bundled in Octavia need a libre bitmap font."
  • MIDI DB: "Why isn't there readily-available multi-standard MIDI data sheet?"
  • Hyacinth: "JS projects should be built faster!"
  • Painted Palette: "What if I made a better headless bot?"
  • WingBlade: "Can I make the same codebase run everywhere?"
  • (unnamed): "Let's build a clean, lightweight and ad-free boardgame experience!"
  • Linen: "Wanna run an r/place replica of our own?"
  • Cubics: "Want a convenient diagram generator for Rubik's cube-like puzzles..."
  • Raven: "I don't want to relearn a keyboard layout to type in another writing system."
  • (unnamed): "Wanna optimize Minecraft?"
  • Rosegap: "Daily Dose of Pony needs an ad system."
  • Ink Stone: "Will SynPix ever be released as font files?"

Where did names of projects come from?

Author Work Project Notes
Bucking Nonsense Cooking Roach Rochelle
Dee Pad A Wolf in Sheep's Clothing Daily Scoop
drFraud Accepting Change Patchwork
ItchyStomach Shed My Skin Mint Mint Flower (Split Horizon)
Jigsaw Cambiare Octavia Cambiare
Lauren Faust My Little Pony: Friendship is Magic Berry Berry Punch
Ditzy Ditzy Doo (Derpy Hooves)
Eclipsed S02E04, Luna Eclipsed
Flitter
Heartstrings Lyra Heartstrings
Inkwell Raven Inkwell
Minuette
Octavia
Raven Raven Inkwell
Rosegap Roseluck
Twinkle Sprinkles Twilight Sparkle
Random_User A Swift Message Graceful Lattice
Ink Stone
Swift Message
Starscribe Fine Print Rosegap Spark Gap (Tracy, or "Tracing")
Thadius0 Shifting Melodies Painted Palette
Scope Scope Lens
WingBlade Midnight Song's wing blade
Wanderer D The Three Sisters Acari

Project inspiration hiearchy

  • Project Moonlight (Media)
    • Heartstrings
    • Octavia
      • Cambiare
      • Ensemble
      • Hyacinth
        • shx
      • MIDI DB
      • Snowy
      • Swiftbook
      • SynPix
        • Ink Stone
  • Project Lilac (Translation, localization and linguistics)
    • Noitieng
    • Raven
  • Project Weaving (Networking and isolation)
    • Floaty
    • Nightglow
    • Patchwork
    • Scope
  • Uncategorized
    • Acari
    • Berry
      • Bread
    • Citrus
    • Crystal Quartz
    • Daily Scoop
    • Ditzy
    • Domain DB
    • Flex
    • Flitter
    • Graceful Lattice
    • Inkwell
    • Leaflet
    • LiteBlock
    • Mint
      • Flame
    • Minuette
    • Painted Palette
      • WingBlade
        • Eclipsed
        • Rochelle
        • Stratus
        • Twinkle Sprinkles
    • Patchwork
    • PonyTrails
      • Gel
        • Iceflakes
    • Rosegap
    • Seperatist
    • Silk
    • Thestral

List of technologies

JavaScript

Engines

Runtimes

NameEngineNode/NPM
DenoV8Manual
DuneV8Yes
Node.jsV8Yes
workerdV8No
BunJavaScriptCoreYes
SpiderfireSpiderMonkeyNo
WinterJSSpiderMonkeyNo
BareQuickJSNo
JavyQuickJSNo
LLRTQuickJSNo
txiki.jsQuickJSNo

List of sizes of data types

Numbers

Integers

GoRust/ZigJavaScalaKotlinC#C
boolboolbooleanBooleanBooleanboolbool
int8i8byteByteBytesbytesigned char
int16i16shortShortShortshort(signed) short
int32i32intIntIntint(signed) long
int64i64longLongLonglong(signed) long long
-i128-----
intisize---nint-
uint8u8--UBytebyteunsigned char
uint16u16charCharUShortushortunsighed short
uint32u32--UIntuintunsigned long
uint64u64--ULongulongunsigned long long
-u128-----
uintusize---nuint-
uintptr------
  • Aliases for certain integer types:
    • u8: byte (Go)
    • i32: rune (Go)
    • bool: _Bool (C)
  • GNU libc offers alternative types for intergers. Read more

Floats and more

GoRust/ZigJavaScala/KotlinC#C
-f16----
float32f32floatFloatfloatfloat
float64f64doubleDoubledoubledouble
-f128---__float128
complex64----float _Complex
complex128----double _Complex
  • The C# decimal type occupies 128 bits, but is different from f128.
  • long double in C varies in compiler implementations.
  • Some C implementations may use _Float128 for f128.

Lavender

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.

Access

Addresses

The service can be accessed from the addresses listed below.

Panels

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.

Moderation

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.

IM services

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

Services

Matrix

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.

Mumble

Planned. Internal and mixnet access only, with no clearnet access planned.

XMPP

We run a Prosody server with native mixnet access, for easier interfacing with the federated XMPP ecosystem. It is not intended for primary use, and its service availability is generally worse than Matrix.

Bridges

As long as adhereing to the Acceptable Usage Policy, members on our homeserver can freely use any of the bridges we host. Certain bridges offer integration to mixnets and overlay networks, namely I2P, Tor and Yggdrasil.

However, please note that integrations with alternative DNS systems (e.g. OpenNIC, ALFIS) likely will not work.

Group chat bridges

The following bridges support both group chats and direct messages.

Direct message bridges

The following bridges only support direct messages.

Voice chat bridges

The following bridges only bridge voice chats.

Media proxies

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 dma.ltgc.cc.

However due to poor design, the active Discord media proxy fails from time to time. We are working on a dedicated active media proxy written in either JS (Deno) or Go.

Passive Discord media proxy

Due to MSC3860 being unsupported on homeservers without conformation of the Matrix 1.7 specification, homeservers will not recognize discord-media.mau.dev, the public redirecting Discord media repo. To circumvent this, we offer a custom cached Discord media proxy at dmr.ltgc.cc instead for use with 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.

Bridge utilisation

Apply for use

Apart from internal use, we also offer bridging services to other entities upon approval with no SLA.

FLOSS projects

MLP fandom communities

Not-for-profit entities

Known issues

Global

  • 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!

Telegram

  • Reactions aren't bridged from Telegram.
  • The bridge suffers from unresponsiveness or even downtimes due to PostgreSQL. Migration to SQLite3 is currently scheduled.
  • 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.
  • Member leave events aren't bridged to Matrix, as such the Telegram member list on Matrix is not representative.

Discord

  • 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.
  • The Discord bridge invites bridged accounts to rooms on-demand, and does not bridge member leave events to Matrix, as such the Discord member list on Matrix is not representative.

Ditzy

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, Reliable UDP 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.

Advantages

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

Disadvantages

  • Directional speed penalty when not in stream mode
  • Not suitable for time-sensitive applications
  • Resource overhead on both servers and clients
  • Possible attack vector via decorated messages

Use cases

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

Specifications

Reference implementation API docs

  • JavaScript

Binary encoding format

Concepts

Meek

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

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. It could be thought of as a protocol of communicating changes about the states of instruments via a set of standardized messages.

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 within reason, and reduce the byte count when the value is smaller with little overhead.

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)
743010000110100001143
6430100001101000001 000000114103
71c5700011100
01010111
10111000
01010111
b857
7ad4129600001010
11010100
00010010
10010110
11010110
11010000
10100101
00010110
d6d0a516

RUDP

RUDP is a general-purpose transport running on top of UDP, designed to achieve guaranteed and ordered packet delivery without the overhead TCP brings. The exact protocol is never documented, but RUDP will always have the following features:

  • Acknowledgement of received packets
  • Flow control and windowing
  • Retransmission of lost packets
  • Over-buffering

Ditzy attempts to implement some of the features, optionally with twists:

  • Acknowledgement of last received packet IDs in each socket
  • Retransmission when messages are considered lost
  • Backpressure with customizable buffer/high watermark whenever possible
  • Transmit-ahead window whenever possible

QUIC

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.

Ditzy aims to achieve seamless connection migration via its client ID binding mechanism with minimal connection overhead.

Specification

Structure

Transmission

Client data socket
|
| Ditzy encoder
| |
| | Client transport
| | |
| | | (the state of the outermost transport is unrelated
| | |  to the states of the reconstructed data sockets)
| | v
| | Server transport
| v
| Ditzy decoder
v
Server data socket

Message

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

LengthValueDescription
1#CommandsCommand ID
1~4(7-bit VLV)Socket ID
1~4(7-bit VLV)Frame ID
1+(7-bit VLV)Payload length
0+(any)Payload data
1byteEnd of payload + (optional) data checksum

Socket ID

The socket ID is randomly selected between 1 and 268435455 (0xfffffff, 228 - 1).

Socket ID 0 is reserved for special purposes and is forbidden from transmitting any payload. It is used to deliver signals that could affect all connections of the client.

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. Frame ID should only be validated and increased in certain commands, check "Step?" to see if they undergo such process.

Length, EoP + Checksum

When Ditzy is set to fast mode (should only be used in safe environments), the payload length value only points to where the EoP byte is located. The EoP byte in fast mode only serves as a confirmation for bounds checking, and thus both sides should only select a random byte that has the 7th bit set to 0 (0~127) to do the job. When the supposed length doesn't match, Ditzy will discard all messages in the bundle completely in case of a decoration attack.

When Ditzy is set to strict mode, the payload length value is ignored, and Ditzy will attempt to validate the checksum once it finds the EoP byte. If the checksum does not match, Ditzy will discard all messages in the bundle completely in case of a decoration attack.

The checksum is calculated by setting the initial value to 63, and performing XOR operations to every byte in the payload. Once this is finished, the calculated value is then inverted, have 1 added. The final value would the the last 7 bits (0b0xxxxxxx) of the value. Example JavaScript code below.

let ditzyChecksum = (bytes) => {
	let checksum = 63;
	for (let i = 0; i < bytes.length; i ++) {
		checksum ^= bytes[i];
	};
	return (~checksum + 1) & 127;
};

Commands

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.

IDCommandLevelStep?
0Socket close1No
1Socket open1No
2Socket aftertouch / signalling1No
3Jump1No
4Full payload send1Yes
5Frame acknowledge1Yes
6Error2No
7Implementation exclusive2No
8Partial payload send3Yes
9Partial payload send continue3Yes
10Unordered tailing acknowledgement3No

0: Socket close

Can be initiated bidirectionally.

Response should be exactly the same as request.

Closes a single connection. Payload can be used to carry optional arbitrary printable error messages, UTF-8 encoded. Analogous to 8x nn vv or 9x nn 00.

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. Frame ID must be set to 0, or the message will be considered invalid.

(Optional) If sent from the receiving end, the value contains would be the final timeout value used in the connection. Analogous to 9x nn vv.

2: Socket aftertouch/signalling

Can be initiated bidirectionally.

Response should have the same frame ID as request.

Challenges a connection. Often used to implement socket latency tests. Analogous to cx vv.

Payload sets challenge type.

Types of aftertouch
  • 0: Latency test SYN1.
  • 1: Latency test ACK1.
  • 2: Latency test SYN2.
  • 3: Latency test ACK2.
Types of signalling
  • 128: Bind client ID, must be the very first message of every Ditzy connection. Frame ID contains the desired client ID. Each active connection can only have a client bound to an ID once, or the connection will be terminated to prevent flooding. Server response indicates a bound client ID.
  • 129: Client terminate. Frame ID contains the desired client ID, should match the client ID bound to the transmission session. All sockets managed under the provided client ID will be gracefully closed. Server response indicates a successful queue of graceful client termination.
  • 130: Saturated send buffer. Typically sent from the server to the client, this is used to signal the client to establish more connections with the server to help deplete its send buffer.

3: Jump

Can be initiated bidirectionally.

No responses are needed for jumps.

Sends a junk frame. The receiving end should ignore jump messages. Useful to implement noise.

4: Full payload send

Can be initiated bidirectionally.

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

Sends a full message. Analogous to f0 .. .. f7.

5: Frame acknowledge

Can be initiated bidirectionally. Only required over unreliable channels.

Sends acknowledgement of the last received sequencial frame.

6: Error

Can be initiated bidirectionally.

No response is needed for errors.

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. Analogous to f0 .. .. f7 or ff .. ..

8: Partial payload send

Can be initiated bidirectionally. Certain underlying transports may disable this.

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

Sends a segment of a message. Used to begin and continue sending the segments of a full message. The server should begin to interpret "full payload send" messages as "payload send complete" on the same socket. Analogous to f0 .. ...

9: Partial payload send continue

Can be initiated bidirectionally. Certain underlying transports may disable this.

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

Sends the final segment of a message. The server should interpret "full payload send" messages as "payload send complete" on the same socket. Analogous to f7 .. ...

10: Unordered tailing acknowledgement

Can be initiated bidirectionally. Only required over unreliable channels.

Sends a list of unordered received frames after the last continuously received frame. Used to reduce frame retransmissions when a copy has already been received.

After frame acknowledgement (message type 5) is sent, unordered tailing acknowledgements could be sent multiple times with the same frame ID as the preceding frame acknowledgement message, as long as the list of acknowledged frames aren't fully sent yet. Frame IDs are all encoded in 7-bit VLVs, with each VLV considered as an element of the list.

Recommended implementation practices

Ideas

Meek as a general terms, covers techniques reconstructing states of duplex sockets over underlying measures of communication. It doesn't have to be constrained to a single set of views. Under ideal circumstances, Meek can achieve full socket state decoupling with arbitrary socket delivery, however reaching those

Generic

Floaty

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.

Usage

Caddyfile

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.

Examples

Adding a response header with a default Floaty ID:

http://:8080 {
	...
	floaty
	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}
	}
	...
}

gel

⛏ 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 extensively used throughout Lightingale Community's infrastructure, either for host servers or for LXC containers. Read more on infrastructure.

Flavours

Gel mostly 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 the full version of Gel. It can also be used in other scenarios, if the full flavour contains packages you'd prefer not to be present on your system.

Full list

SlimFullNameLXC ready?LXC base size
slimalpalpineAlpine StableNo11 MiB
slimalmaalmaAlmaLinuxYes433 MiB
slimdebdebianDebian StableYes363 MiB
slimleapleapsuseopenSUSE LeapYes190 MiB
slimsuseopensuseopenSUSE TumbleweedNo-
slimrockrockyRocky LinuxYes433 MiB
photonN/APhoton LinuxNoN/A

Usage & Security

Installation

Native

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 https://github.com/ltgcgo/gel/releases/latest/download/install.sh). (or sh <(curl -Ls https://codeberg.org/ltgc/gel/releases/download/latest/install.sh), use GEL_SLIM=1 to enable slim installation)
  3. Connect via SSH with ssh -p 1122 <serverIP>. User passwords won't change, but SSH settings will. See the SSH section for details.

Containers

Container images are only offered as a convenient way of evaluating 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 docker.io/ltgc/gel:<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

Offloading RAM

Warning

Avoid offloading RAM in guests as much as possible, when the root host you have access to of the guest could have RAM offloading enabled instead.

Gel does not configure RAM offloading automatically in any way.

swap

When enabled, the system will swap memory pages used less frequently off the active RAM, freeing up system resources whenever possible. This will lessen the impact of memory hungry processes, at the cost of disk wear and tear.

swap comes in two types, disk partition and files. Swapfiles are generally not supported in certain file systems like btrfs, however they're much more flexible compared to disk partitions, since they could be created without threatening the underlying filesystem and can have multiple active simultaneously, as such swapfiles should be preferred whenever possible.

Depending on the actual size of RAM and remaining vacancy on the disk, the chosen size of the swap is generally between 50% and 200% of it. Generally for a system with small RAM (e.g. 1 GB), a swap with the size of 2 GiB is desired; for a system with large RAM (e.g. 32 GB), a swap with the size of 16 GiB could be considered sufficient. If you want to have hibernation enabled on your system, the swap size should be no smaller than the physical RAM.

To create a 2 GiB swapfile at /swapfile (1048576 * 1024 * 2), run the following commands as root.

dd if=/dev/zero of=/swapfile bs=1048576 count=2048
mkswap /swapfile
chmod 600 /swapfile

To enable the swapfile immediately, run the following command. Disabling the swapfile only needs to change the swapon command to swapoff.

swapon /swapfile

If the swapfile at /swapfile needs to be loaded automatically across reboots, open /etc/fstab and append the following line.

/swapfile   none    swap    sw  0   0

zswap

Notice

All steps demonstrated below do not persist across reboots. Read Setting up Zswap in Debian 11 GNU/Linux for persistence.

Requires swap to be enabled. zswap creates a compressed cache in RAM for system to swap pages off to, before the system decides to offload to the on-disk swap instead. Enabling zswap on top of swap helps to lessen the burden dumped onto the disk, make memory usage more efficient, while increasing responsiveness, as some of the infrequently accessed pages now resides in the much-faster RAM instead.

To see the current configurations for zswap, run the following command.

grep -R . /sys/module/zswap/parameters

Stastistics for zswap is also available.

grep -R . /sys/kernel/debug/zswap

Enabling zswap is as easy as running the following command as root.

echo 1 > /sys/module/zswap/parameters/enabled

zswap will use at most 20% of your actual RAM to store the compressed cache. Let's say you want to adjust the allocation percentage to 25%.

echo 25 > /sys/module/zswap/parameters/max_pool_percent

To see the current compression factor of the system, run the commands below.

cd /sys/kernel/debug/zswap
perl -E "say $(cat stored_pages) * 4096 / $(cat pool_total_size)"

Distributions typically choose lz4 or lzo as the compression algorithm for zswap, however zstd is also available for more powerful devices. lzo is slightly slower than lz4 for a slightly higher compression factor. lz4 is recommended for most use cases, which could be set with the command below.

echo lz4 > /sys/module/zswap/parameters/compressor

A list of typical compression factors is available below, as well as the source of the data.

AlgorithmFactor
lz42.1
lzo2.15
zstd3

The deer is always horny.

Alpine Linux

Additional repos

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

glibc compatibility

While not done by default, Alpine installations come bundled with a helper script configuring glibc compatibility. It may not work under every situation, but it should handle most use cases. root is required.

bash ~/gel/distro/sh/glibc.sh

openSUSE Leap

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

Security

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.

SSH

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.

Container setup

LXC

This section documents the processes of configuring LXC on distros supported by Gel.

Installation

  • Alpine: apk add lxc lxcfs lxc-download lxc-bridge
  • Debian: apt install lxc lxcfs lxc-templates uidmap libpam-cgfs bridge-utils --no-install-recommends
  • openSUSE: zypper in lxc
  • Rocky Linux/AlmaLinux: dnf install lxc lxcfs lxc-templates
  • Photon: N/A

Config files

  • Container config files: /var/lib/lxc/<name>/config

Container creation from official templates

When creating containers from official templates, you'll be presented with a list of available distros, alongwith release names and CPU architectures. Visit for the full list.

To select a source image directly without the selection prompt, use the following command.

lxc-create -t download -n "<name>" -- --dist <distro> --release <release> --arch <arch>

Assign static IPv4 addresses

From Setup network bridge in lxc-net.

Create /etc/lxc/dhcp.conf. The definitions go in dhcp-host=<containerName>,<ip> format. Example below.

dhcp-host=deerHorny,10.0.3.114
dhcp-host=polakCute,10.0.3.115

If /etc/default/lxc-net exists, have the following line inside to tell lxc-net use the DHCP config before restarting the lxc-net service.

LXC_DHCP_CONFILE=/etc/lxc/dhcp.conf

Enable autostart

In the container config, have the following lines.

# Enable autostart
lxc.start.order = <startOrder> # Lower is earlier
lxc.start.auto = 1
lxc.start.delay = 4 # In seconds

Enable nested containerization

In the container config, have the following lines.

# Allow nested containerization
lxc.include = /usr/share/lxc/config/nesting.conf

Enable FUSE

In the container config, have the following lines.

# Enable FUSE
lxc.mount.entry = /dev/fuse dev/fuse none bind,create=file,rw 0 0

Enable TUN

In the container config, have the following lines.

# Enable TUN
lxc.mount.entry = /dev/net dev/net none bind,create=dir
lxc.cgroup2.devices.allow = c 10:200 rwm

Limit CPU and RAM usage

From Memory Controller ・cgroup2.

In the container config, follow the example provided below.

# Limit CPU and RAM
lxc.cgroup2.memory.min = 268435456
lxc.cgroup2.memory.max = 536870912
lxc.cgroup2.cpu.max = 500000 1000000

This sets the container to...

  • Use at most 512 MiB of RAM (hard limit), with 256 MiB guaranteed (hard limit).
  • Allows using half of a core's worth of computing power.

Raise limits on opened files

From Proxmox ulimit hell: how to really increase open files ?

In /etc/sysctl.conf, make sure the following lines are present. Feel free to adjust the values to your needs.

fs.inotify.max_queued_events = 1048576
fs.inotify.max_user_instances = 1048576
fs.inotify.max_user_watches = 1048576
vm.max_map_count = 262144

In /etc/security/limits.conf, have the following lines. Feel free to adjust the values to your needs.

*     soft  nofile  1048576 unset
*     hard  nofile  1048576 unset
root  soft  nofile  1048576 unset
root  hard  nofile  1048576 unset
*     soft  memlock 1048576 unset
*     hard  memlock 1048576 unset

In the container config, have the following lines. Feel free to adjust the values to your needs.

# Raise limits on opened files
lxc.prlimit.nofile = 1048576

Inside the container, have the following lines in /etc/security/limits.conf. Feel free to adjust the values to your needs.

*     soft  nofile  1048576 unset
*     hard  nofile  1048576 unset
root  soft  nofile  1048576 unset
root  hard  nofile  1048576 unset
*     soft  memlock 1048576 unset
*     hard  memlock 1048576 unset

Reboot the host and the container(s) to apply the changes.

Manual unprivileged container setup

Extended from this blog post.

The containers configured these way are unprivileged, however they are owned by root, this is due to the problems surrounding unprivileged containers when owned by unprevileged users.

You can create the container before or after assigning subordinate IDs manually, but it must be done before modifying the container's configuration file. All commands in this section assume root privilege unless told explicitly otherwise.

Select and map subordinate IDs

Subordinate IDs permit mapping a range of IDs to a user, allowing the container to run unprivileged without the typical downsides. To avoid conflicts, it's advised to reserve a relatively large gap between different unprivileged containers in multiples of 65536, the minimum required amount of subordinate IDs for running unprivileged containers of any kind.

You'll be editing /etc/subuid for user IDs, and /etc/subgid for group IDs. Both files follow the same scheme: <username>:<startID>:<idCount>. For example, hornydeer:2097152:65536 maps IDs from 2097152 to 2162687 to user hornydeer, 65536 IDs in total. Comments are not allowed there.

As an example, we're setting the start UID and start GID to 1148576, and allocate 65536 IDs for use by the container. If you intend to have an LXC container act as a container host, you may need to scale up the count of IDs. Write the following line to both /etc/subuid and /etc/subgid.

root:1148576:65536

If you're going to run unprivileged containers inside the target unprivileged LXC, below is an example reserving enough subordinate IDs for use.

root:1148576:262144
Apply mapped IDs in configuration

To apply the mapped IDs, head to /var/lib/lxc/<containerName> and modify the config file. According to the containerized distro chosen, there may be seperate user namespace profiles, so switch to those if you encounter problems.

# Remapped user and group IDs
lxc.include = /usr/share/lxc/config/userns.conf
lxc.idmap = u 0 1148576 65536
lxc.idmap = g 0 1148576 65536

If you've chosen to use the larger ID space for unprivileged containers above, below is the corresponding example.

# Remapped user and group IDs
lxc.include = /usr/share/lxc/config/userns.conf
lxc.idmap = u 0 1148576 262144
lxc.idmap = g 0 1148576 262144
Change owner of the container root

Before the LXC container could be started, the owner of its root folder must be set as the beginning subordinate ID, 1148576 in the case of the example. Run the following command.

chown -R 1148576:1148576 /var/lib/lxc/<containerName>/rootfs

Also ensuring the container itself can access its own filesystem for good measure.

chmod 755 /var/lib/lxc # Most distros already has this as default
chmod 755 /var/lib/lxc/<containerName>
chmod 755 /var/lib/lxc/<containerName>/rootfs
chmod 640 /var/lib/lxc/<containerName>/config

nftables

The default config for nftables looks like this.

#!/usr/sbin/nft -f

flush ruleset

table inet filter {
	chain input {
		type filter hook input priority filter;
	}
	chain forward {
		type filter hook forward priority filter;
	}
	chain output {
		type filter hook output priority filter;
	}
}
  • It's possible to match multiple ports at the same time. Instead of specifying a single port number (e.g. 443), use curly braces: {443, 8443}. Ranges can also be specified: 1024-2047.
  • If a certain rule only applies to traffic originating from certain interfaces, prefix the rule with iif <interface>. Can be a single interface (e.g. iif "eth0") or multiple (e.g. iif {"eth0", "ens15"}).
Transparent service exposure

From nftables: forwarding without masquerading, Quick reference: nftables in 10 minutes.

Because the LXC host is the network gateway of all LXC containers, service exposure without masquerading is entirely possible, allowing services inside LXC slices to obtain the actual IP addresses. Add the block below to begin specifying rules for service exposure.

If you want to expose services on both IPv4 and IPv6, rules will need to be duplicated. It's also important to note that containers must have the respective IP version available, for it to be exposed transparently. LXC 6.0.0 and newer has IPv6 addresses assigned automatically, while 4.0.0 and newer can have IPv6 manually configured. Only LXC 5.0.0 and newer supports IPv6 connectivity behind NAT.

table ip nat {
	chain prerouting {
		type nat hook prerouting priority filter;
		# Insert new rules for IPv4 here
	}
}
table ip6 nat {
	chain prerouting {
		type nat hook prerouting priority filter;
		# Insert new rules for IPv6 here
	}
}

Let's say we want to expose 10.0.3.2:443 for anyone on the Internet to access on port 443.

tcp dport 443 dnat to 10.0.3.2

If the port numbers are not the same, the port will need to be overriden.

tcp dport 443 dnat to 10.0.3.2:8443

Or multiple ports are to be exposed without overriding the port.

tcp dport {443, 8443} dnat to 10.0.3.2
tcp dport 512-1023 dnat to 10.0.3.2

Or only expose access to (a) certain interface(s).

iif "eth0" tcp dport 443 dnat to 10.0.3.2
iif {"eth0", "vlan0"} tcp dport 443 dnat to 10.0.3.2

An example of a rule with similar use under IPv6.

iif "he-ipv6" tcp dport {80, 443} dnat to [fc11:4514:1919:810::ff:fe00:2]

Flush your rulesets with the command below, so LXC slices will still have connectivity via NAT after flushing.

nft -f /etc/nftables.conf; systemctl restart lxc-net
Network access restriction - IP-based

Inspired by How to restrict network access of LXC container.

Notice

nftable-based network access control is still under investigation. Problems are expected to rise.

If fine-grained access control like destination-matching (e.g. domain) is desired, use EEP with transparent proxy on the host instead.

Since the current nftables approach requires static IPs to be assigned first, but there is no way found to have IPv6 addresses assigned statically, IPv6 access might need to be disabled for the container.

The inet filter forward section is where network access of individual containers is filtered.

If whitelisted network access is desired, add a rule in the scheme shown below to the end of the section for that specific container.

iif "lxcbr0" ip saddr 10.0.3.2 drop;

Then add allowed access ranges before the final drop to grant access to specific addresses. If problems occur with transparent service exposure, they will need to be made exempt.

iif "lxcbr0" ip saddr 10.0.3.2 ip daddr 10.0.3.0-10.0.3.255 accept;

Or if network access isn't whitelisted, and access to certain ranges are to be blocked, add a rule in the scheme shown below.

iif "lxcbr0" ip saddr 10.0.3.2 ip daddr 10.0.3.2-10.0.3.255 drop;

Podman

This section documents the processes of setting up Podman on distros supported by Gel. To get Podman functioning, fuse and tun support has to be present.

If you're running Podman inside an (unprivileged) LXC container, make sure the steps listed below have all been applied to the host LXC container, all of which could be found above.

  • Assign a larger ID space
  • Enable FUSE
  • Enable nested containerization
  • Enable TUN
  • Raise limits on opened files

Installation

Warning

  • Certain distros (e.g. Debian) may not have a functioning version of crun. Install crun from Nixpkgs when such errors are encountered.
  • A few distros like Photon do not have podman-compose bundled.
  • If you encounter warnings regarding / not being shared, fix temporarily with mount --make-rshared /. Read Alpine Wiki for further info.
  • Alpine: apk add podman podman-compose
  • Debian: apt install podman podman-compose
  • openSUSE: zypper in podman podman-compose
  • Rocky Linux/AlmaLinux: dnf install podman podman-compose
  • Photon: tdnf install podman

After installation, run a "Hello World" container to ensure everything works correctly.

podman run --rm hello-world

If problems occur, below is an example command for debugging.

podman run --security-opt="seccomp=unconfined" --log-level=debug --rm hello-world

Manual subordinate ID assign

Note Distros may already have this section configured automatically. Only follow this section when you encounter problems.

Explanations about subordinate IDs are available in previous sections. If you encounter Podman complaining about IDs, below is an example inside unprivileged LXC containers to apply in both /etc/subuid and /etc/subgid.

<username>:65536:131072

Run podman system migrate whenever the assigned subordinate ID space changes.

Octavia

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

Features

  • 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

Demo usage

Support coverage

Implementation

SysEx documentation

API documentation

Visualizer

Warning

This section covers how to use the visualizers bundled as public demos, as such it does not reflect the behaviour of the respective modules themselves.

Things to notice

Rendering

  • Visualizers have strict render resolution constraints. For the best results, it is advised to only render while conforming to those resolution constraints.
  • Visualizers are all designed to render at 50 FPS. Some visualizers may offer custom framerates, however it is advised to only render at a framerate less than or equal to the capture framerate. Visualizers offered by Octavia, especially ones displaying individual notes, feature an algorithm guaranteeing notes to be displayed each frame. As such, a framerate too high will cause visualizers fail to show display immediate notes.

Usage

Input selectors

To begin using visualizers, you must select how you want to accept events. There are several options available.

Load MIDI files

You can load standard MIDI files (.mid or .kar), load SysEx blobs (.syx), load voice remapping tables (.mdat) or custom voice bank files with this action. An audio track must be loaded with the MIDI file.

Click on the "MIDI" button to load respective files. For multi-port MIDI files, port declarations via standard meta events and XGworks port assign events are all supported. Refer to multi-port extensions for details.

Load synced audio tracks

You can load an audio file synced to the accompanying MIDI file with this action. A MIDI file must be loaded with the audio file.

Click on the "audio" button to load synced audio tracks.

Receive from the shared line-in bus

When active, the visualizer will receive events from the shared line-in bus. Events received are directly emitted from the middleware without any modifications. Read MIDI I/O routing to acknowledge how to configure how MIDI events are received.

Click on the "line in" button to begin receiving from the bus. The button may appear as just "line" in some visualizers.

Receive from the shared line-out bus

Same as "line-in", but the events received will be processed by the Octavia core present on the middleware panel page. As such, events could've been modified if polyfilling or real-time translation has been enabled. Read MIDI I/O routing to acknowledge how to configure how MIDI events are received.

Click on the "line out" button to begin receiving from the bus. The button may not be present in certain visualizers.

Mode selectors

Octavia supports a range of modes ensuring correct state handling. Upon mode switches, the corresponding mode selector will be highlighted. Clicking on the mode selectors will change the global fallback mode of the core respectively.

Visualizer-specific options

Some visualizers come with additional options for configuring behaviour and look. These options are usually quite self-explanatory, but explanations for certain options considered obscure are also available below.

Demo selector

Octavia have two demo selection systems used by various public demo visualizers: letter ID and double selection.

Letter ID

This is the simplest selection system used. Demos are indexed by a unique letter from different writing systems. Simply hitting on one of the letters loads the respective demo, while depending on the visualizer, hovering over the letters may either expose the file name or some detailed info.

Double selection

Demos are grouped by collections. To select a specific demo, first select the desired collection, then select the desired file. Pressing the "load" button will load the demo, while long presses or alt clicks will load and play the demo.

Explore

Toggle authentic mode ("true mode")

To allow visualizers function normally after possible legal strikes, most visualizers render under the "libre" mode. In libre mode, assets used are replaced with libre counter parts as much as possible, with famous examples like the libre 5 by 7 font from SynPix.

However, it is also possible for certain visualizers to try resemble the real screens as much as possible under a specific rendering mode. This mode is dubbed "true mode" or "authentic mode", and can be accessed by appending #trueMode to the URLs of visualizers, or by pressing T.

Changing channels/parts

Single-focus visualizers can only display information from one channel at a time. Focused channel can be changed by clicking on the vertical edges (left and right edges) of such visualizers, or scrolling on such visualizers.

For production purposes however, it's recommended to embed channel switch SysEx messages among the events instead. Most, if not all Octavia visualizers, support the Yamaha MU channel switch SysEx message.

Changing display modes

Certain visualizers offer various rendering modes. You can switch between modes by clicking on the top or the bottom edges of these visualizers.

TopBottom
QYsong info, part infoN/A
PSRsong title, voice name, rhythmmeasure, tempo

Middleware

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

Reverb

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,
large)
Stage (1, 2)Stage (1, 2)Stage
Plate (XG, GM)PlatePlate (wet, dry)
Delay (LCR, LR)DelayDelay (stereo)Delay (stereo)
Echo
Cross DelayPanning DelayDelay (3-tap, 4-tap,
mod, 3D, trem.c.)
Delay (cross, dual, tap 1-3)
Early Reflection
(1, 2)
Early Reflection
(1-3)
Gate (forward, reverse)Gate (forward, reverse,
sweep 1-2)
White Room
Tunnel
Canyon
Basement
Karaoke (1, 2, 3)
Spring

Chorus

Yamaha XGGS ChorusGS InsertionKORG AI²

Delay

Yamaha XGGS DelayGS InsertionKORG AI²

Miscellaneous

Yamaha XGGS InsertionKORG AI²

Dual effect

Mutual

  • X: Yamaha XG
  • G: Roland GS
  • A: KORG AI²
RevChoOvrDstEnhFlnDlyRotPhsAmpCmpAWa
RevA
ChoGGGGGA
OvrGGGXGAXGGXG
DstGGXGAXXX
EnhGGG
FlnGGGGGA
DlyAGAXGAXGAGGAAAA
RotXGXAXX
PhsGA
AmpX
CmpX
AWaXGX

RPN/NRPN values

RPN/NRPN values

Voice data maps

Types

ID maps

TSV files mapping MSB, PRG and LSB into voices.

  • MSB: cc0 (bank MSB) value of the voice.
  • PRG: PC (program change) value of the voice.
  • LSB: cc32 (bank LSB) value of the voice.
  • NME: 8-character ID of the voice.
  • ELC: Element count (minus one) of the voice.
    • When set to 0, the voice takes up one element. 1 for two, 2 for three, the same goes on.
    • When set to 16, the voice is treated as a drum kit.
    • When set to 17, the voice is treated as a voice menu.
    • Any value above is not defined.
  • DRM: Drum map ID used. Can also be used by voice menus.
  • VXP: Voice property map ID used.

Drum maps

Custom script files defining properties of drum kits and their voices.

  • drm defines the current drum map ID to write to.
    • e.g. drm xgStdKit switches to xgStdKit.
  • dcp copies parameters from a set drum kit.
    • e.g. dcp xgStdKit copies parameters from xgStdKit to the current drum kit.
  • nno defines the current drum note number to write to.
    • e.g. nno 39 switches to 39.
  • npw writes multiple parameters to a single drum note.
    • npw <note> <exclusiveGroup> <elementCount>
  • neg sets the exclusive group (aka. alternate assign) of the current note number. Defaults to 0 (disabled).
  • nec sets the note element count of the current note number. Defaults to 1.

Voice property maps

TSV files describing certain properties of individual voices.

  • VXP: Voice property ID

VL properties

  • BNS: VL Breath Noise Source
    • 0: None
    • 1: Modulation wheel
    • 2: Blow strength
    • 4: Throat formant
  • BNM: VL Breath Noise Amplitude from Mod Wheel
    • 0: -1
    • 64: 0
    • 127: 1
  • BNB: VL Breath Noise Amplitude from Blow Strength
  • BNT: VL Breath Noise Amplitude from Throat Formant
  • BNV: VL Breath Noise Value Floor
    • -128: -1
    • 0: 0
    • 127: 1
  • BND: VL Breath Noise Blow Strength Decay Duration
  • BNL: VL Breath Noise Blow Strength Decay Level
  • BAD: VL Breath Attack Duration, specified in milliseconds
  • BAL: VL Breath Attack Level
    • 0: -64 (from a very wide triangle)
    • 64: 0 (no attack EG)
    • 127: 63 (from a very narrow triangle)
  • BDD: VL Breath Decay Duration, specified in milliseconds
  • BDL: VL Breath Decay Level
    • 0: Decay to 0 (pluck)
    • 64: Decay to 50.4%
    • 127: No decay
  • TOM: VL Throat Formant Oscillation from Modulation
    • 0: None
    • 127: Maximum
  • TOS: VL Throat Formant Oscillation Speed, specified in milliseconds when a cycle completes.
  • TOT: VL Throat Formant Oscillation Type
    • 0: None
    • 1: Single oscillator
    • 2: Double oscillator (single oscillator modulated by an additional LFO)
  • TFS: VL Throat Formant Source
    • 0: Constant until set
    • 1: cc1 (Modulation wheel)
    • ...
    • 13: cc13 (default VL throat formant source)
    • ...
    • 32: Always constant
  • TFV: VL Throat Formant Value, the fixed default value for certain instruments.

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 Source Note
88 High Resolution Velocity
Store only
91 Effect 1 Send (Reverb)
92 Effect 2 Send (Tremolo)
93 Effect 3 Send (Chorus)
94 Effect 4 Send (Variation/Delay)
95 Effect 5 Send (Phaser)
96 Data Increment
97 Data Decrement
98 LSB NRPN
99 MSB NRPN
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)
Registered Parameters 0x0000 Pitch Bend Range/Sensitivity
0x0001 Fine Tuning
0x0002 Coarse Tuning
0x0005 Modulation Depth
0x3d00 3D Azimuth Angle
0x3d01 3D Elevation Angle
0x3d02 3D Gain
0x3d03 3D Distance Ratio
0x3d04 3D Max Distance
0x3d05 3D Gain at Bound
0x3d06 3D Reference Distance Ratio
0x3d07 3D Pan Spread Angle
0x3d08 3D Roll Angle
Non-Registered Parameters 0x0108 Vibrato Rate
Redirected to cc76
0x0109 Vibrato Depth
Redirected to cc77
0x010a Vibrato Delay
Redirected to cc78
0x0120 Brightness (LPF Cutoff)
Redirected to cc74
0x0121 Resonance
Redirected to cc71
0x0124 HPF Cutoff
0x0130 EQ Bass Gain
0x0131 EQ Treble Gain
0x0134 EQ Bass Frequency
0x0135 EQ Treble Frequency
0x0163 Attack Time
Redirected to cc73
0x0164 Decay Time
Redirected to cc75
0x0166 Release Time
Redirected to cc72
0x14rr Drum Brightness (LPF Cutoff)
0x15rr Drum Resonance
0x16rr Drum Attack Time
0x17rr Drum Decay Time
0x18rr Drum Coarse Tuning
0x19rr Drum Fine Tuning
0x1arr Drum Level
0x1crr Drum Pan
0x1drr Drum Reverb Send
0x1err Drum Chorus Send
0x1frr Drum Variation/Delay Send
0x24rr Drum HPF Cutoff
0x30rr Drum EQ Bass Gain
0x31rr Drum EQ Treble Gain
0x34rr Drum EQ Bass Frequency
0x35rr Drum EQ Treble Frequency
Program Change ✓ 0-127
System Exclusive General MIDI
General MIDI rev. 2
YAMAHA XG
YAMAHA PLG-150AP
YAMAHA PLG-150AN
YAMAHA PLG-150DR/PC
YAMAHA PLG-150DX
YAMAHA PLG-150PF
YAMAHA PLG-100SG
YAMAHA PLG-150VL
YAMAHA TG300
Roland GS
Roland SD
Roland C/M
KORG NS5R
KORG N1R Redirected to NS5R
KORG X5D(R)
KORG 05R/W
KAWAI GMega Also known as KAWAI K11
AKAI SG01
CASIO GZ-50M
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

For a list of supported modes, refer to state.mjs internal mode IDs.

Supported SysEx Instructions

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

Mutual instructions

GMGM2MT-32XGGS05R/WX5DNS5RSDGMegaGMega LXSG-01GZ-50M
System reset
Master setup
Reverb setup
Chorus setup
Variation setup?
Part setup?
Equalizer
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

KORG X5D

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

KORG NS5R

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

Targets

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. For a list of supported modes, refer to state.mjs internal mode IDs.

VendorTargetTypeBankSysEx
MMAGMS
MMAGM2S
RolandMT-32S
RolandGSS
RolandSDS
YAMAHATGL
YAMAHAXG¹S
YAMAHAPLG-150ANP-
YAMAHAPLG-150APP
YAMAHAPLG-150DRP
YAMAHAPLG-150DXP-
YAMAHAPLG-150PCP
YAMAHAPLG-150PFP
YAMAHAPLG-150VLP
YAMAHAPLG-100SGP
YAMAHAS90 ESL
YAMAHAMotif ESL
KORGAG-10M
KORG05R/WL
KORGX5DRL
KORGNS5R/NX5RL
KAWAIGMegaL
KAWAIGMega LXM
AKAISG01kM
CASIOGZ-50MM
ALESISNanoSynthM
  1. Octavia implements XG level 3.0 or later, and XG version 2.0 or later.

Custom sound banks

  • Voice name maps (.mdat)
  • SysEx bank dumps (.syx)
    • KORG X5 (05R/W)
    • KORG X5D (X5DR)
    • KORG NS5R (NX5R)
    • KORG Trinity
    • Yamaha PLG-AN (AN200)
  • Yamaha S90 ES Voice Editor (.s7e)
  • Yamaha Motif ES Voice Editor (.w7e)
  • Korg Program/Combi/Global (.pcg)
    • Korg KROSS 2

Specific targets

Roland MT-32

TargetTypeStatus
MT-32M
MT-100M-
CM-32LM
CM-32LNM-
CM-64M-
CM-500M-
LAPC-IM-
LAPC-NM-
RA-50M-
E-20M-

Roland GS

TargetTypeStatus
CM-300M
SC-55L
SC-88L
SC-88 ProL
SC-8850L
SD-20M
SD-35M
SD-50M
SD-80M
SD-90M
SK-50L-

Yamaha TG

TargetTypeStatus
TG55M-
TG33M-
TG77M-
TG100M-
TG500M-
TG300M

Yamaha XG

TargetTypeStatus
DBXG50M
DBXG51M
DBXG60M
MU5M
MU80M
MU50M
MU90L
MU10M
MU100L
MU15M
MU128L
MU1000L
MU2000L
MU500M
PLG100-XGP
QY700M
QY70M
QY100M
SW60XGM
SW1000XGM
S-YXG50M
S-YXG70M
S-YXG100M
S-YXG2006LEM

Octavia standard visualizers

Octavia comes with a set of modular standard visualizers with each release.

For a guide on how to use the public demos, refer to demo visualizer usage.

Visualizers

Octavia Cambiare

  • Lead developer: Lumière Élevé

The most feature-rich visualizer built on top of Octavia available. Inspired by MegaMID, vanBasco Karaoke Player and TiMidity++, Octavia Cambiare is designed from the ground up, and seeks to entirely replace what inspired it.

Octavia MU

  • Lead developer: Lumière Élevé

A recreation of the screens on the Yamaha MU line up. Bitmap is collected with collective effort.

The font used for labels is Public Sans, licensed under SIL OFL.

Bitmap contributors

Special thanks to all of the people who had contributed the MU bitmap! If you see your name missing here, please contact us for proper credits.

  • MIDIMan
  • Lumière Élevé
  • GFHK-SDGM
  • MJG0117

Octavia SC

  • Lead developer: Lumière Élevé

A recreation of the screens on Roland SC-55, Roland SC-88 and Roland SC-88 Pro.

The font used for labels is Work Sans, licensed under SIL OFL.

Octavia NS5R

  • Lead developer: Lumière Élevé

A recreation of the screens on KORG NS5R, with help from JayB.

The font used for labels is Jost, licensed under SIL OFL.

Octavia QY

  • Lead developer: Lumière Élevé

A recreation of the screens on the Yamaha QY line up, with help from JayB.

Octavia PSR

  • Lead developer: GFHK-SDGM

A recreation of the screens on Yamaha PSR.

Octavia SC-8850

  • Lead developer: Lumière Élevé

A recreation of the screen on Roland SC-8850.

Bitmap contributors

Special thanks to all of the people who had contributed the SC-8850 bitmap!

  • SSQMinky
  • MasteredRealm
  • Thorndust
  • GFHK-SDGM
  • Lumière Élevé

Octavia MU15

  • Lead developer: Lumière Élevé

A recreation of the screen on Yamaha MU15.

Support and specification table

MUSCNS5RQYPSRSC-8850MU15CambiareTUI
Max name length81210²88128248
Max shown parts64641288164646416
PC# start index111Both1110N/A
Voice detailsPBPPBPFPPBPPFN
Current modeBLCBBLDBCDD
Voice bitmap
Letter display
Bitmap display
Wider bitmap
Screen dump
Chord display¹
Pixel blur✓³✓³✓³
Lyrics
Song title
Meta events
Effect sends
Effect types
Switch part
PB/Transpose
Current position
VL monitor
DX monitor
User sound sets
Custom MDAT

Voice details

  • N: Name only
  • P: With program number
  • B: With bank number
  • F: With full bank numbers

Current mode

  • B: Bitmap prompt
  • L: Letter prompt
  • C: Colour change
  • D: Dedicated slot

Additional notes

  1. Planned feature, not yet implemented.
  2. Octavia NS5R can render voice names with at most 12 characters under certain conditions.
  3. Except for Octavia MU, Octavia PSR and Octavia MU15, the intensity of pixel blur is customizable.

state.mjs API

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

Constants

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. GS is short for General Sound.
  • xg: Yamaha XG mode. Compatible with TG-100 and TG-300. XG is short for eXtended General.
  • sc: Roland GS mode, but with mode 1 or mode 2 set. Specific to Roland SoundCanvas SC-88 and up.
  • g2: General MIDI Level 2 mode.
  • sd: Roland SD mode. SD is used for Roland's Studio Canvas lineup.
  • 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 or K11 mode.
  • sg: Akai SG mode.
  • krs: KORG KROSS 2 mode.
  • s90es: Yamaha S90 ES mode.
  • motif: Yamaha Motif ES mode.
  • mt32: Roland MT-32 mode.
  • doc: Yamaha DOC mode. DOC is short for Disk Orchestra Collection.
  • qy10: Yamaha QY10 native mode.
  • qy20: Yamaha QY20 native 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

allocated

ccToPos

Interfaces

OctaviaDevice

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.

Requirements

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

Piano

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

Chromatic percussion

PC#Voice Name
008Celesta
009Glockenspiel
010Music Box
011Vibraphone
012Marimba
013Xylophone
014Tubular Bells
015Dulcimer1
  1. Some implementations may swap Dulcimer out with Santur.

Organ

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

Guitar

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

Bass

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
040Violin
041Viola
042Cello
043Contrabass
044Tremelo Strings
045Pizzcato Strings
046Harp
047Timpani

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

Brass

PC#Voice Name
056Trumpet
057Trombone
058Tuba
059Muted Trumpet
060French Horn
061Brass Section
062Synth Brass 1
063Synth Brass 2

Reed

PC#Voice Name
064Soprano Saxophone
065Alto Saxophone
066Tenor Saxophone
067Baritine Saxophone
068Oboe
069English Horn
070Bassoon
071Clarinet

Pipe

PC#Voice Name
072Piccolo
073Flute
074Recorder
075Pan Flute
076Blown Bottle
077Shakuhachi
078Whistle
079Ocarina

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
097Soundtrack
098Crystal
099Atmosphere
100Brightness
101Goblins
102Echo Drops
103Sci-Fi

Ethnic

PC#Voice Name
104Sitar
105Banjo
106Shamisen
107Koto
108Kalimba
109Bagpipe
110Fiddle
111Shanai

Percussive

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

Sound effects

PC#Voice Name
120Guitar Fret Noise
121Breath Noise
122Seashore
123Bird Tweet
124Telephone Ring
125Helicopter
126Applause1
127Gunshot
  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

Events

Assembly

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.

Types

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

System message types

ID#IDTypeOptional
2400xf0System Exclusive (Start of Exclusive)No
2470xf7System Exclusive (End of Exclusive)No
2480xf8ClockYes
2500xfaStartYes
2510xfbContinueYes
2520xfcStopYes
2540xfeActive sensingYes
2550xff(Line invalid) Meta eventsNo

Types

Control Changes

Mapping

Data

ID#IDTypeRangeOptional
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

Voice

ID#IDTypeRangeOptional
10x01Modulation0-127No
50x05Portamento Time0-127No
70x07Volume0-127No
100x0aPan0-127No
110x0bExpression0-127No
640x40Sustain (Hold)0-127No
650x41Portamento Switch0-127No
660x42Sostenuto0-127No
670x43Soft Pedal0-127No
710x47Resonance0-127No
720x48Release Time0-127No
730x49Attack Time0-127No
740x4aBrightness0-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

Modes

ID#IDTypeRangeOptional
1200x78All Sound Off0No
1210x79Reset All Controllers0No
1230x7bAll Note Off0No
1240x7cOmni Off0Yes
1250x7dOmni On0Yes
1260x7eMono0-16No
1270x7fPoly0No

Types

Registered Parameter Numbers

Non-registered Parameter Numbers

Warning

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.

Features

  • 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)

Installation

Warning

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!

Windows

  1. Download the latest version of node_windows.zip.
  2. Extract node_windows.zip 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 https://github.com/ltgcgo/painted-palette/raw/main/src/bash/install.sh).

Running

Warning

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 127.0.0.1:14514 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>.

Podman/Docker

  • Clone the repo via git clone https://github.com/ltgcgo/painted-palette.git 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

WIP

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=http://127.0.0.1:4444/). 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>

Examples:

  • 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>

Subcommands

r/place 2023

Warning

Information on this page is outdated.

Written on 22nd June 2023

Warning

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?

Pros

  • 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

Cons

  • 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.

raven

💨 Lightning-fast intuitive typing.

Target scripts

Usage

m17n

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.

Linux

  • 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.

Android

Warning

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

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.

Linux

  • 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.

Windows

  • 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.

Android

fcitx5-android

TBD.

Trime

TBD.

Key map

Consonants

KeymapARUR/FAUG
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)

Vowels

Letters with hamza

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

Numbers

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.

KeymapARUR/FAUG
0٠۰٠
1١۱١
2٢۲٢
3٣۳٣
4٤۴٤
5٥۵٥
6٦۶٦
7٧۷٧
8٨۸٨
9٩۹٩

Punctuations

Chinese Bopomofo

A non-Latin transliteration system for Standard Chinese and other Sinitic languages.

Key map

Keys are mainly ordered via native Bopomofo ordering. Spaces are used for stream breaking.

Consonants

Standard

SequenceBopomofoPinyinGenericSymbols IIWade-GilesPostal¹
bbbbpp
pppp
mmmmmm
ffffff
ddddtt
tttt
nnnnnn
llllll
ggggkk
kkkk
hhhhhh
jjjijichitsi; ki
qqcichichʻitsʻi; kʻi
xxsishihsisi; hi
Zzhjhjchch
Cchchchchʻchʻ
Sshshshshsh
rrrrjj
zzztztsts
ccctstsʻtsʻ
ssssss
iyyyyy
Iyyyyy
uwwwww
Uyuyuyuyuyu
vv--vv
Nng--ngng
Ggn--gngn
mm---mm
nnnnnnn
NNngngngngng
  1. Aspirations have been added to better distinguish between consonants.

Extension

SequenceBopomofo
B
V(non-Unicode)
D(non-Unicode)
L
G
H
Q
K
R(non-Unicode)
N/A(non-Unicode)
J
X(non-Unicode)
N/A(non-Unicode)
N/A
N/A(non-Unicode)

Vowels

Standard

SequenceBopomofoPinyinGenericSymbols IIWade-GilesPostal
aaaaaa
oooooo
eeeeo/ê/ehe
ehêeeeheh
iiiiii
Iiiiii
uuuuuu/uh
Uüyuiuüü
ihiihrih/ŭih/ŭ
uhiihrih/ŭih/ŭ
aiaiaiaiaiai
eieieieieiei
ui ueiㄨㄟuiueiueiui/ueiwei
ao auaoaoauaoao
ouououououow
iu iouㄧㄡiuiouiouiuiu
Iu Iou丨ㄡiuiouiouiuiu
anananananan
enenenenenen
in ienㄧㄣininininin
In Ien丨ㄣininininin
un uenㄨㄣununuenunun
Un Uenㄩㄣünyuniunünün
aNangangangangang
eNengengengêngêng
iN ieNㄧㄥinginginginging
IN IeN丨ㄥinginginginging
oN uN ueNㄨㄥongongungungung
UN UeNㄩㄥiongyongiungiungiung
ie iehㄧㄝieieieiehieh
Ie Ieh丨ㄝieieieiehieh
Ue Uehㄩㄝüeyueiueüehüeh
ererererêrhêrh

Additional combinations

BopomofoPinyinGenericSymbols IIWade-GilesPostal
ㄧㄚiaiaiaiaia
ㄨㄚuauauauawa
ㄨㄛuouououowo
ㄨㄞuaiuaiuaiuaiwai
ㄧㄠiaoiaoiauiaoiao
ㄧㄢianianianienien
ㄨㄢuanuanuanuanwan
ㄩㄢüanyuaniuanüanüan
ㄧㄤiangiangiangiangiang
ㄨㄤuanguanguanguangwang

Extension

SequenceBopomofo
N/A
A
O
On
N/A(non-Unicode)
N/A(non-Unicode)
N/A
N/A
E
N/A(non-Unicode)
N/A
N/A
N/A
N/A
N/A
N/A
on(non-Unicode)
N/A

Tailing

SequenceBopomofo
W
Wb
Wd
Wg
W1ˉ
W2ˊ
W3ˇ
W4ˋ
W5˙
W6˪
W7˫

Cyrillic script

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

Warning

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

Vowels require at most two keys.

Short vowels

SequenceBEPAShavianDeseretExample
Aæ𐑨𐐰cat
e ehɛ𐑧𐐯bet
Ee EEe𐑧𐐯bet
i ihɪ𐑦𐐮fit
o ohɒ𐑪𐐱hot
a ahʌ𐑳𐐲cut
u uhʊ𐑫𐐳cook
E Ehə𐑩𐐲lover
Ii𐑦𐐨unity
Uu𐑫𐐭

Long vowels

SequenceBEPAShavianDeseretExample
ii𐑰𐐨eat
ooɔː𐑷𐐫all
eeɜː𐑻𐐲𐑉her
uu𐑵𐐭who
aaɑː𐑭𐐪car

Diphthongs

SequenceBEPAShavianDeseretExample
ei𐑱𐐩cake
ai𐑲𐐴like
oiɔɪ𐑶𐑎oil
euəʊ𐑴𐐬coat
ou𐑴𐐬hope
au𐑬𐐵how
irɪə𐑾𐐮𐐲ear
erɛə𐑺𐐯𐑉air
urʊə𐑫𐑩𐐳𐐲sure

Shavian compatibles

SequenceBEPAShavianDeseretExample
aRɑːr𐑸𐐪𐑉art
oRɔːr𐑹𐐫𐑉/𐐬𐑉ore
eRɛər𐑺𐐯𐑉air
Erər𐑼𐐲𐑉lover
ERɜːr𐑻𐐲𐑉hurt
iRɪər𐑽𐐮𐐲𐑉ear
yUjuː𐑿𐑏you

Consonants

None of the consonants require two keys.

Voiceless-voiced pairs

SequenceBEPAShavianDeseretExample
pp𐑐𐐹pat
bb𐑚𐐺bat
tt𐑑𐐻tie
dd𐑛𐐼deer
kk𐑒𐐿cat
gg𐑜𐑀get
ss𐑕𐑅sit
zz𐑟𐑆zip
ff𐑓𐑁fit
vv𐑝𐑂van
Tθ𐑔𐑃thank
Dð𐑞𐑄mother
Sʃ𐑖𐑇shell
Zʒ𐑠𐑈vision
C𐑗𐐽chips
j𐑡𐐾juice
qtr𐑑𐑮𐐻𐑉try
Qdr𐑛𐑮𐐼𐑉dry
cts𐑑𐑕𐐻𐑅hats
Jdz𐑛𐑟𐐼𐑆hands

Aspirated, nasal and etc

SequenceBEPAShavianDeseretExample
hh𐑣𐐸hat
Hx𐑣𐐸loch
mm𐑥𐑋mad
nn𐑯𐑌nod
Nŋ𐑙𐑍ring
ll𐑤𐑊luck
rr𐑮𐑉ring
yj𐑘𐐷you
ww𐑢𐐶way

Specials

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

SequenceBEPAShavianDeseretDescription
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.

Merged key map

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

Vowels

KeymapIPAMongolianManchuSibeTodo
aɑ
eə
ii
oɔ
uʊ
Oo
Uu
Ee
Iɨ
``ː

Consonants

KeymapIPAMongolianManchuSibeTodo
nn
Nŋ
bb
pp
hx
gg
mm
ll
ss
Sʃ
tt
dd
ct͡ʃ (t͡s)
jd͡ʒ (d͡z)
yj
rr
ww
ff
kk
Kk
Gk
Hk
Ct͡s
Jd͡z
xx
Rʐ
Lɬ
Zd͡ʐ
Tt͡ʂ

Split key map

Mongolian

Vowels

U+KeymapIPAMongolian
1820aɑ
1821eə
1822ii
1823oɔ
1824uʊ
1825Oo
1826Uu
1827Ee

Consonants

U+KeymapIPAMongolian
1828nn
1829Nŋ
182Abb
182Bpp
182Chx
182Dgg
182Emm
182Fll
1830ss
1831Sʃ
1832tt
1833dd
1834ct͡ʃ / t͡s
1835jd͡ʒ / d͡z
1836yj
1837rr
1838ww
1839ff
183Akk
183BKk
183CCt͡s
183DJd͡z
183Exx
183FRʐ
1840Lɬ
1841Zd͡ʐ
1842Tt͡ʂ

Manchu and Sibe

Seven letters in Sibe are different from Manchu, namely i, ŋ, k, f, j, zh and r. Be careful of the codepoints used in Sibe texts.

Vowels

U+KeymapIPAManchu & Sibe
1820aɑ
185Deə
1873 / 185Eiiᡳ / ᡞ
1823oɔ
1860uu
1861Uʊ
185FIɨ

Consonants

U+KeymapIPAManchu & Sibe
1828nn
1829 / 1862Nŋᠩ / ᡢ
1874 / 1863kkᡴ / ᡣ
1864gg
1865hx
182Abb
1866pp
1830ss
1867Sʃ
1868tt
1869dd
182Fll
182Emm
1834ct͡ʃ
1835 / 186Ajd͡ʒᠵ / ᡪ
1836yj
183AKk
186CGg
186DHx
1875 / 1837rrᡵ / ᠷ
1876 / 186Bffᡶ / ᡫ
1838ww
186ECt͡s
186FJd͡z
1870Rʐ
1871Tt͡ʂ
1877 / 1872Zd͡ʐᡷ / ᡲ

Todo

Vowels

U+KeymapIPATodo
1820aɑ
1844eə
1845ii
1846oɔ
1847uʊ
1848Oo
1849Uu
1843``ː

Consonants

U+KeymapIPATodo
1828nn
184ANŋ
184Bbb
184Cpp
184Dhx
184Egg
184Fmm
182Fll
1830ss
1831Sʃ
1850tt
1851dd
1852ct͡ʃ
1834``
1853jd͡ʒ
1855yj
1837rr
1856ww
1838ff
1857Gg
1858kk
1854Ct͡s
1834Jd͡z
1859xx
185A``
185B``
185C``

Punctuations and symbols

Numbers

U+KeymapMongolian
18100
18111
18122
18133
18144
18155
18166
18177
18188
18199

Punctuations

U+KeymapMongolianManchuDescription
1801\N/AEllipsis for Mongolian.
1802,N/AComma for Mongolian.
1803.N/AFull stop for Mongolian.
1804:N/AColon for Mongolian.
1807'N/AA bare tooth. "Glottal stop" letter; "Sibe syllable boundary marker" (SSBM).
1808``N/AComma for Manchu.
1809``N/AFull 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. "Mongolian vowel separator" (MVS).
180F``Free variation selector 4.
200C^Zero-width non-joiner (ZWNJ).
200D*Zero-width joiner (ZWJ).
202F-Narrow non-breaking space (NNBSP).

Additional notes on typing traditional Mongolian script using Raven

  • Certain grammatical suffixes are preceded by a narrow non-breaking space (NNBSP), NOT a normal space, these suffixes are always written without any space in Cyrillic Mongolian.
  • The disjoint tail (which is quite common), namely ᠎ᠠ, should always be preceded by an MVS (U+180E), NOT an NNBSP or a normal space.
  • When typing the vowel ü/ү (U+1826) in foreign words (usually get a в in Cyrillic), add an extra FVS1 (U+180B) after the letter.
  • When typing the consonant t/т (U+1832) in foreign words, add an extra FVS1 after the letter, unless it sits at the beginning of the word.
  • When typing the consonant d/д (U+1833) in foreign words, add an extra FVS1 after the letter, unless it sits in the middle of the word, and also before a vowel.
  • When typing a single long tooth in a falling diphthong, use a single y, not i. E.g.: ᠨᠠᠶᠮᠠ nayma.

Additional notes on typing Manchu using Raven

Additional notes on typing Sibe using Raven

Seven letters in Sibe are different from Manchu, namely i, ŋ, k, f, j, zh and r. Be careful of the codepoints used in Sibe texts.

Tibetan

Rochelle

🔪 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.

Modules

Text emitter

API

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.

Constructor

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.

Events

chunk

MessageEvent<Uint8Array>

When a raw chunk is received from the stream.

close

Event

When the stream or the emitter closes.

error

ErrorEvent

When the emitter encounters a critical error.

fail

MessageEvent<Uint8Array>

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

raw

MessageEvent<Uint8Array>

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.

text

MessageEvent<String>

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

Properties

closed

Not implemented.

Boolean: TextEmitter.closed

If the text emitter is closed.

Methods

close()

Not implemented.

undefined: TextEmitter.close()

Close the current stream.

shx

📜 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

Usage

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

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

Instances

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

Non-CW

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 (https://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 api.ltgc.cc if without further clarification.

Endpoints

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

EventWrapper

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

Server

{
	"domain": "example.com",
	"cw": false,
	"active": true
}

Post

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": "https://equestria.social/users/thatonegib/statuses/110464545243574580",
	"url": "https://equestria.social/@thatonegib/110464545243574580",
	"tags": [{
		"name": "mlp",
		"url": "https://equestria.social/tags/mlp"
	}],
	"emojis": [{
		"code": "flutteryay",
		"url": "https://equestria.social/system/custom_emojis/images/000/000/145/original/1295608.png",
		"static": "https://equestria.social/system/custom_emojis/images/000/000/145/static/1295608.png",
		"inPicker": true
	}, {
		"code": "ajsmug",
		"url": "https://equestria.social/system/custom_emojis/images/000/000/088/original/1292830.png",
		"static": "https://equestria.social/system/custom_emojis/images/000/000/088/static/1292830.png",
		"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": "https://joinmastodon.org/"
	},
	"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=\"https://equestria.social/@AlzMarioWolfe\" class=\"u-url mention\">@<span>AlzMarioWolfe</span></a></span><br /> 💜 <br />@DamienInTheDark<br /> 04 Oct 2019<br />Comms CLOSED</p>",
		"url": "https://equestria.social/@thatonegib",
		"avatar": "https://equestria.social/system/accounts/avatars/109/524/364/471/531/266/original/8123b1c31f504128.jpg",
		"avatarStatic": "https://equestria.social/system/accounts/avatars/109/524/364/471/531/266/original/8123b1c31f504128.jpg",
		"header": "https://equestria.social/system/accounts/headers/109/524/364/471/531/266/original/e5cd38c16822e681.jpg",
		"headerStatic": "https://equestria.social/system/accounts/headers/109/524/364/471/531/266/original/e5cd38c16822e681.jpg",
		"sumPost": 58,
		"atLastPost": "2023-05-31",
		"noIndex": false,
		"emojis": [],
		"roles": [],
		"fields": [{
			"name": "Look through my Gallery!",
			"value": "<a href=\"https://www.deviantart.com/thatonegib/\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\">deviantart.com/thatonegib/</span><span class=\"invisible\"></span></a>",
			"atVerify": null
		}, {
			"name": "Help me make a living!",
			"value": "<a href=\"https://www.patreon.com/ThatOneGib\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"\">patreon.com/ThatOneGib</span><span class=\"invisible\"></span></a>",
			"atVerify": null
		}, {
			"name": "Watch the sauce get made!",
			"value": "<a href=\"https://www.youtube.com/channel/UC2V6hQau5NkH4abuBFoFhyg\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://www.</span><span class=\"ellipsis\">youtube.com/channel/UC2V6hQau5</span><span class=\"invisible\">NkH4abuBFoFhyg</span></a>",
			"atVerify": null
		}, {
			"name": "Obligatory Twatter link",
			"value": "<a href=\"https://twitter.com/ThatOneGib\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"><span class=\"invisible\">https://</span><span class=\"\">twitter.com/ThatOneGib</span><span class=\"invisible\"></span></a>",
			"atVerify": null
		}],
		"atNew": 1671148800000,
		"sumFan": 25,
		"sumSub": 5
	},
	"media": [{
		"id": "110464545127306536",
		"type": "image",
		"url": "https://equestria.social/system/media_attachments/files/110/464/545/127/306/536/original/4f8c3b035aede9ea.jpeg",
		"preview": "https://equestria.social/system/media_attachments/files/110/464/545/127/306/536/small/4f8c3b035aede9ea.jpeg",
		"remote": null,
		"previewRemote": null,
		"text": null,
		"meta": {
			"original": {
				"width": 1015,
				"height": 2042,
				"size": "1015x2042",
				"aspect": 0.4970617042115573
			},
			"small":{
				"width": 338,
				"height": 680,
				"size": "338x680",
				"aspect": 0.4970588235294118
			}
		},
		"alt": "Alt text example",
		"blurhash": "USAAX:WFMtogouocMyWBjXa$f,jZIUWBxukC"
	}],
	"ats": [{
		"id": "110377043343501824",
		"username": "silk",
		"url": "https://equestria.social/@silk",
		"acct": "silk"
	}],
	"handle": "@[email protected]",
	"rid": "[email protected]"
}

Service Usage

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

API

Please refer to API.

Web frontend

The web frontend is expected to become publicly available at mlp.ltgc.cc.

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

Snowy

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

Snowy will not be active if BroadcastChannel already exists.

Usage

  • 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.

SynPix

👾 The open pixel font for embedded LCDs.

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

Support

Unicode Blocks

  • ASCII
  • Latin-9
  • Some additional Latin alphabets, see below for details
  • IPA (U+0250 - U+029F)
  • 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
  • Hebrew (basic letters only, no full Yiddish support yet)
  • Georgian (upcoming in version 0.4)
  • Cherokee (upcoming in version 0.4)
  • Runes
  • Tai Le
  • New Tai Lüe (upcoming)
  • Roman numerals (U+2160 - U+2165)
  • Bagua symbols
  • Astronomical symbols
  • Zodiac symbols
  • Coptic
  • CJK radicals supplement (partial complete)
  • Kangxi radicals (except 9 characters “⼢⼮⿋⿎⿏⿐⿒⿔⿕”)
  • CJK symbols and punctuation (、。々〇「」)
  • “Hangzhou” numerals
  • Hiragana (missing 2 characters “ぱぽ”)
  • Katakana (missing 1 character “パ”)
  • Bopomofo
  • Hangul compatibility jamo (done for modern jamos)
  • CJKV Ideographs (see below for details)
  • Lisu (Fraser alphabet)
  • Phags-pa (upcoming in version 0.4)
  • Full-width ASCII
  • Half-width katakana
  • Half-width Hangul
  • Various currency symbols (partial complete, ¢£¥€¢£¥)
  • Gothic (upcoming?)

EU Official Languages

  • Bulgarian (done in basic Cyrillics)
  • Croatian (no tone marks yet)
  • Czech
  • 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 in version 0.4)
  • Irish (done in Latin-9 for modern orthography, old orthography upcoming in version 0.4)
  • Italian (done in Latin-9)
  • Latvian
  • Lithuanian
  • Maltese (upcoming in version 0.4)
  • Polish
  • Portuguese (done in Latin-9)
  • Romanian (upcoming in version 0.4)
  • Slovak
  • Slovene (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) (no tone marks yet)
  • Esperanto

Romanization Systems

  • Hànyǔ Pīnyīn

Cyrillic Alphabets

  • Russian
  • Ukrainian (Ґґ Єє Іі Її)
  • Pre-1918 Russian (four extra letters: Іі Ѣѣ Ѳѳ Ѵѵ)
  • Belarusian (Іі, Ўў)
  • Bulgarian
  • Dungan (Cyrillic) (Җҗ Ңң Әә Ўў Үү, upcoming in version 0.4)
  • Macedonian (Ѓѓ Ѐѐ Ѕѕ Ѝѝ Јј Љљ Њњ Ќќ Џџ)
  • Mongolian (Cyrillic) (Өө Үү)
  • Kazakh (Cyrillic) (Әә Ғғ Ққ Ңң Өө Ұұ Үү Һһ Іі)
  • Kyrgyz (Ңң Өө Үү)
  • Serbo – Croatian (Cyrillic) (Ђђ Јј Љљ Њњ Ћћ Џџ, no tone marks yet)
  • Tajik (Ғғ Ӣӣ Ққ Ӯӯ Ҳҳ Ҷҷ)
  • Tatar (Cyrillic) (Әә Җҗ Ңң Өө Үү Һһ, upcoming in version 0.4)
  • Tuvan (Ңң Өө Үү)
  • Uzbek (Cyrillic) (Ўў Ққ Ғғ Ҳҳ)

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.

Usage

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.

Caddy

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

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.

API

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.

System

WingBlade.rt.cores

Use

Report the amount of CPU cores.

Syntax

Number: WingBlade.rt.cores

WingBlade.rt.exit

Use

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

Syntax

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

WingBlade.rt.memory

Use

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

Syntax

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.
}

WingBlade.rt.networkDefer

Use

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

Useful for serverless functions.

Syntax

Boolean: WingBlade.rt.networkDefer

WingBlade.rt.os

Use

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

Syntax

String: WingBlade.rt.os

WingBlade.rt.persist

Use

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.

Syntax

Boolean: WingBlade.rt.persist

WingBlade.rt.variant

Use

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

Syntax

String: WingBlade.rt.variant

WingBlade.rt.version

Use

Report the version of the current runtime WingBlade runs on.

Syntax

String: WingBlade.rt.version

Environment variables

Note

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

WingBlade.env.get

Use

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

Syntax

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

WingBlade.env.set

Use

Set an environment variable with given value.

Syntax

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

WingBlade.env.delete

Use

Remove an environment variable.

Syntax

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

WingBlade.env.has

Use

Indicate whether or not an environment variable exists.

Syntax

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

WingBlade.env.toObject

Use

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

Syntax

Object: WingBlade.env.toObject();

Filesystem

WingBlade.file.read()

Use

Read the whole file as Uint8Array.

Syntax

Promise<Uint8Array>: WingBlade.file.read(String: path, Object<ReadFileOptions>: opt);

Read Deno.ReadFileOptions for the opt params.

WingBlade.file.write()

Use

Write the whole Uint8Array as a file.

Syntax

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

Read Deno.WriteFileOptions for the opt params.

Utilities

WingBlade.util.randomInt

Use

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

Syntax

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

WingBlade.util.sleep

Use

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

Syntax

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

Networking

Web services

WingBlade.web.serve

Use

Start a web server with a handler function.

Syntax

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

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

handler

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

WingBlade.web.acceptWs

Use

Upgrade the incoming request to a WebSocket connection.

Syntax

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

UpgradedWebSocket

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

UpgradeWebSocketOptions

{
	protocol: String,
	idleTimeout: Number
}

Read Deno.UpgradeWebSocketOptions for details.

WingBlade.web.acceptSSE

Use

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

Syntax

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

UpgradedSSE

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

Web Stream

Quick ReadableStream convertion

Warning

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.

ReadableStream.prototype.array()

ReadableStream.prototype.arrayBuffer()

ReadableStream.prototype.blob()

ReadableStream.prototype.json()

ReadableStream.prototype.text()

Stream behaviour modification

ChokerStream

Use

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.

Syntax

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.
}