Commit Graph

141 Commits (physics)

Author SHA1 Message Date
Noah 08e65c32b5 Overhaul the Platformer Physics System
* Player character now experiences acceleration and friction when
  walking around the map!
* Actor position and movement had to be converted from int's
  (render.Point) to float64's to support fine-grained acceleration
  steps.
* Added "physics" package and physics.Vector to be a float64 counterpart
  for render.Point. Vector is used for uix.Actor.Position() for the sake
  of movement math. Vector is flattened back to a render.Point for
  collision purposes, since the levels and hitboxes are pixel-bound.
* Refactor the uix.Actor to no longer extend the doodads.Drawing (so it
  can have a Position that's a Vector instead of a Point). This broke
  some code that expected `.Doodad` to directly reference the
  Drawing.Doodad: now you had to refer to it as `a.Drawing.Doodad` which
  was ugly. Added convenience method .Doodad() for a shortcut.
* Moved functions like GetBoundingRect() from doodads package to
  collision, where it uses its own slimmer Actor interface for just the
  relevant methods it needs.
2020-04-04 21:00:32 -07:00
Noah c3d7348843 Inventory System for Level Actors
* Added an inventory system for actors as a replacement to the arbitrary
  key/value data store. Colored keys now add themselves to the player's
  inventory, and colored doors check the inventory.
* Inventory is a map[string]int between doodad filenames
  (red-key.doodad) and quantity (0 for key items/unlimited qty).
* API methods to add and remove inventory.
* Items HUD appears in Play Mode in lower-left corner showing doodad
  sprites of all the items in the Player's inventory.
2020-04-02 23:09:46 -07:00
Noah 3cb99ad5f8 New (Colored) Locked Door Doodads
* Revamped the sprites for the four colored locked doors. They now have
  a side-view profile perspective rather than a front view.
* Doors open facing the left or the right based on what direction the
  colliding actor approached it from.
2020-04-02 21:43:41 -07:00
Noah f8ca9a0921 Tooltips Update
* Update code for recent changes in UI toolkit around event handlers for
  buttons.
* Add tooltips to various buttons in the Editor Mode. The left toolbar
  shows the names of each tool, the Doodad Palette shows the title of
  each doodad and the Color Palette shows the swatch attributes (solid,
  fire, water, etc.)
2020-03-09 22:22:22 -07:00
Noah 7142c76b86 Initial Guidebook code 2020-03-09 22:21:59 -07:00
Noah b4922edf5d Doodad Tool: Add Tag Support for edit-doodad
* The `doodad edit-doodad` command now allows setting custom key/value
  tags in doodad files, for extra data storage useful to their scripts.
* Colored keys and doors now store a `color` tag with the appropriate
  color so that their scripts don't have to parse their Title to find
  that information.
* Trapdoors now store a `direction` tag to hold the direction the door
  is facing.
2020-01-02 22:12:20 -08:00
Noah 0e3a30e633 Fix Actor Collision Checks Again
* Recent collision update caused a regression where the player would get
  "stuck" while standing on top of a solid doodad, unable to walk left
  or right.
* When deciding if the actor is on top of a doodad, use the doodad's
  Hitbox (if available) instead of the bounding box. This fixes the
  upside-down trapdoor acting solid when landed on from the top, since
  its Hitbox Y coordinate is not the same as the top of its sprite.
* Cheats: when using the noclip cheat in Play Mode, you can hold down
  the Shift key while moving to only move one pixel at a time.
2020-01-02 22:05:49 -08:00
Noah a43e45fad0 Level Collision and Scrolling Fixes
* Fix the level collision bug that allowed clipping thru a ceiling while
  climbing up a wall.
* Fix the scrolling behavior to keep the character on-screen no matter
  how fast the character is moving, especially downwards.
* Increase player speed and gravity.
* New cheat: "ghost mode" disables clipping for the player character.
* Mark an actor as "grounded" if they fall and are stopped by the lower
  level border, so they may jump again.
2020-01-02 20:23:27 -08:00
Noah 7b3aec0fef Fix Two-State Blocks & Collision Detection
* Two-state Buttons now also subscribe to the state change message, so
  other on/off buttons in the same level update to match the state of
  the button that was hit.
* Add lock mutexes around the scripting engine to protect from
  concurrent event handlers.
2020-01-02 17:58:22 -08:00
Noah cd31868a13 Add app version/update check to the Main Scene 2020-01-01 17:50:15 -08:00
Noah 8965a7d86a Doodads: Crumbly Floor, Start Flag & State Blocks
Add new doodads:

* Start Flag: place this in a level to set the spawn point of the player
  character. If no flag is found, the player spawns at 0,0 in the top
  corner of the map. Only use one Start Flag per level, otherwise the
  player will randomly spawn at one of them.
* Crumbly Floor: a solid floor that begins to shake and then fall apart
  after a moment when a mobile character steps on it. The floor respawns
  after 5 seconds.
* State Blocks: blue and orange blocks that toggle between solid and
  pass-thru whenever a State Button is activated.
* State Button: a solid "ON/OFF" block that toggles State Blocks back
  and forth when touched. Only activates if touched on the side or bottom;
  acts as a solid floor when walked on from the top.

New features for doodad scripts:

* Actor scripts: call SetMobile(true) to mark an actor as a mobile mob
  (i.e. player character or enemy). Other doodads can check if the actor
  colliding with them IsMobile so they don't activate if placed too close
  to other (non-mobile) doodads in a level. The Blue and Red Azulians
  are the only mobile characters so far.
* Message.Broadcast allows sending a pub/sub message out to ALL doodads
  in the level, instead of only to linked doodads as Message.Publish does.
  This is used for the State Blocks to globally communicate on/off status
  without needing to link them all together manually.
2019-12-30 18:13:28 -08:00
Noah c08a1bc13e PlayScene: Set the Edit Button's position correctly 2019-12-29 00:01:47 -08:00
Noah b924ea9467 UI: Renamed Anchor -> Side for frame packing layout 2019-12-28 21:48:49 -08:00
Noah 0437adfbf8 Change types int32 -> int per upstream render and ui library 2019-12-27 19:16:34 -08:00
Noah c1353d1c0f Split lib/ui into its own separate repo 2019-12-27 16:32:26 -08:00
Noah a060330450 Switch to external git.kirsle.net/go/ui package 2019-12-27 16:31:58 -08:00
Noah d658359240 Switch github.com/kirsle/golog to git.kirsle.net/go/log
* New logger module supports js/wasm build by skipping the dependency on
  ssh/terminal (which detected interactive consoles, not applicable to
  JS). In WASM the logs go to the browser console and ANSI color codes
  not needed.
2019-12-22 18:34:31 -08:00
Noah ea0b41a781 Cut lib/render into its own package, change all imports 2019-12-22 18:21:58 -08:00
Noah 2adffd56c6 Update wasm_exec.js from latest Go release 2019-12-22 18:15:09 -08:00
Noah 7355778a39 render: Refactor Events System to Make Module Standalone
* Refactor the events used in lib/render/sdl to be more general-purpose
  to make librender a stand-alone library separate from Doodle.
2019-12-22 14:11:01 -08:00
Noah 3634577f19 Prepare v0.0.10-alpha for release 2019-07-17 18:22:59 -07:00
Noah 32db95ea85 MacOS .app Bundle
* Add a shell script to generate a MacOS .app bundle for proper
  distribution.
2019-07-17 18:10:13 -07:00
Noah 65a811db0d Auto-prune Empty Chunks in Level Files
* Discovered a bug where if you hit the Undo key to erase pixels and an
  entire chunk became empty by it, the chunk would have rendering errors
  and show as a solid black square instead of the level wallpaper
  showing through.
* Chunks that have no pixels in them are culled from the chunker
  immediately when you call a Delete() operation.
* The level file saver also calls a maintenance function to prune all
  empty chunks upon saving the file. So existing levels with broken
  chunks need only be re-saved to fix them.
2019-07-16 22:10:18 -07:00
Noah 6af60f1128 Improve Collision Detection: More Active w/ Actors
* Improve the collision detection algorithm so that Actor OnCollide
  scripts get called more often WHILE an actor is moving, to prevent a
  fast-moving actor from zipping right through the "solid" hitbox and
  not giving the subject actor time to protest the movement.
* It's implemented by adding a `Settled` boolean to the OnCollide event
  object. When the game is testing out movement, Settled=false to give
  the actor a chance to say "I'm solid!" and have the moving party be
  stopped early.
* After all this is done, for any pair of actors still with overlapping
  hitboxes, OnCollide is called one last time with Settled=true. This is
  when the actor should run its actions (like publishing messages to
  other actors, changing state as in a trapdoor, etc.)
* The new collision detection algorithm works as follows:
  * Stage 1 is the same as before, all mobile actors are moved and
    tested against level geometry. They record their Original and New
    position during this phase.
  * Stage 2 is where we re-run that movement but ping actors being
    intersected each step of the way. We trace the steps between
    Original and New position, test OnCollide handler, and if it returns
    false we move the mobile actor to the Last Good Position along the
    trace.
  * Stage 3 we run the final OnCollide(Settled=true) to let actors run
    actions they wanted to for their collide handler, WITHOUT spamming
    those actions during Stage 2.
* This should now allow for tweaking of gravity speed and player speed
  without breaking all actor collision checking.
2019-07-16 21:07:38 -07:00
Noah 17b18b8c0a Better Ellipse Drawing Algorithm 2019-07-16 18:27:00 -07:00
Noah 0c6c77a423 Lemon-shaped Ellipse Tool (WIP)
* Add initial Ellipse Tool to the Editor Mode. Currently there's
  something wrong with the algorithm and the ellipses have a sort of
  'lemon shape' to them.
* Refactor the IterLine/IterLine2 functions to be more consistent.
  IterLine used to be the raw algorithm that took a bunch of coordinate
  numbers and IterLine2 took two render.Point's and was the main one
  used throughout the app. Now, IterLine takes the two Points and the
  raw algorithm function removed.
2019-07-14 14:18:44 -07:00
Noah cc1e441232 Eraser Tool, Brush Sizes
* Implement Brush Sizes for drawtool.Stroke and add a UI to the tools panel
  to control the brush size.
  * Brush sizes: 1, 2, 4, 8, 16, 24, 32, 48, 64
* Add the Eraser Tool to editor mode. It uses a default brush size of 16
  and a max size of 32 due to some performance issues.
* The Undo/Redo system now remembers the original color of pixels when
  you change them, so that Undo will set them back how they were instead
  of deleting the pixel entirely. Due to performance issues, this only
  happens when your Brush Size is 0 (drawing single-pixel shapes).
* UI: Add an IntVariable option to ui.Label to bind showing the value of
  an int reference.

Aforementioned performance issues:

* When we try to remember whole rects of pixels for drawing thick
  shapes, it requires a ton of scanning for each step of the shape. Even
  de-duplicating pixel checks, tons of extra reads are constantly
  checked.
* The Eraser is the only tool that absolutely needs to be able to
  remember wiped pixels AND have large brush sizes. The performance
  sucks and lags a bit if you erase a lot all at once, but it's a
  trade-off for now.
* So pixels aren't remembered when drawing lines in your level with
  thick brushes, so the Undo action will simply delete your pixels and not
  reset them. Only the Eraser can bring back pixels.
2019-07-11 19:07:46 -07:00
Noah 7317615318 Add fpm script to make RPM and Deb packages 2019-07-09 20:09:01 -07:00
Noah 329adb76d9 Add Open Source Licenses 2019-07-08 19:12:25 -07:00
Noah 0126c288b2 Minor Build Script Updates, Mac OS Support
* Update the Makefile to choose MacOS friendly `date` formats.
* Build the Windows doodle.exe binary as a GUI application to skip the
  console window.
* Added Mac OS build instructions.
2019-07-08 18:16:45 -07:00
Noah 154fc6c9cb Update Doodad build-scripts to tag extra data
* The Blue Azulian marks its doodad file as Hidden.
* All Doodads are write locked after generation and tagged with common
  author value.
2019-07-06 23:50:38 -07:00
Noah fd649b7ab1 Doodad CLI Tool Features; Write Lock and Hidden
* The `doodad` CLI tool got a lot of new commands:
  * `doodad show` to verbosely print details about Levels and Doodads.
  * `edit-level` and `edit-doodad` to update details about Levels and
    Doodads, such as their Title, Author, page type and size, etc.
* Doodads gain a `Hidden bool` that hides them from the palette in
  Editor Mode. The player character (Blue Azulian) is Hidden.
* Add some boolProps to the balance/ package and made a dynamic system
  to easily configure these with the in-game dev console.
  * Command: `boolProp list` returns available balance.boolProps
  * `boolProp <name>` returns the current value.
  * `boolProp <name> <true or false>` sets the value.
* The new boolProps are:
  * showAllDoodads: enable Hidden doodads on the palette UI (NOTE:
    reload the editor to take effect)
  * writeLockOverride: edit files that are write locked anyway
  * prettyJSON: pretty-format the JSON files saved by the game.
2019-07-06 23:28:11 -07:00
Noah 6476a67faf Make Fire Deadly
* Touching "fire" pixels in a level will pop up the End Level alert box
  saying you've died by fire and can restart the level.
* Update level.WriteFile() to prune broken links between actors before
  save. So when a linked actor is deleted, the leftover link data is
  cleaned up.
* Slight optimization in Canvas.drawStrokes: if either end of the stroke
  is not within view of the screen, don't show the stroke.
2019-07-06 20:31:50 -07:00
Noah cb02feff1d Add Switches, Fire/Water Collision and Play Menu
* New doodads: Switches.
  * They come in four varieties: wall switch (background element, with
    "ON/OFF" text) and three side-profile switches for the floor, left
    or right walls.
  * On collision with the player, they flip their state from "OFF" to
    "ON" or vice versa. If the player walks away and then collides
    again, the switch flips again.
  * Can be used to open/close Electric Doors when turned on/off. Their
    default state is "off"
  * If a switch receives a power signal from another linked switch, it
    sets its own state to match. So, two "on/off" switches that are
    connected to a door AND to each other will both flip on/off when one
    of them flips.
* Update the Level Collision logic to support Decoration, Fire and Water
  pixel collisions.
  * Previously, ALL pixels in the level were acting as though solid.
  * Non-solid pixels don't count for collision detection, but their
    attributes (fire and water) are collected and returned.
* Updated the MenuScene to support loading a map file in Play Mode
  instead of Edit Mode. Updated the title screen menu to add a button
  for playing levels instead of editing them.
* Wrote some documentation.
2019-07-06 18:30:03 -07:00
Noah a504658055 Centralized Tick Counter, Fix Actor Dragging Bug
* The game's tick counter was moved from Doodle.ticks to shmem.Tick
  where it is more easily available from every corner of the code.
* Fix a bug in the Level Editor where dragging an already-existing actor
  from one part of your map to another, would cause it to lose all its
  data (especially its UUID), breaking links to other doodads. Now the
  existing Actor catches a ride on the drag object to be reinserted
  later.
* Animate the Link Line visualizers between actors. They now animate a
  blinking color between magenta and grey-ish.
2019-07-05 16:04:36 -07:00
Noah dc2695cfc9 Add More Trapdoor Doodads
* Add the other trapdoor directions: Left, Right and Up.
* UI: Show a color square in each Palette Swatch button in Edit Mode.
  * Instead of just the label like "solid", "fire", "decoration" it also
    shows a square box colored as the swatch color. The label and box
    are left-aligned in the button.
* Minor Play Mode physics update:
  * The player jump is now limited: they may only continue to move
    upwards for 20 ticks, after which they must touch ground before
    jumping again.
  * Remove the "press Down to move down" button. Only gravity moves you
    down.
* Fix a crash in the Editor Mode when you dragged doodads on top of each
  other. Source of bug was the loopActorCollision() function, which only
  should be useful to Play Mode, and it expected the scripting engine to
  be attached to the Canvas. In EditorMode there is no scripting engine.
2019-07-05 15:02:22 -07:00
Noah 22440f436b Add Scrolling in the Doodad Palette Window
* Rudimentary scrolling shows a Left and Right button at the top of the
  Doodad Palette if your window is deemed not tall enough to contain all
  of the doodads.
* A "progress bar" is shown between the buttons indicating the
  percentage of your scroll down the doodad list. When you're able to
  see the final row of doodads, the progress bar is at 100%.
2019-07-03 21:55:15 -07:00
Noah 12d34517e9 Add Tool Bar to Editor Mode
* Toolbar has icon buttons for the Pencil Tool, Line Tool, Rect Tool,
  Actor Tool and Link Tool.
* Remove the tab buttons from the top of the Palette window. The palette
  tab is now toggled between Swatches and Doodads by the tool selected
  on the tool bar, instead of the tab buttons setting the tool.
* Remove the "Link Doodads" button from the Doodad Palette. The Link
  Tool has its own dedicated toolbar button with the others.
2019-07-03 20:24:04 -07:00
Noah 5a1ec156ca Editor Mode: Line Tool and Rectangle Tool
* Add support for the LineTool and RectTool while in the EditorMode to
  easily draw straight lines and rectangle outlines.
* Key bindings were added to toggle tools in lieu of a proper UI to
  select the tool from a toolbar.
  * "F" for Pencil (Freehand) Tool (since "P" is for "Playtest")
  * "L" for Line Tool
  * "R" for Rectangle Tool
2019-07-03 17:19:25 -07:00
Noah 5d8c5510d8 Draw Lines Visualizing Doodad Links in Edit Mode
* If the current edit tool is Actor or Link, use the new drawtool.Stroke
  object to draw visual lines connecting every pair of linked actors in
  the level. The lines are hidden during normal editing and gameplay and
  only appear when you're possibly manipulating your actors and links.
2019-07-03 16:51:23 -07:00
Noah c8620f871e Drawing Strokes and Undo/Redo Functionality
* Add new pkg/drawtool with utilities to abstract away drawing actions
  into Strokes and track undo/redo History for them.
* The freehand Pencil tool in EditorMode has been refactored to create a
  Stroke of Shape=Freehand and queue up its world pixels there instead
  of directly modifying the level chunker in real time. When the mouse
  button is released, the freehand Stroke is committed to the level
  chunker and added to the UndoHistory.
* UndoHistory is (temporarily) stored with the level.Level so it can
  survive trips to PlayScene and back, but is not stored as JSON on
  disk.
* Ctrl-Z and Ctrl-Y in EditorMode for undo and redo, respectively.
2019-07-03 16:25:23 -07:00
Noah 0c22ecae5e Level Exit Doodad
* Add a Level Exit doodad, which for now is a little blue flag on a pole
  that reads "END"
* JavaScript API: global function EndLevel() will end the level. The
  exit doodad calls this when touched by the player.
* Add a "Level Completed" alert box UI to PlayScene with dynamic button
  layouts.
  * The alert box pops up when a doodad calls EndLevel() and contains
    action buttons what to do next.
  * "Play Again" restarts the current level again.
  * "Edit Level" if you came from the EditorScene; otherwise this button
    is not visible.
  * "Next Level" is a to-be-implemented button to advance in the single
    player story mode. Only shows up when PlayScene.HasNext=true.
  * "Exit to Menu" is always visible and closes out to the MainScene.
2019-07-02 15:24:46 -07:00
Noah 3d08291bc5 Demo Running Level as Title Screen Wallpaper
* Load SDL2 fonts from go-bindata storage so we don't have to ship
  external font files on disk.
* Dedupe names of doodads so we don't show double on the front-end
  (go-bindata bundled doodads + those on local filesystem)
* Use go-bindata for accessing wallpaper images.
* Better flashed messages walking you through the Link Tool.
* Stylize the title screen (MainScene) by rendering a live example level
  as the background wallpaper, with mobile doodads in motion.
2019-06-27 22:59:36 -07:00
Noah 54776ec9e1 Makefile Love and Windows Bugfixes
* Fixed a bad filepath separator check that failed on Windows.
* Disable ANSI colors in logger for Windows console.
2019-06-27 20:24:13 -07:00
Noah 35a89e5dbe WASM: Store User Files in localStorage
* In WASM build, user levels and doodads are written to localStorage
  using their userdir path as keys (".config/levels/test.level")
* LoadFile() and WriteFile() for both Levels and Doodads interact with
  the localStorage for WASM build instead of filesystem for desktop.
* userdir.ListLevels() and ListDoodads() for WASM scan the localStorage
  keys for file names.
* userdir.ResolvePath() now works for WASM (previously was dummied out),
  checks for the file in localStorage.
2019-06-27 15:59:18 -07:00
Noah b17ca34de2 Bindata: Embedding Doodads and Levels (for WASM)
* Use `go-bindata` to embed built-in doodads and levels directly into
  the Doodle binary. `make bindata` produces the bindata source file.
* Add `FromJSON()` method to Levels and Doodads to load objects from
  JSON strings in memory (for bindata built-ins or WASM ajax requests)
* Update file loading functions to check the embedded bindata files.
  * pkg/config.go#EditFile:
    * Supports editing a level from bindata (TODO: remove this support)
    * If the "assets/levels/%(simple-name.level)" exists in bindata,
      edits that drawing.
    * No such support for editing built-in doodads.
    * WASM has no filesystem access to edit files except built-in
      levels (yet)
  * pkg/doodads#ListDoodads:
    * Prepends built-in doodads from bindata to the returned list.
    * WASM: no filesystem access so gets only the built-ins.
  * pkg/doodads#LoadFile:
    * Checks built-in bindata store first for doodad files.
    * WASM: tries an HTTP request if not found in bindata but can go no
      further if not found (no filesystem access)
  * pkg/filesystem#FindFile:
    * This function finds a level/doodad by checking all the places.
    * If the level or doodad exists in bindata built-in, always returns
      its system path like "assets/doodads/test.doodad"
    * WASM: always returns the built-in candidate path even if not found
      in bindata so that ajax GET can be attempted.
  * pkg/level#ListSystemLevels:
    * New function that lists the system level files, similar to the
      equivalent doodads function.
    * Prepends the bindata built-in level files.
    * WASM: only returns the built-ins (no filesystem support)
    * Desktop: also lists and returns the assets/levels/ directory.
  * pkg/level#LoadFile:
    * Like the doodads.LoadFile, tries from built-in bindata first, then
      ajax request (WASM) before accessing the filesystem (desktop)
* Menu Scene: TODO, list the built-in levels in the Load Level menu.
  This feature will soon go away when WASM gets its own storage for user
  levels (localStorage instead of filesystem)
2019-06-27 15:07:34 -07:00
Noah c7cc40a339 Refactor Render Texture-Cache Interface
Since SDL2 is using in-memory bitmaps the same as Canvas engine, the
function names of the render.Engine interface have been cleaned up:

* NewTexture(filename, image) -> StoreTexture(name, image)
  Create a new cached texture with a given name.
* NewBitmap(filename) -> LoadTexture(name)
  Recall a stored texture with a given name.
* level.Chunk.ToBitmap uses simpler names for the textures instead of
  userdir.CacheFilename file-like paths.
2019-06-27 13:01:01 -07:00
Noah 3d199ca263 SDL2: Cache Bitmaps in Memory, Not on Disk
* Update the SDL2 engine's texture caching to use an sdl.RWops file
  buffer in memory instead of outputting bitmap images to the
  filesystem.
2019-06-27 12:46:35 -07:00
Noah ba6892aa95 WASM Texture Caching
* Refactor texture caching in render.Engine:
  * New interface method: NewTexture(filename string, image.Image)
  * WASM immediately encodes the image to PNG and generates a JavaScript
    `Image()` object to load it with a data URI and keep it in memory.
  * SDL2 saves the bitmap to disk as it did before.
  * WASM: deprecate the sessionStorage for holding image data. Session
    storage methods panic if called. The image data is directly kept in
    Go memory as a js.Value holding an Image().
* Shared Memory workaround: the level.Chunk.ToBitmap() function is where
  chunk textures get cached, but it had no access to the render.Engine
  used in the game. The `pkg/shmem` package holds global pointers to
  common structures like the CurrentRenderEngine as a work-around.
  * Also shmem.Flash() so Doodle can make its d.Flash() function
    globally available, any sub-package can now flash text to the screen
    regardless of source code location.
  * JavaScript API for Doodads now has a global Flash() function
    available.
* WASM: Handle window resize so Doodle can recompute its dimensions
  instead of scaling/shrinking the view.
2019-06-27 12:03:52 -07:00
Noah 48fc40ade4 Texture Caching for WASM Canvas Engine
* Add RGBA color blending support in WASM build.
* Initial texture caching API for Canvas renderer engine. The WASM build
  writes the chunk caches as a "data:image/png" base64 URL on the
  browser's sessionStorage, for access to copy into the Canvas.
* Separated the ClickEvent from the MouseEvent (motion) in the WASM
  event queue system, to allow clicking and dragging.
* Added the EscapeKey handler, which will abruptly terminate the WASM
  application, same as it kills the window in the desktop build.
* Optimization fix: I discovered that if the user clicks and holds over
  a single pixel when drawing a level, repeated Set() operations were
  firing meaning multiple cache invalidations. Not noticeable on PC but
  on WebAssembly it crippled the browser. Now if the cursor isn't moving
  it doesn't do anything.
2019-06-26 22:44:08 -07:00