Zoom At The Mouse In PIXI

PIXI is a 2D graphics engine for the web, utilizing WebGL with canvas fallback. It bills itself mainly as a tool to make games, which by all appearances it’s quite decent at. I’m using it for a non-game project, and I wanted to give the user the ability to zoom in and out with the mouseweel. That’s easy enough but having the zoom occur to or from the point the mouse cursor is at, ala Google Maps, proved slightly more tricky. Let’s start out with a basic class that extends PIXI.Container so you can add stuff to it. It’ll take a canvas in the constructor & set up the renderer and loop, so when you do add stuff, it just shows up. Nice and simple for our purposes here.

In our main JS file, we’ll import ZoomStage, instantiate one, and draw some random circles & lines so there’s something visible to zoom into.

Now, how do we make it respond to mousewheel events? PIXI doesn’t provide mousewheel support, so we have to do it ourselves. Unfortunately, there are browser inconsistencies to reckon with, but they’re not too bad. Firefox uses an event called “DOMMouseScroll”, whereas other browsers use simply “mousewheel”. When you get the event object, in most browsers it has a wheelDelta property which is positive if the wheel was turned forwards (i.e. zooming in) and negative if the wheel was turned backwards. Firefox is the oddball again, providing a detail property that unintuitively has the opposite sign – negative for forward/in, positive for backwards/out. Now we can begin writing the event handler:

And register the event listeners in the constructor like so:

Now this will zoom in and out when you roll the mousewheel, but not where the cursor is pointing. To do that, we need to use a property of PIXI’s display objects called pivot. As the name suggests, if you change an object’s rotation, it’ll rotate around that point, but it does more than that. If you change scale, it also uses the pivot as the focal point. So if we set the pivot to the coordinates of the mouse cursor before changing scale, that should give us what we want.

There’s a hitch, though. The pivot is also where the object’s position is fixed on. Actually, that’s two hitches:

  1. The location of the pivot is set in the object’s own coordinate space. So if you have a 100×100 square and set its pivot to (50,50), it’ll be in the center of the square. This is regardless of scaling.
  2. The (x,y) coordinates of the object are where the pivot is placed. So if you again have a 100×100 square with pivot (50,50) and you set its position to (95,120), the center of the square will be positioned at (95,120), rather than the upper-left.

To cope with #1, we need to take the mouse coordinates, which are global & convert them to the local coordinate space of the object. That being regardless of scaling means if our example square is scaled so that it appears 222×222, or 37×37, or any other size, in its own coordinate space it’s still 100×100 & if you’re setting the pivot you need to account for that. To cope with #2, we need to realize that moving the pivot will move the object, and counter that so that it doesn’t appear to “jump” to a different spot as the zoom starts. This bit is easy – just reposition it at the mouse coordinates.

How exactly can one take the global coordinates from the mouse event and get them into the object’s own coordinate space? PIXI’s interactions system deals with this, it just doesn’t do mousewheel events. So there is a function already written for us that will convert global to local coordinates. From the PIXI docs here, the InteractionData class has a method getLocalPosition which takes ( displayObject, point, globalPos ) . The display object will be our ZoomStage, so its scaling will be taken into account. point is a PIXI.Point in which the converted coordinates will be stored, and globalPos is another PIXI.Point that will be used as custom global coordinates for the calculation. In other words, if we pass in our global coordinates of where the mouse cursor is, we’ll end up with the local coordinates we’re looking for!

Putting it all together, we’ll set the position of the ZoomStage to the mouse cursor coordinates, and its pivot coordinates to the mouse position converted into local coordinates. That will make the stage zoom from/to that location, while counter-adjusting the position of the stage so that it doesn’t actually move. Here is the final event handler:

You can find a working project for this at https://github.com/eiridescent/pixizam.

What Fitness Means To Me As A Trans Woman

my bike, a Trek 7.3 FX hybrid, stands in a grassy field.

At 32 years old, for the first time in my life, I’m serious about getting in shape. I’ve got an exercise mat, a dumbbell, a jump rope, and a plan. I’m biking more than ever before. I’m figuring out how to eat healthier. I’ve joined NerdFitness Academy. You might think it’s typical for someone who treated their body poorly in their 20s to try and not die of a heart attack at 50, and that’s probably true. But for me, there’s more to it than that. I am a transgender woman, and I’ve spent my life in a very fraught and deeply layered relationship with my body. Getting motivated to get fit is all about that relationship.


“[Women] are taught that our bodies are always failing us, because they are failing to live up to the shape that other people have told them to be. I first learned this lesson as a four year old, when I was told for the first time that my penis meant that I had to be a boy, regardless of what I believed or wanted.

Transpeople know the feeling of body failure with a deep and terrible intimacy…”

Kai Cheng Thom

