Reproduce:
1. Add an item with animations, and play them.
2. Remove the item.
3. Add it back.
4. Observe the button shows up in "Paused" state, even though it's playing.
This is because the server-side template wasn't doing anything to try to keep the play/pause button it renders in sync with the current saved state in the cookies, so it was always causing a morph to the pause state. Now we listen to the cookie instead!
I also updated the JS behavior to be a bit more consistent: treat the behavior as defaulting to true, unless it's explicitly set to the string "false".
I pulled the source map for the Neopets renderer, and had Claude compare it to ours. It noticed the key issue responsible for a high number of unsolved rendering issues: we weren't setting up the `MotionGuidePlugin`, which I've never heard of before. Whoops!
In addition to this, we made some other minor fixes for consistency:
- Use whatever Stage object the library exports (will sometimes be StageGL)
- Resize the stage rather than the clip (shouldn't matter?)
- Send a callback to the library when done (I'm not aware of any anims that use this but some may!)
The specific item I was debugging was "Food Fight Shower", and it works now! But I also know we've had a solid handful of similar inexplicable wild rendering bugs, which I imagine this solves as well.
We might want to consider auditing our Known Glitches on SWF assets to see how many of them can be removed, now that this is resolved.
I couldn't find a library for this functionality that didn't require
jQuery, and I don't want to be adding *more* jQuery requirements. So, I
decided to throw together my own!
The `<magic-magnifier>` component copies its contents into a "lens"
element, then uses basic JS to track mouse position, then uses CSS to
move the lens and its contents into a helpful position.
One thing I noticed here is that the zoom is a bit crunchy because
we're using PNG images, and it's hard to zoom in even further than we
already are. I might try switching this UI to use the SVG images by
default instead?
When you hover the row for a layer in the table, it highlights the
corresponding layer in the outfit viewer. And when you click anywhere
in the row, it opens the first link (usually the PNG image).
Ah whoops, I didn't notice that, when Turbo morphs the
`<measured-container>` into what the server HTML returns, it deletes
the `style` attribute we were using.
In this change, I refactor for `MeasuredContainer` to be the component
rather than `MeasuredContent`, so that it can also be responsible for
listening for changes to its own `style` prop, and remeasuring when
they happen.
We're also careful to avoid infinite loops, by only doing this when the
property is missing! (Otherwise, setting `--natural-width` triggers the
callback again, oops!)
Oh sweet, I learned about a new CSS feature with good-enough support!
This lets you use CSS transitions for an element as it enters the page,
or becomes visible.
Firefox only has partial support for this feature rn, but its partial
support covers our case, I tested to make sure! (Specifically, it
doesn't handle transitioning from `display: none` yet, which isn't what
we're doing.)
It's only actually used in two JS files, so rather than doing a weird
global `$.ajaxSetup` call, let's just inline it into the small handful
of AJAX calls that actually care.
The silly motivation is that I wanted to remove `.prettierignore`,
which just exists to omit that one folder from `npm run format`. But it
also seems like this is the standard place to put them—a standard
created long after we first set this up lol
I think this has just been broken for a long time? And I don't think
it's very useful in a world 15 years later, where our problem *used* to
be giant gaps in our library, which isn't really our data problem
anymore.
Closes#3, by adapting the suggested changes! Thank you!!
We both change how we create pet name preview jobs, by catching the `@`
case early; and we better handle symbols in pet names when showing the
thank you message, by parsing the query string more correctly.
Co-Authored-By: Steve C <diceroll123@gmail.com>
I haven't been running Prettier consistently on things in this project.
Now, it's quick-runnable, and I've got it on everything!
Also, I just think tabs are the right default for this kind of thing,
and I'm glad to get to switch over to it! (In `package.json`.)
I skipped this for a bit because I couldn't think of a simple way to
adapt this behavior to a web component + vanilla CSS setting, but then
I thought of CSS variables, and sat down and cranked this out!
If something goes wrong, like the site goes down or has an intermittent
error, try a full pageload. That way, we're both retrying, and in a way
that gives the user more control and visibility into what's going on,
and what they can potentially do about it. (e.g. if there's a useful
error message, they will see it!)
The loading indicator *should* fade in after two seconds, to avoid a
flash of a loading indicator when the page loads quickly - but in some
circumstances it wouldn't delay:
1. Visit an item page. (It delays correctly the first time!)
2. Click "Infinite Closet", then click a link to another item page.
3. The loading indicator appears immediately, because this time the
web component JS is already loaded, so the `outfit-layer` elements
enter `:state(loading)` *immediately*. The element starts at
`opacity: 1`, and the delay doesn't matter, because it was never at
anything else.
In this change, we have the `outfit-viewer` web component take on a
`:state(after-first-frame)`, after a `setTimeout(0)` resolves. That
enables the loading state CSS to *never* apply on the first frame, but
then sometimes kick in on the *second* frame, so that the element is
correctly perceived as "transitioning" from hidden to visible, and the
two-second delay will apply.
For static image layers, this was *always* logging that we failed to
send the frame a "pause" message. Which, like, of course!
It makes sense to log the notable circumstance where we send a message
we *expect* to arrive, but the frame isn't loaded yet. But if there's
just no frame, ignore it and don't bother to say so.
Here, I remember the trick I learned when building the outfit viewer:
web components are great for making sure stuff stays initialized well
in a Turbo environment!
The problem was, after submitting the form and getting a new preview
loaded via Turbo, the part where we remove `inert` would get undone.
Additionally, this script only loads *once* per session, so if you
Turbo-nav to a different item then that part of the page never ran.
Instead, we use web components to remove the attributes on mount, then
again if they're ever reapplied by Idiomorph.
We mark the options as `inert` and `aria-hidden` while the JS is still
loading—and if the `noscript` tag tells us it's never coming, it covers
up the picker with a brief explainer!
The basics are working great! There's a few known missing things though:
- Add reasonable noscript behavior
- Disable options where there's no valid appearance
- Lay it out actually _good_, instead of just images dumped there