Skip to content

chenglou/chenglou.github.io

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

My MidJourney AI art gallery, made to show shiny UI/UX details. As seen in the tweet.

Demo

Features

  • Non-disruptive, interruptible transitions. Animations don't block your ability to interact with the UI.
  • Optionally reduced motion for accessibility.
  • Layout-aware decoupled hit areas. In the gallery's line mode, the left & right cursor hit areas vertically extend to the window's edges, so that horizontally thin images don't have smaller hit areas than others. Hit areas also don't move with their image during transition, so you don't have to snipe click images. Consequently, rapidly clicking the left or right image doesn't accidentally dismiss the gallery (caused by clicking on a gap between image, or re-clicking on the newly centering image itself while it's still moving).
  • Window resize transition. Just enough to convey what moved where.
  • Anchor during resize. No layout shift! Resize without losing what you're looking at.
  • Area-based responsive image size. Naive responsive layout uses the width of an item, but an image's visual impact is determined by its area. For the same width, square images visually appear bigger, while long images end up too thin. So we punish the formers by shrinking them, and grow the latters, to end up with more visually equal image sizes. Nice tangential article here.
  • Non-throttled cursor updates. The cursor state, when specified on the UI elements themselves (e.g. cursor: 'zoom-in'), doesn't update immediately during smooth scrolling. Hover effects also don't trigger til scrolling ends.
  • Edge rubberbanding on the first & last item.
  • Dynamic depth management. Proper z-index adjustments when images overlap. The center image in line view needs to be in front.
  • Framerate-decoupled animation. Transitions run well and on time even when framerate is uneven, or when frames are completely dropped on lower-end devices.
  • Spring physics (exaggerated in the link for effect). Subtle playful bounces.
  • Continous hover effect. The cursor attracts images magnetically, as opposed to a typical discrete, one-off upward lift transition trigger.
  • Seamless repositioning on image dismissal. In line view, navigating to a image and dismissing it transports you to the location of that image even if it's way further down the grid.
  • Pretty selections. Select-all doesn't ruin the page's look.
  • Routing.
  • Occlusion culling. Only render what's in view (sometime called virtualization). This puts a nice hard upper bound on the amount of DOM manipulations.
  • Keyboard inputs & multiple inputs coordination. Concurrent keys and cursor events are resolved without pretending they're independent events.
  • Progressive image loading. Though this could be done better.
  • Smoothness & performance. Works on 120fps displays, including ProMotion.
  • Battery-friendly. Fewer DOM nodes & no excessive tangential computations. You'll never get the Safari tab energy consumption warning.
  • Blur & brightness effects. These help focusing on the middle image in the line view.
  • SEO-friendly.
  • Cool images =)

For developers:

  • Short, dependency-free code with no hidden control flow.
  • Fun debug mode with manual frame stepping.
  • Guaranteed minimum render count. Renders are batched per frame. Also no multi-frames cascading rerenders from wrongly ordered state changes.
  • Minimal DOM nodes. A clean, wrapper-divs-free inspector experience.

Architecture

flowchart TB
  subgraph Initialization
    ISstate["State declaration"]
    IDOM["Static DOM chunks"]
    IEvents["Events Registration (all static)"]
  end
  IEvents -- triggers --> Render
  subgraph Render["Render (1 frame)"]
    direction TB
    A("DOM reads (batched)") --> State
    subgraph State["State changes"]
      direction TB
      B("Handle inputs") --> C("New layout & cursor")
      C --> D("Animation tick")
      D --> E("Occlusion & render DOM writes (batched)")
    end
    State --> F("Commit state changes")
  end
  Render -- "\nProgrammatic scroll/more animation?" --> Render