Why exercise? Why pursue physical fitness? Because it’s your body, your home. Growing up as a trans girl – and years into adulthood as well – my main feeling towards my body was alienation. It was mine, but it didn’t feel like mine. Something was wrong. I wasn’t at home in my own body at all. I spent over two decades severely depressed, all the while knowing that I should take care of it, but lacking any investment in doing so. I wanted to stop feeling tired all the time, but trying to exercise was like if you had to do a stranger’s laundry to keep your own clean. I wanted more than anything to wake up, look in the mirror, and recognize what I saw. I did, in the “that is the body I inhabit” way, but yearned to identify with the face looking back through the mirror. Seeing your reflection and feeling, profoundly, spiritually, to the core of your being, that is me – that is something most people take for granted and one of the greatest joys for trans people who transition.

When you don’t feel that, and you’re living with undiagnosed, untreated clinical depression, and your body is full of the wrong hormones, and you wouldn’t really mind if you never woke up tomorrow, it’s nearly impossible to care about eating right and building strength.

Now, if you’ve been following me for some time you probably are aware that I served a four-year enlistment in the United States Air Force. It’s not at all uncommon for closeted trans women to join the military, or to pursue other hypermasculine-coded activities. Transphobia is so prevalent and so violent, and we internalize not only that but our society’s hatred of women and femininity so that we come to despise ourselves and seek to avoid being ourselves at any cost. Often it seems like the way to do that is to double down on the lie and pretend even harder to be a man. I genuinely believed that being molded by the military would solve all my problems. Instead, I lived with the psychic rot of self-hate and constant fear of the violence that would ensue if it were discovered who I really was.

Exercising and eating were no easier just because I was required to do them. I did PT as little as possible, took advantage of the Air Force’s lax fitness standards at the time, and ate lots of very unhealthy, greasy foods at the chow hall. In basic training, I was the weak link in my flight when PT tests were done and earned one of the most terrifying moments of my life when an MTI exploded at me at breakfast one morning.

I finally had the epiphany I needed and it was impossible for me to do anything about it because I would have been kicked out.


Now, I’m finally transitioning. It’s been a slow process for me; I’m four years in and still not out at work or publicly. I’m still working on actually getting all the treatments that I need. But I recognize my reflection more than I ever have before, and my life is full of such joy and fullness and verve as I never dreamed I would ever experience. My relationship with my body is still fraught. It always will be. There’s no escaping that. I feel the same pressures and have the same insecurities foisted upon me as any woman. I worry if I’ll be pretty enough. I worry if, even if I blend in with cis people, whether people will like me less because of my 6’2″ stature. I was very worried when I first started researching how to get in shape if strength training would make my muscles look too big and what people’s reactions to that would be. (Fortunately there are plenty of resources for women’s fitness that clarify you will not “get huge” unless you specifically work for that.)

The most important thing, though, is I am beginning, even if only a little bit, to love my body. And since I’ve gone through so much to get here and have so much more ahead in order to correct it and finally feel at home, it would be foolish in the extreme to not take care of it now. Feeling at home and connected to your body is the baseline, but it’s not enough. I want to feel great. I want the rush of not only inhabiting a body that’s right for me, but achieving with it.

And I need it to last as long as possible. Everyone wants to live as long as they can but it has a new urgency and greater significance to me. In my 30s, I am only now beginning the life I should have had from the start. Most people get 70-80 years living as their authentic selves in terms of gender and their body. I’m only going to get 40-50 if I live that long. I need to make sure I do. I need to make the most of every single day, and hopefully stretch beyond that to 90 years old and beyond. I wouldn’t bet against it either, as I’m a stubborn mule and I’ve only survived to reach this point through pure obstinate perserverence. Fitness and determination are what will get me to the end.

Prayer Beads

Prayer beads

Today I received my prayer beads from Fiery Crossroad on etsy. Mine are a bit different from the stock one they sell but the artist was really great to work with and I am so happy with the result. The plain red, white, and black beads that punctuate the set are the Norns – Urd, Verdande, and Skuld. The rest, starting from the tassel, are:

1. Yggdrasil
2. Sol
3. Åsgard
4. Vanheim
5. Alvheim
6. Midgard
7. Svartalvheim
8. Jotunheim
9. Muspelheim
10. Nivlheim
11. Helheim
12. Odin
13. Frigg
14. Tor
15. Siv
16. Ull
17. Ty
18. Balder
19. Nanna
20. Forsete
21. Hod
22. Brage
23. Idunn
24. Heimdall
25. Fulla
26. Eir
27. Gjevjon
28. Gnå
29. Sjavn
30. Lovn
31. Syn
32. Lin
33. Var
34. Vår
35. Såga
36. Snotra
37. Njord
38. Skade
39. Frøy
40. Frøya
41. Einherjer
42. Valkyrjer
43. Jord
44. Loke
45. Sigyn
46. Hel
47. Æge
48. Rån
49. Frosti
50. Mime
51. Måne

I’m still working on writing what to say for each of them! I’m keeping each one very short since there’s so many of them. If I ever feel the need, I can get devotional jewelry for just a specific one and write something longer for that.

A promise

Content warning: depression, dysphoria, breakups, suicide


