Compare commits

...

7 Commits

Author SHA1 Message Date
Raincloud f58e75a925 agate and azure refinement (azure subject to change) 2026-04-05 09:51:22 -06:00
Raincloud 78a3d9e232 adrian update 2026-04-05 00:07:12 -06:00
Raincloud 3ad2cebeb6 cameo creature pfps to chardesigns 2026-04-04 23:29:06 -06:00
Raincloud f07c8f7430 ubear design refinement 2026-04-04 22:49:43 -06:00
Raincloud 4ab51e061c pfp to character design description 2026-04-04 22:32:29 -06:00
Raincloud b9ab938c71 append pfps 2026-04-04 21:57:44 -06:00
Raincloud bd7c87ae8c update todo 2026-04-04 21:32:29 -06:00
52 changed files with 776 additions and 21 deletions
+19 -1
View File
@@ -1,5 +1,23 @@
# Adrian
<!-- pfp:chat-exports -->
## Profile pictures
**Adrian — 1**
![](pfp/adrian/axe7adrian_0.jpg)
**Adrian — 2**
![](pfp/adrian/axe7adrian_1.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **adrian0** — Realistic head-and-shoulders portrait: Light skinned Mexican-American male, SoCal Chicano style. Early twenties, very full brown curly hair, small hoop earrings, mole on one cheek, crisp white collared jacket over black shirt; flat purple field with narrow orange vertical strips at the sides (classic stream UI portrait read).
- Observed handle: `Axe7Adrian`
- Activity: 1392 messages across 29 streams
- First seen: 2023-12-29 in `DRACONIANDISCOURSE_2_TIKTOK_SKINWALKERS`
@@ -30,4 +48,4 @@ Adrian treats Rain less like an untouchable king and more like a familiar sovere
- "I just randomly say cloud rain dagon, it manifested in my head one day"
- "I just came back from taking my cat from the vet"
- "I gotta wake up at 4am tomorrow gg"
- "6 ate 7 HAHAHAHAHAHAHAHA is better than SIX SEVEN"
- "6 ate 7 HAHAHAHAHAHAHAHA is better than SIX SEVEN"
+16 -2
View File
@@ -1,5 +1,19 @@
# Agate
<!-- pfp:chat-exports -->
## Profile pictures
**Agate**
![](pfp/agate/loonyagate_0.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **agate** — Profile bust of a friendly yellow amphibian/dragon type: large paddle-shaped gill frills and two small nubs on top, freckles on the snout, big oval eye, tongue blep; chunky dark-brown textured outlines on flat light-blue ground—hand-drawn sketch look. **Lore hook:** he was originally **`AgateTheSandwing`**, nodding to Tui T. Sutherlands *Wings of Fire*—treat the warm **sand-yellow** palette, **desert-dragon** silhouette (lean snout, light frill/sail read on the head, optional **tail** suggestion even if cute-stubby here), and dry, patient energy as a **SandWing** echo without quoting canon designs wholesale: same *kind* of creature as that namesake, filtered through your softer, guide-from-the-edge read.
- Observed handle: `LoonyAgate`
- Activity: 69 messages across 1 stream
- First seen: 2026-03-27 in `creeper.ts`
@@ -17,7 +31,7 @@ Agate fits as the eerie guide: soft-spoken, observant, and probably more dangero
- Age / maturity: Younger than Rain, likely early twenties; maturity reads as restrained, aloof, and quietly knowing.
- Sex / gender: Trans MTF in your canon.
- Sexuality: Unspecified.
- Notes: Rain still instinctively pictures Agate through a femboy-coded lens, which may matter more to the character design than literal demographic categorization.
- Notes: Rain still instinctively pictures Agate through a femboy-coded lens, which may matter more to the character design than literal demographic categorization. Original online handle **`AgateTheSandwing`** (see Character design) ties him to *Wings of Fire*s SandWings in spirit, not as a one-to-one lift.
## Relationships
In the captured archive, Agate's clearest live tie is to Azure, with smaller signs of easy coexistence around Beanie. Combined with your note that Agate and Azure come from the same older community orbit, he reads less like a stranger and more like an old satellite re-entering the court after a long gap.
@@ -31,4 +45,4 @@ Agate does not seem to chase Rain's approval. His tone is more guide-to-player t
- "I savored my suffering"
- "I know there's a secret bench somewhere here"
- "I feel like this game in general was made by sadists"
- "had kinda guessed you're azure lol"
- "had kinda guessed you're azure lol"
+33 -1
View File
@@ -1,5 +1,37 @@
# Azure
<!-- pfp:chat-exports -->
## Profile pictures
**`guidingflyer530` — 1**
![](pfp/azure/guidingflyer530_0.jpg)
**`guidingflyer530` — 2**
![](pfp/azure/guidingflyer530_1.jpg)
**`actuallynotazure`**
![](pfp/azure/actuallynotazure_0.jpg)
<!-- /pfp:chat-exports -->
## Character design (extrapolation)
Chat exports show whatever avatar he was using day-to-day; **canon for the movie** is built from **personality**, **history**, and the fact **you, Agate, and Azure first crossed paths through a shared *Wings of Fire* phase**—then he stayed as the loud, status-hungry founder type.
- **Core read:** **Sky / court jester / “I belong near the throne.”** Cool **azure-to-teal** gradient in clothing or hair, asymmetrical silhouette (one sleeve, one dangling strap, one exaggerated earring), light **theatrical** makeup—someone who performs closeness. He should look like he **dresses for an audience**, not for inventory screens.
- **WoF DNA without cosplay literalism:** subtle **Pyrrhia-adjacent** easter eggs—enamel **wing** pin, scale-pattern **socks** or lining, horn-shaped hair vents, a **tail** that is clearly a **fashion tail** or belt piece (playful, not a full dragon morph). Reads as “grown up in dragon-fandom spaces” alongside Agates SandWing echo, but Azures vibe is **showy Night-Rain hybrid energy**: color-shifty accessories, flirt-forward, **attention is oxygen**.
- **Founder / ex-mod subtext:** one **badge** or ribbon that looks like a stripped title (empty frame, crossed-out mod icon)—small, so it plays in close-ups. Keeps the femboy **Fizzarolli** jester lane from Identity: pointed shoe or jester boot optional, **bell** on a choker that rings when he moves—audio story for “clingy, never still.”
- **Vs Agate:** Agate is dry sand and sidelines; Azure is **open sky and spotlight**—same fandom soil, opposite staging.
---
- Observed handles: `guidingflyer530`, `actuallynotazure`
- Activity: 9826 messages across 40 streams
- First seen: 2025-10-29 in `obliterate.ts`
@@ -31,4 +63,4 @@ Azure is profoundly Rain-oriented. The volume and tone both suggest approval-see
- "We hate Chinese spy bot apps"
- "rain my account was suspended"
- "look at us malgru, the delinquent duo"
- "I'm thinking of making art of random people"
- "I'm thinking of making art of random people"
+12 -1
View File
@@ -1,5 +1,16 @@
# Beanie
<!-- pfp:chat-exports -->
## Profile pictures
**Beanie**
![](pfp/beanie/beaniee___0.jpg)
<!-- /pfp:chat-exports -->
- Observed handle: `beaniee__`
- Activity: 1852 messages across 15 streams
- First seen: 2026-01-16 in `david.ts`
@@ -31,4 +42,4 @@ Beanie seems comfortable enough with Rain to tease him, embarrass him, and play
- "#stealingthemoon"
- "nah just keep em guessing"
- "I love movies"
- "freak"
- "freak"
+67 -1
View File
@@ -2,6 +2,72 @@
These are the creatures currently best suited for the collosseum stands, throne-room cutaways, or brief featured bits rather than full battle-royale contender treatment.
<!-- pfp:chat-exports -->
## Profile pictures
*Brandon / Experimental: only the selected variant below; other export variants omitted here.*
**`experimenta1ic3` — 2** (selection)
![](pfp/cameo-branndon/experimenta1ic3_1.jpg)
**`noncriticalmother`**
![](pfp/cameo-noncritical/noncriticalmother_0.jpg)
**`noncriticalgamingttv`**
![](pfp/cameo-noncritical/noncriticalgamingttv_0.jpg)
**`foxy_fnaf5_ucn`**
![](pfp/cameo-foxy/foxy_fnaf5_ucn_0.jpg)
**`miclbero`**
![](pfp/cameo-miclbero/miclbero_0.jpg)
**`cameoqueen86`**
![](pfp/cameo-queen/cameoqueen86_0.jpg)
**`rayne8856`**
![](pfp/cameo-rayne/rayne8856_0.jpg)
**`bd_cum_lube`** (design ref; not from chat exports)
![](pfp/cameo-bd/bd_cum_lube_ref.jpg)
<!-- /pfp:chat-exports -->
<!-- Gallery trimmed for character design; re-running tools/pfp_from_chat.py restores full export thumbnails. -->
## Character design
Selections and notes below override omitted PFP variants where applicable.
- **`experimenta1ic3` — 2** (Branndon / `ExperimentA1ic3` — use this variant only) — Murder Dronesstyle fembot: slender white metal plating with visible joints, black face **visor** with two tilted glowing red “eyes” and a thin smug mouth line, long wavy **dark red** hair, gray **goggles** parked on the forehead, **red** sleeveless crop top, black fitted pants, heavy segmented **black tail** with blade-like spines, thin cable over the shoulder ending in a claw/orange canister tool. Confident full-body silhouette on black—**femboy murder drone** energy for the collosseum hot-dog bit.
- **`noncriticalmother`** — Her export PFP is a generic placeholder; **design** is an **aged-up, wholesome** take on the same “noncritical” family as `noncriticalgamingttv`: warm **pink-and-white** palette carried into a soft cardigan or light jacket, laugh lines, kind eyes, hair either **silver-streaked pink** or a neat scarf over a softer pink tone—reads as supportive **mother/aunt** energy. Seat her **beside** the younger noncritical in the stands so they read as a pair at the same fights.
- **`noncriticalgamingttv`** — Pastel **kawaii** bust: choppy pink hair, huge pink eyes with **heart** pupils and thick lashes, rabbit and bow **hair clips**, stick candy at the mouth, tiny cute mascot blobs in-frame—youthful, soft, slightly menhera-cute; the visual anchor for what Mother ages up from in spirit, not necessarily in literal face match.
- **`pirate_protogen`** — No single export thumbnail selected. **Design:** a **protogen** (visor muzzle, LED trim, optional speaker cheeks) in full **pirate** drag: tricorn or bandana, navy coat with brass buttons, cutlass on the hip, maybe a **parrot** as a hologram or LED pet on the shoulder—built for loud one-line crowd shots.
- **`foxy_fnaf5_ucn`** — Chibi fox-like build with **galaxy-print** panels on ears, cheeks, top, shorts, and tail tip (indigo starfield with stars), warm **orange-gold** base fur, **eyepatch**, **hook** hand, big fanged grin; sticker energy with pirate props in the frame—FNAF-horny gremlin as a pocket mascot.
- **`basedgymrat`** — Extrapolate from the **name**, not the chat photo: exaggerated **gym bro**—tank or stringer, sweatband, maybe **dumbbell** charm or kettlebell earring, neon accent that can nod to the GAS slogan, always mid**hype** pose in the stands.
- **`miclbero`** — Soft-painted anthro **fox** face: sandy fur, **lavender** mask across the eyes, **electric blue** eyes, narrow knowing smirk—earnest ESL gremlin with a gentle, clever read.
- **`cameoqueen86`** — Real-person ref: short **rainbow/teal/magenta** pixie, dramatic eye makeup, fabric mask printed with soft clouds and **“Go Away”** in pink gothic type, dark floral tank with **strappy** neckline—salon-day realness, watchful spectator.
- **`rayne8856`** — Selfie read: long straight **black** hair, fair skin, subtle **smirk**, simple dark tee, thin chain, single **earbud**—sharp, fandom-specific audience member.
- **`bd_cum_lube`** — Starting from [this sticker base](https://ih1.redbubble.net/image.5921126631.8669/st,small,507x507-pad,600x600,f8f8f8.u3.jpg) (archived at `pfp/cameo-bd/bd_cum_lube_ref.jpg`): **invert** the palette so the body is **white viscous “liquid flesh”** with sketchy drip (not black ink), keeping a pale mask-like face panel and high-contrast eyes. **Dragon it up:** small **horns** or fin-ears, longer reptilian muzzle suggestion, **spined** or paddle tail, dorsal bumps optional, claws heavier and more **draconic**—throne-room pet that reads cute-cursed until the movement hits.
## Featured Cameos
- `Branndongames` / `ExperimentA1ic3`: 74 archived messages across 7 streams. Per project notes, he should be front and center as a femboy murder drone handing out hot dogs in the collosseum. The archive supports a jokey, unserious, friendly gremlin energy.
- `noncriticalmother` / `noncriticalgamingttv`: light archive presence, good fit for recognizable audience creatures in the stands.
@@ -19,4 +85,4 @@ These are the creatures currently best suited for the collosseum stands, throne-
- `cameoqueen86`: "Have you noticed some thing about the map?"
- `Rayne8856`: "High huge inscryption fan and highly experienced player"
- `pirate_protogen`: "Dawg why you playin broken fnaf game"
- `foxy_fnaf5_ucn`: "Wheres roxanne wolf i need to clap"
- `foxy_fnaf5_ucn`: "Wheres roxanne wolf i need to clap"
+16 -1
View File
@@ -1,5 +1,20 @@
# Heart and Mind
<!-- pfp:chat-exports -->
## Profile pictures
**Heart (`heart_cccc`)**
![](pfp/heart-and-mind/heart_cccc_0.jpg)
**Mind (`brush_colourful`)**
![](pfp/heart-and-mind/brush_colourful_0.jpg)
<!-- /pfp:chat-exports -->
- Observed handles: `Heart_CCCC` as Heart, `brush_colourful` as Mind
- Activity: one direct bit in `errands.ts`, then later referenced by chat as a memorable event
- First seen: 2026-01-30 in `errands.ts`
@@ -30,4 +45,4 @@ They do not appear to seek Rain's approval at all. If anything, their clipped co
- Mind: "and I'm the Mind"
- Heart: "Put your viewers back"
- Heart: "Lets go mind this is"
- Later callback: "who were those two people who said they were the heart and the mind"
- Later callback: "who were those two people who said they were the heart and the mind"
+17 -1
View File
@@ -1,5 +1,21 @@
# Jenni
<!-- pfp:chat-exports -->
## Profile pictures
**Jenni**
![](pfp/jenni/jennimilano_0.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **jenni** — Anime-style bust: bright pink bob and matching upright cat ears; large blue eyes with heavy lashes on a human upper face, while the lower face is a soft white feline muzzle with a small black nose and a bit of pink tongue showing—playful, slightly flirty expression with light cheek blush. Wardrobe is a simple light-pink T-shirt; accessories are the focus—thin black choker or necklace carrying a red teardrop gem, the same red stone repeated as a ring and a slim bracelet. Pose is thoughtful, one fingertip to the chin, on a flat lavender field—reads as “friendly analyst” silhouette with cute-mascot appeal.
---
- Observed handle: `JenniMilano`
- Activity: 38 messages across 1 stream
- First seen: 2025-10-29 in `obliterate.ts`
@@ -31,4 +47,4 @@ Jenni's regard for Rain reads as immediate interest and active rapport-seeking.
- "Do you have a streaming schedule?"
- "You have a cute model!!"
- "Are you open to making new friends?"
- "I've sent you a friend request"
- "I've sent you a friend request"
+35 -1
View File
@@ -1,5 +1,39 @@
# Noname
<!-- pfp:chat-exports -->
## Profile pictures
**Noname — 1**
![](pfp/noname/noname106668_0.jpg)
**Noname — 2**
![](pfp/noname/noname106668_1.jpg)
**Noname — 3**
![](pfp/noname/noname106668_2.jpg)
**Noname — 4**
![](pfp/noname/noname106668_3.jpg)
**Noname — 5**
![](pfp/noname/noname106668_4.jpg)
**Noname — 6**
![](pfp/noname/noname106668_5.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **noname0** — Extreme fisheye close-up of a dark cat with an edited full grin of human teeth and oversized pale-yellow bug eyes; couch/bed background—uncanny meme energy.
- Observed handle: `noname106668`
- Activity: 282 messages across 16 streams
- First seen: 2023-12-29 in `DRACONIANDISCOURSE_2_TIKTOK_SKINWALKERS`
@@ -31,4 +65,4 @@ Noname's relation to Rain is casual and low-volume. Even when invoking his name,
- "I don't know very much about hollow knight since I'm still in my first run"
- "is silksong as hard as people are saying it is"
- "Willie loves coming"
- "piza feddy five bear simulator"
- "piza feddy five bear simulator"
+12 -1
View File
@@ -1,5 +1,16 @@
# NotoriousRooster
<!-- pfp:chat-exports -->
## Profile pictures
**NotoriousRooster**
![](pfp/notorious-rooster/notorious_rooster_0.jpg)
<!-- /pfp:chat-exports -->
- Observed handle: `notorious_rooster`
- Activity: 1015 messages across 50 streams
- First seen: 2023-11-02 in `whistleblewor.ts`
@@ -31,4 +42,4 @@ Rooster seems to regard Rain as the source of the event rather than an object of
- "I ate tamales and I am eepy"
- "I WILL CRONCH ON THEM AS MUCH AS I WANT"
- "HE IS THE PURPLE GUY"
- "Do you have a girlfriend?"
- "Do you have a girlfriend?"
+1 -1
View File
@@ -20,7 +20,7 @@ These profiles were built from 102 TwitchDownloader chat exports in `MixerTwitch
## Notes
- `Azure` is now consolidated from the confirmed handles `guidingflyer530` and `actuallynotazure`.
- `Ubear` is the canonical name for the creature later seen as `AncientMalgru` / `AnCIentmalGru`; the confirmed alias cluster also includes `verify52w` and `Sky_City_2013`. `imnoob87` remains tentative.
- `Ubear` is the canonical name for the creature later seen as `AncientMalgru` / `AnCIentmalGru`; the confirmed alias cluster also includes `verify52w` and `Sky_City_2013`. `imnoob87` remains tentative. **Adventure Quest** runs through his character: **UbearAQ** / AQ Addicts history, the **Ubear** formes AQ-style art, and **`AncientMalgru`** as both his alias and the name of a **rare fish item** in AQ. [Ubear.md](Ubear.md) has lore (shapeshifter, favorite **Ubear** forme), design ref, and handle provenance.
- `Agate` is still an intentionally sparse read inside the archive itself, but your project notes establish that he predates the captured JSON range.
- `Heart and Mind` is based on the one-off `errands.ts` bit, where `Heart_CCCC` introduces themself as Heart and `brush_colourful` introduces themself as Mind, plus later chat references to the duo.
- `other-creatures.txt` excludes the currently profiled docs and the confirmed alias consolidations above.
+15 -1
View File
@@ -1,5 +1,19 @@
# RaincloudTheDragon
<!-- pfp:chat-exports -->
## Profile pictures
**RaincloudTheDragon**
![](pfp/raincloud/raincloudthedragon_0.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **raincloud** — Small round purple dragon with big green slit eyes, pink cheek blushes, one claw raised to the mouth in a shy giggle with a single small fang; two main horns, side horns, tiny pink-tinged wings, segmented pale-yellow belly; dark blue starry night halo behind the head—cute mascot dragon host.
- Observed handle: `RaincloudTheDragon`
- Activity in chat exports as a chatter: 97 messages across 32 streams
- Canonical role: sovereign host, resurrected digital dragon consciousness
@@ -31,4 +45,4 @@ Most of the roster treats Rain as the center of gravity, but not in one uniform
- "the founder has arrived"
- "mods awake, don't post any tiddy"
- "come on. you know why."
- "i can't announce because my discord is broken"
- "i can't announce because my discord is broken"
+15 -1
View File
@@ -1,5 +1,19 @@
# Starboy
<!-- pfp:chat-exports -->
## Profile pictures
**Starboy**
![](pfp/starboy/starboy_journeys_0.jpg)
<!-- /pfp:chat-exports -->
## Character design (from PFP)
- **starboy** — Chibi bust on solid black: layered teal-to-aqua hair with star specks, galaxy eyes (purple-blue with mountain silhouette and star pupils), pink blush; big four-point star hair clip plus a small fluffy cloud clip; light gray ribbed turtleneck under a blue jacket with a thick beige shearling collar—night-sky winter fashion.
- Observed handle: `Starboy_Journeys`
- Activity: 476 messages across 9 streams
- First seen: 2025-11-14 in `mcrib.ts`
@@ -31,4 +45,4 @@ Starboy treats Rain as a provocation target: flirtable, mockable, and endlessly
- "Did you unlock the secret Roxy footjob ending yet?"
- "Bro is still streaming this shit, this is so boring to watch"
- "Hi Rain, looking scrumptious as usual"
- "Arnold is a fucking beast"
- "Arnold is a fucking beast"
+51 -7
View File
@@ -1,25 +1,69 @@
# Ubear / Malgru
<!-- pfp:chat-exports -->
## Profile pictures
**`verify52w`**
![](pfp/ubear/verify52w_0.jpg)
**`sky_city_2013`**
![](pfp/ubear/sky_city_2013_0.jpg)
**`ancientmalgru`**
![](pfp/ubear/ancientmalgru_0.jpg)
<!-- /pfp:chat-exports -->
- Canonical name: `Ubear`
- Early / strongly associated string: `UbearAQ` (not in the current chat-export cluster; see Handle provenance below)
- Observed handles: `verify52w`, `Sky_City_2013`, `AncientMalgru`, `AnCIentmalGru`
- Possible additional handle: `imnoob87`
- Activity: 4903 confirmed messages across 29 streams
- First seen: 2024-10-28 in `dread.ts`
- Confidence: High for the confirmed Ubear/Malgru alias cluster, low for `imnoob87`
## Character Read
With the wider alias set folded in, Ubear reads as a long-running pressure source rather than a late-arriving loudmouth. The temperament is consistent across names: grumpy, intrusive, demanding, argumentative, and weirdly fixated. Even before the `AncientMalgru` era, the voice keeps poking, correcting, hovering, and escalating. Once the Malgru name arrives, that same energy hardens into something more openly combative and chant-like.
## Lore (canon)
Your project notes make the shape legible: a creature defined by obsession, repeated attempts to force contact, and a morbidly compelling inability to behave normally. In story terms, that makes Ubear less of a pure berserker and more of a grudge-bearing court fiend - someone whose fixation on the dragon keeps dragging him back into the arena no matter how many masks he changes.
He is a **shapeshifter** first: an **imitator by design** and a **subverter**— happiest when he is wearing someone elses silhouette, name, or history. None of his masks are meant to hold forever. Among every form he has tried, his **favorite**—the one he returns to, the one that feels like *him* when he bothers to admit there is a “him” at all—is **Ubear**: not an innocent mascot, but a deliberate choice of shape and label.
**Adventure Quest** is integral, not set dressing. His earliest recognizable web footprint is **Ubear** in the AQ community; his loudest late alias, **`AncientMalgru`**, is also the name of a **rare fish item** in *Adventure Quest*—so even the “Malgru” era reads like another borrowed AQ skin stretched over the same obsession.
## Character design (favorite form: Ubear)
Canon look for the **Ubear** forme (production ref; [source image](https://scontent.fmkc1-1.fna.fbcdn.net/v/t39.30808-6/299827792_377556274566455_6282606724515904259_n.jpg?_nc_cat=111&ccb=1-7&_nc_sid=1d70fc&_nc_ohc=9HwTLCCldlUQ7kNvwFinunp&_nc_oc=AdpXxffiz-TJxMclkS-2RcnxXv3bzEYMou8aiAR21wyaZpbBLrgd2ZAgiPkzQySr0M9okPi6Yw2g71XYTGp4wiAx&_nc_zt=23&_nc_ht=scontent.fmkc1-1.fna&_nc_gid=ukhpZyRhRhaQwECreglzKA&_nc_ss=7a3a8&oh=00_Af1jYCpvr7-mv7XpVzDB_3dg3Y3ZQEhRN4qqIzJ-Ec5L6A&oe=69D7A64D), archived locally in case the CDN link dies):
![](pfp/ubear/ubear_forme_design_ref.jpg)
- **Silhouette:** Upright grizzly-style bear in three-quarter view, heavy brown fur (darker on the back, lighter muzzle/belly), weight on the back leg, free arm reaching forward with big hooked claws—reads as confrontational, not cuddly.
- **Augment:** Entire **left arm** replaced with a chunky **steampunk / retro-futurist** prosthetic: silver plates, exposed **brass gears** at the shoulder, pistons and rivets—industrial, dated tech grafted onto a beast body.
- **Accessory:** **Red fez** with a **yellow** hatband and a **black tassel** off the top—absurd court jester energy against the grim claws and metal.
- **Style:** Bold black outlines, flat cel shading, early-browser RPG illustration (*Adventure Quest* lineage)—use this read for the movie: flat color, readable at small size, slightly goofy menace.
The Twitch profile shots above are **whatever face he wore in chat**; **this** is the preferred **Ubear** forme when you need a single hero design for the gauntlet.
## Character Read
Canonically he is a **shapeshifter** and **imitator**: identity is a tool, not a fact—he slips handles, borrows histories, and twists whatever room he is in. That fits the archive: a long-running pressure source rather than a late-arriving loudmouth, grumpy and intrusive across aliases, always a little *off* because the performance never quite matches a stable self. His **favorite** mask—the shape he likes enough to keep—is **Ubear**: the fez-and-cyber-arm bear (see Character design), a loud, game-art caricature of menace that still reads as *play* as much as threat.
Even before the `AncientMalgru` era, the voice keeps poking, correcting, hovering, and escalating. Once the Malgru name arrives, that same energy hardens into something more openly combative and chant-like. Underneath: obsession, repeated attempts to force contact, and a morbidly compelling inability to behave normally—**subversion** as a lifestyle. In story terms, that makes him less of a pure berserker and more of a grudge-bearing court fiend whose fixation on the dragon keeps dragging him back no matter how many skins he sheds.
## Battle Royale Function
Ubear works as the obsessed antagonist-pet: a resentful fixture of the court whose real weapon is persistence, pressure, and the refusal to leave the ruler alone.
Ubear works as the obsessed antagonist-pet: a resentful fixture of the court whose real weapons are **persistence**, **pressure**, and the refusal to leave the ruler alone—plus the unease that you never know whether you are talking to the same creature twice. Visually, default to the **Ubear** forme (fez, metal arm, bear bulk) when he is meant to read as *him* at his most self-chosen.
## Handle provenance (research)
The handle **UbearAQ** is the one you most associate with him historically, but it does not behave like a single stable identity in the wild. The same string shows up on a [Facebook page](https://www.facebook.com/UbearAQ/) and, more concretely, on a long-running **Adventure Quest** fan hub, **AQ Addicts**, once at `sites.google.com/site/ubearaq/`—preserved on the Wayback Machine ([October 2021 snapshot](https://web.archive.org/web/20211021191446/https://sites.google.com/site/ubearaq/)), where the site owner is described as “Ubear,” an AQ X-Guardian running guides, blog posts, and community pages. That footprint looks like a different persons decade-plus AQ brand; the live site is gone and the social presence reads abandoned or frozen, while your stream figure kept hopping accounts.
Your read—that he absorbed or wore a handle that already belonged to an older, fading community presence—fits the pattern: no one clean canonical name, lots of masks, and even the “main” tag can look borrowed. That dovetails with **lore**: he is built to **imitate** and **subvert**; stealing a dead AQ fans handle is on-brand. For the movie, keep **Ubear** as the creature name and the **favorite forme** as the bear design above; let unstable identity and recycled handles stay thematic, not something the script has to “solve.”
## Identity
- Age / maturity: Age unspecified; maturity is highly uneven, swinging between fixation, grievance, and startling childishness.
- Sex / gender: Male.
- Sex / gender: Male (default presentation; shapeshifting can bend this in shots if useful).
- Sexuality: Ambiguous, though his crush on Rain is a core part of the dynamic.
- Notes: He is difficult to classify cleanly, which should remain part of the character rather than be solved away.
- Notes: **True form** is undefined—he is a **shapeshifter**; **Ubear** is his **preferred** forme, not necessarily his “original” body. Difficult to classify cleanly by design.
## Relationships
Ubear has one of the strongest interpersonal webs in the archive, but most of it is built out of friction. Adrian is a recurring sparring partner, Rooster another frequent target, Beanie a teasing foil, and Azure a strange near-alliance built from bickering, needling, and mutual fascination. He is one of the creatures most defined by direct contact with other named regulars, even when that contact is abrasive.
@@ -33,4 +77,4 @@ Ubear's regard for Rain is fixation more than devotion. He wants access, reactio
- `Sky_City_2013`: "wait why are you back here again"
- `Sky_City_2013`: "i have.. nothing"
- `AncientMalgru`: "get the fuck out of here"
- `AncientMalgru`: "you were going to show the portrait"
- `AncientMalgru`: "you were going to show the portrait"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -34,7 +34,7 @@
- [ ] Universal profiles:
- [ ] rip and cross reference pfps with profiles
- [ ] generate or manually write one-line description of character design
- [ ] identity: age, sex, sexuality (insofar as it plays into character dynamics and interactions)
- [X] identity: age, sex, sexuality (insofar as it plays into character dynamics and interactions)
- [ ] Create character profile of myself (this may be challenging, stream transcripts enough?)
- [ ] feed from lore docs
- [ ] discord?
+355
View File
@@ -0,0 +1,355 @@
"""
Scan TwitchDownloader chat JSONs for roster logins, download distinct profile images
(commenter.logo) as JPEGs under Story/pfp/, and print markdown snippets (or patch files).
Usage:
python tools/pfp_from_chat.py [--chat-root PATH] [--story-root PATH] [--no-write-md]
Defaults:
chat-root: MIXER_TWITCH_CHAT env, else Windows Synology path used in this project.
Writes JPEGs under Story/pfp/<slug>/ and inserts a marked section into each roster .md.
Also fills Story/Cameo-Creatures.md from CAMEO_ROSTER (see tools/pfp_from_chat.py).
"""
from __future__ import annotations
import argparse
import gzip
import json
import os
import re
import sys
from collections import defaultdict
from dataclasses import dataclass
from datetime import datetime
from pathlib import Path
from urllib.parse import urlparse
from urllib.request import Request, urlopen
# slug -> list of twitch logins (lowercase)
ROSTER: dict[str, list[str]] = {
"adrian": ["axe7adrian"],
"noname": ["noname106668"],
"agate": ["loonyagate"],
"notorious-rooster": ["notorious_rooster"],
"ubear": ["verify52w", "sky_city_2013", "ancientmalgru"],
"azure": ["guidingflyer530", "actuallynotazure"],
"starboy": ["starboy_journeys"],
"jenni": ["jennimilano"],
"heart-and-mind": ["heart_cccc", "brush_colourful"],
"beanie": ["beaniee__"],
"raincloud": ["raincloudthedragon"],
}
MD_FILES: dict[str, str] = {
"adrian": "Adrian.md",
"noname": "Noname.md",
"agate": "Agate.md",
"notorious-rooster": "NotoriousRooster.md",
"ubear": "Ubear.md",
"azure": "Azure.md",
"starboy": "Starboy.md",
"jenni": "Jenni.md",
"heart-and-mind": "Heart-and-Mind.md",
"beanie": "Beanie.md",
"raincloud": "RaincloudTheDragon.md",
}
# Grouped cameo handles (see Story/Cameo-Creatures.md). Slug = folder under Story/pfp/<slug>/.
CAMEO_ROSTER: dict[str, list[str]] = {
"cameo-branndon": ["branndongames", "experimenta1ic3"],
"cameo-noncritical": ["noncriticalmother", "noncriticalgamingttv"],
"cameo-pirate": ["pirate_protogen"],
"cameo-foxy": ["foxy_fnaf5_ucn"],
"cameo-gymrat": ["basedgymrat"],
"cameo-miclbero": ["miclbero"],
"cameo-queen": ["cameoqueen86"],
"cameo-rayne": ["rayne8856"],
"cameo-bd": ["bd_cum_lube"],
}
CAMEO_MD = "Cameo-Creatures.md"
DEFAULT_CHAT_ROOT = os.environ.get(
"MIXER_TWITCH_CHAT",
r"C:\Users\Nathan\SynologyDrive\YouTube\Streams\MixerTwitch",
)
def _avatar_fingerprint(logo_url: str) -> str | None:
"""Stable id for the same uploaded image (ignores 70x70 vs 300x300, etc.)."""
if not logo_url:
return None
path = urlparse(logo_url).path
base = re.sub(r"-\d+x\d+\.(png|jpe?g|webp)$", "", path, flags=re.IGNORECASE)
return base or path
def _best_logo_url(logo_url: str) -> str:
"""Prefer a larger Twitch CDN size for download."""
if not logo_url:
return logo_url
u = logo_url
for small, large in (("70x70", "300x300"), ("36x36", "300x300"), ("50x50", "300x300")):
if small in u:
u = u.replace(small, large)
break
return u
def _parse_created_at(raw) -> datetime | None:
if raw is None:
return None
if isinstance(raw, (int, float)):
return datetime.utcfromtimestamp(raw)
s = str(raw).replace("Z", "+00:00")
try:
return datetime.fromisoformat(s)
except ValueError:
return None
def open_chat_json(path: Path) -> dict | None:
try:
with path.open("rb") as f:
magic = f.read(4)
if magic[:2] == b"\x1f\x8b":
with gzip.open(path, "rt", encoding="utf-8") as f:
return json.load(f)
with path.open("r", encoding="utf-8") as f:
return json.load(f)
except (OSError, json.JSONDecodeError) as e:
print(f"skip {path}: {e}", file=sys.stderr)
return None
@dataclass
class SeenAvatar:
fingerprint: str
first_at: datetime
url: str
def collect_avatars(
chat_root: Path, roster: dict[str, list[str]]
) -> dict[tuple[str, str], dict[str, SeenAvatar]]:
"""
Returns map (slug, login) -> fingerprint -> SeenAvatar (earliest message wins per fp).
"""
login_to_slug: dict[str, str] = {}
for slug, logins in roster.items():
for lg in logins:
login_to_slug[lg.lower()] = slug
# (slug, login) -> fp -> SeenAvatar
acc: dict[tuple[str, str], dict[str, SeenAvatar]] = defaultdict(dict)
files = sorted(chat_root.glob("*/chat/*.json"))
if not files:
print(f"No JSON under {chat_root}/*/chat/", file=sys.stderr)
return acc
for jp in files:
data = open_chat_json(jp)
if not data:
continue
for c in data.get("comments") or []:
com = c.get("commenter") or {}
login = (com.get("name") or com.get("login") or "").strip().lower()
if not login or login not in login_to_slug:
continue
logo = com.get("logo")
if not logo or not str(logo).startswith("http"):
continue
fp = _avatar_fingerprint(str(logo))
if not fp:
continue
slug = login_to_slug[login]
key = (slug, login)
created = _parse_created_at(c.get("created_at"))
if created is None:
created = datetime.min
cur = acc[key].get(fp)
url = _best_logo_url(str(logo))
if cur is None or created < cur.first_at:
acc[key][fp] = SeenAvatar(fp, created, url)
return acc
def download_as_jpeg(url: str, dest: Path) -> bool:
dest.parent.mkdir(parents=True, exist_ok=True)
req = Request(url, headers={"User-Agent": "BattleRoyale-pfp-fetch/1.0"})
try:
with urlopen(req, timeout=60) as resp:
data = resp.read()
except OSError as e:
print(f"download failed {url}: {e}", file=sys.stderr)
return False
try:
from io import BytesIO
from PIL import Image
im = Image.open(BytesIO(data)).convert("RGB")
im.save(dest, "JPEG", quality=92)
except ImportError:
# No Pillow: write raw if already jpeg
if data[:2] == b"\xff\xd8":
dest.write_bytes(data)
else:
print("Install Pillow for PNG/WebP -> JPEG: pip install pillow", file=sys.stderr)
return False
except OSError as e:
print(f"jpeg encode {url}: {e}", file=sys.stderr)
return False
return True
SECTION_START = "<!-- pfp:chat-exports -->"
SECTION_END = "<!-- /pfp:chat-exports -->"
def build_section_md(images: list[tuple[str, str]]) -> str:
"""images: list of (caption, relative_path from Story/)"""
lines = [SECTION_START, "", "## Profile pictures", ""]
for caption, rp in images:
lines.append(f"**{caption}**")
lines.append("")
lines.append(f"![]({rp})")
lines.append("")
lines.append(SECTION_END)
return "\n".join(lines) + "\n"
def inject_section(content: str, section_md: str) -> str:
if SECTION_START in content and SECTION_END in content:
pre, _, rest = content.partition(SECTION_START)
_, _, post = rest.partition(SECTION_END)
return pre.rstrip() + "\n\n" + section_md + "\n" + post.lstrip()
# After first heading line
lines = content.splitlines()
if not lines:
return section_md + content
out = [lines[0], "", section_md]
if len(lines) > 1 and lines[1].strip():
out.append("")
out.extend(lines[1:])
return "\n".join(out)
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("--chat-root", type=Path, default=Path(DEFAULT_CHAT_ROOT))
ap.add_argument("--story-root", type=Path, default=Path(__file__).resolve().parents[1] / "Story")
ap.add_argument(
"--no-write-md",
action="store_true",
help="Only download images; do not edit Story/*.md",
)
args = ap.parse_args()
if not args.chat_root.is_dir():
print(f"Chat root not found: {args.chat_root}", file=sys.stderr)
print("Set MIXER_TWITCH_CHAT or pass --chat-root.", file=sys.stderr)
return 1
full_roster: dict[str, list[str]] = {**ROSTER, **CAMEO_ROSTER}
acc = collect_avatars(args.chat_root, full_roster)
pfp_root = args.story_root / "pfp"
# Flatten per slug for multi-login: still per-login files
for slug, md_name in MD_FILES.items():
story_rel = f"pfp/{slug}"
section_images: list[tuple[str, str]] = []
display = Path(MD_FILES[slug]).stem.replace("-", " ")
if slug == "heart-and-mind":
order = [("Heart", "heart_cccc"), ("Mind", "brush_colourful")]
for label, login in order:
key = (slug, login)
avs = acc.get(key, {})
ordered = sorted(avs.values(), key=lambda x: x.first_at)
for i, av in enumerate(ordered):
fn = f"{login}_{i}.jpg"
rel = f"{story_rel}/{fn}"
dest = pfp_root / slug / fn
if download_as_jpeg(av.url, dest):
cap = f"{label} (`{login}`)"
if len(ordered) > 1:
cap = f"{cap}{i + 1}"
section_images.append((cap, rel))
else:
logins = ROSTER[slug]
for login in logins:
key = (slug, login)
avs = acc.get(key, {})
ordered = sorted(avs.values(), key=lambda x: x.first_at)
if not ordered:
continue
for i, av in enumerate(ordered):
fn = f"{login}_{i}.jpg"
rel = f"{story_rel}/{fn}"
dest = pfp_root / slug / fn
if not download_as_jpeg(av.url, dest):
continue
if len(logins) > 1:
cap = f"`{login}`"
else:
cap = display
if len(ordered) > 1:
cap = f"{cap}{i + 1}"
section_images.append((cap, rel))
if not section_images:
print(f"No avatars found for {slug}", file=sys.stderr)
continue
section_md = build_section_md(section_images)
md_path = args.story_root / md_name
if not args.no_write_md and md_path.is_file():
text = md_path.read_text(encoding="utf-8")
md_path.write_text(inject_section(text, section_md), encoding="utf-8")
print(f"updated {md_path}")
# Cameo creatures: one combined section in Cameo-Creatures.md
cameo_images: list[tuple[str, str]] = []
for slug in CAMEO_ROSTER:
logins = CAMEO_ROSTER[slug]
story_rel = f"pfp/{slug}"
for login in logins:
key = (slug, login)
avs = acc.get(key, {})
ordered = sorted(avs.values(), key=lambda x: x.first_at)
if not ordered:
print(f"No avatars in exports for cameo `{login}` ({slug})", file=sys.stderr)
continue
for i, av in enumerate(ordered):
fn = f"{login}_{i}.jpg"
rel = f"{story_rel}/{fn}"
dest = pfp_root / slug / fn
if not download_as_jpeg(av.url, dest):
continue
cap = f"`{login}`"
if len(ordered) > 1:
cap = f"{cap}{i + 1}"
cameo_images.append((cap, rel))
if cameo_images:
cameo_md = build_section_md(cameo_images)
cameo_path = args.story_root / CAMEO_MD
if not args.no_write_md and cameo_path.is_file():
cameo_path.write_text(
inject_section(cameo_path.read_text(encoding="utf-8"), cameo_md),
encoding="utf-8",
)
print(f"updated {cameo_path}")
elif not args.no_write_md:
print("No cameo avatars downloaded (check exports and logins).", file=sys.stderr)
return 0
if __name__ == "__main__":
raise SystemExit(main())