One time I was in Zul’Farrak, because I’m a gigantic nerd and also because it was better than being present in my actual surroundings, on a military base. It was like meditation but with other people and hit points. I was helping a guildie and when we were finished, sitting there together in the sand, she surprised me.

“Can I tell you something, like really personal? I feel like I can trust you.”
“Nobody else knows this so can you keep it a secret?”
“I was born a boy.”

Agonizing seconds passed. I knew she’d be spending every single one of them bracing for the worst. I had to decide. I swallowed hard. My hands shook.

“I’ve never told anyone this before, but… me too.”

I explained to her that I hadn’t transitioned, that this was all completely new to me, that I was terrified, but I was also dying.

“I don’t have any friends,” she told me, “they always leave. I can hook you up with some support groups in the PNW though.”
“I’m tall.”
“I’m not saying you can’t do this, but it’s going to draw attention, you know? I’m just saying.”
“I have a big awful crush on a boy in the guild. I’m like 99% certain he feels that way too. It’s hopeless, though.”
“Yeah. I’ve fallen for plenty of internet boys I can never be with too. You learn to deal with it and enjoy it for what it is.”

I logged out and reread TSRoadmap for the 112th time. It was utterly impossible. Not happening. A fantasy at best. But if I’d been cursed with eternal life like some kind of fucked up transsexual character of Greek myth, I’d have spent eternity rereading it and dreaming.

I’m out of the military. I’m in college, like before I enlisted, but this time I’m gay. I certainly wasn’t a woman, because I couldn’t be a woman, life just didn’t work that way. Oh, it did for other people. Those other trans women out there, actually transitioning (somehow) and existing and all that? Totally. Best I could do is put my face up to the glass and wonder what the secret was to passing through it. No, I had to accept being a guy and that meant being gay, and doing something with the knowledge I gained about myself the previous two years. As if one can ever return to such a state of ignorance.

This was actually worse than simply being in the closet. The cognitive dissonance will really screw you up. It’s like trying as hard as you can not to think about an elephant, except instead of picturing the elephant ever more clearly you get ever-escalating dysphoria and emotional rot and desire to jump from the 10th Avenue bridge into the silty, swirling currents of the Mississippi.

Mostly, I dealt with it by listening to heavy metal. Like man, have you heard the new Agalloch? It’s so good. Fucking bleak, man. You might go goth, instead. You might even stay goth when you transition. I grew a beard. It was a magnificent beard, aside from the fact it was just something to hide behind. Something so I would at least have a different face to stare at in my mirror and not recognize.

It’s a few years later. I’m transitioning, somehow. I’m dissolving estrodial under my tongue, anyway, and what happens as a result of that is simply going to happen. It’s not that I can’t imagine doing those things so much as that they’re happening and I don’t have a choice.

I have a girlfriend for the second time in my life. The literal first thing that happened when we became a couple is that she moved in with me. Before our first date, even. On the bright side I’m pretty chill about calling or not calling for a UHaul now because I already mastered it.

I shave my face. I cry. She touches me. I cry. She chuckles and I ask her what’s funny and she says she was just thinking about how completely different our bodies are. I cry. She says her needs aren’t being met. I cry.

It’s a few years later. I’m still transitioning. I’m not out at work. I’ve been in the hospital, I’ve been out. I found religion and pop music. I want to scream. I don’t think I’ll ever stop wanting to scream. I’m one of those trans women. I’m alive. You can be too. I promise. It’s brutal out there, but you can be too.

Sound & Color Toy

I actually made this a little while back, while watching AGDQ 2014: http://eiridescent.com/colors

When you click on one of the squares, it generates a tone based on the color. Hues map to notes on two octaves of a pentatonic scale, lightness corresponds to volume, and saturation to duration. It also blends the color you clicked on into the colors of the adjacent (non-diagonal) squares, so it’s impossible to play this “instrument” without irrevocably changing it.

I wanted to learn a bit of the Web Audio API, and while it’s a bit low-level, it’s not too hard to deal with for making simple notes like this.

Web Audio still has vendor prefixes hanging around, so if the spec evolves this code could become obsolete. An “oscillator” produces a wave, and “gain” lets you adjust the volume. So you’re kind of creating these components & imagining how you would have to physically connect them for it to work. Make an oscillator, connect it to the gain, connect the gain to the context.destination which you can kind of think of as the final output or speakers. If you did it the other way around, if the API let you (I haven’t tried), it wouldn’t work: you’d have a gain node changing the gain of nothing, then an oscillator, then the output. It’s not just “combine these things together to make the resulting sound,” the ordering matters. For folks who have done electronic audio stuff before this is probably not at all a surprise, but to me it was less obvious at first.

oscillator.type  could be sine, square, sawtooth, triangle, or “custom”, the latter of which both fascinates and terrifies me.

With that out of the way, playing notes based on color properties is easy, with a little assistance from jQuery.

From here, I think it’d be fun to make a simple music sequencer, but I’d have to learn more about how such a thing even works.