Skip to content
rim95devPublic

About

MapleStory Universe Cards (ideation only)

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

MapleStory Universe Cards

⚠️ Prototype — ideation only

This is a throwaway page built to explore an idea, not a product. Nothing here is a spec, a roadmap, or a commitment. All card artwork is AI-generated, the card list is invented, and the whole repository may be rewritten or deleted without notice.

Unofficial personal experiment. Not affiliated with, endorsed by, or representing any game or publisher.

Four cards, four optical models. Hover to tilt, click to enlarge, click anywhere off the card or press Esc to close. Vite + TypeScript; the output is a plain static site.

The page is dark only — index.html stamps data-color-mode="dark" and nothing changes it at runtime. src/styles/theme.css still carries the light palette on the bare :root, so dropping that attribute brings it back.

npm install
npm run dev
npm run build      # typecheck + static build into dist/
npm run preview    # serves the build exactly as it deploys, base path and all

Deploying

Published at https://rim95dev.github.io/msu-cards by .github/workflows/deploy.yml on every push to main. It needs Pages switched on for the repository with GitHub Actions as the source, once.

vite.config.ts sets base: '/msu-cards/'. Rename the repository and that has to change with it — every asset URL is derived from it, including the card images looked up at runtime through import.meta.env.BASE_URL. npm run dev will not catch a mismatch; npm run preview will.


How it works

The pointer is read in polar terms rather than as an x/y position: the angle from the card's center to the pointer, and how far out it sits.

--px, --py    pointer across the card, 0..1
--dx, --dy    the same, signed from the center: -1..1
--ang         angle from center to pointer, degrees, 0 = right
--lean        distance from center, 0 at the middle, 1 at the edge
--lean-y      vertical distance only, 0 at the middle, 1 at top or bottom
--lit         0 when the pointer is away, 1 while it is on the card

--ang is what the surfaces are built on. Once a surface knows the angle it is being viewed from, it can be written as a conic gradient or a hue rotation — so light travels around the card rather than sliding across it, which is what most of these materials actually do.

--lean is the other one worth reaching for: multiply anything by it and the effect starts at zero face-on and peaks at the corners, which is how nearly every real surface behaves.

Not every surface should use --ang, though. A treatment lit by a fixed source needs to ignore it — otherwise the light is really the cursor, and it shows. Those surfaces read --dy and --lean-y instead, so only tipping the card up and down changes what you see, and sliding sideways under the lamp changes nothing.

Motion is exponential smoothing rather than a spring — each value closes a fixed fraction of its remaining gap per unit time, with no velocity term. Nothing can overshoot or ring, which is the point: these values drive light, and light does not bounce.

Closing an enlarged card is the exception, and it is deliberate. Opening is a reveal and can take its time; closing is a dismissal and should be over before you think about it. The card is aimed at 0.84 of its resting size on a very short time constant, and the moment it passes below 0.97 it is retargeted back to 1. That dip is what gives it a snap — a decay on its own always reads limp, because its tail is asymptotic and the last stretch crawls. The handover is triggered by the value rather than a timer, or it would land at a different point in the curve depending on how large the card had been.

Every surface is generated in CSS. There are no texture files.


The surfaces

Surface Model What you should see
matte Diffuse Almost nothing. The control card
brush Anisotropic reflection Fine radial grain with two opposed highlight lobes swinging around
oilslick Thin-film interference The whole palette rotating as the angle changes, not sliding
facet Cut crystal Flat wedges that snap between values instead of sweeping. The cut belongs to the card — its origin never moves; only the light travelling across it does

facet reads most clearly at a glance; brush is the most subtle and needs a slow hover to show what it does.

A fifth surface, refract (chromatic dispersion under a fixed overhead light), is still in src/styles/fx-refract.css and in the Surface union, but no card uses it and main.ts no longer imports its stylesheet. Add a card with surface: 'refract' and restore that import to bring it back.

Tuning one

Each src/styles/fx-*.css is self-contained and reads the four variables above. Each also retunes --spec-size and --spec-strength, the shared highlight — that pair alone is most of the difference between matte and polished.


Card artwork

Full specification: ASSETS.md.

What Where Size
Card front — the whole card, frame and text included public/img/cards/{id}.png 734 × 1024, full bleed
Surface mask (optional, recommended) public/img/masks/{id}.png 734 × 1024

Four images: test1, test2, test3, test4. Cards are single-sided — no card back. Anything missing is drawn as a placeholder naming the file it wants.


Layout

index.html
src/
  main.ts              builds the grid, owns the open card
  card.ts              one card: DOM, pointer readings, open/close
  smooth.ts            exponential smoothing
  placeholder.ts       stand-in art; delete once every card has real art
  types.ts             CardData, Surface
  data/cards.ts        the card list
  styles/
    theme.css          page chrome, palette, light/dark
    card.css           card shell, film + spec layers, mask
    fx-*.css           one file per surface
public/img/            card art, masks, and the MetaMask mark

Things that will bite you

  • Surfaces are composited against the artwork, not the page. .tcard__face carries isolation: isolate, and removing it lets every film blend straight through to the page background.
  • --ang is deliberately not smoothed. An angle wraps at ±180°; interpolate it and the light takes the long way around every time the pointer crosses the center line.
  • A near-white card loses its light areas under refract or facet. That is what the masks in public/img/masks/ are for.
  • Cards with no image log a 404. The viewer probes for the real file first. The noise goes away as art gets added.
  • The wallet button is a mock and must stay one. It never touches window.ethereum; clicking it raises a notice saying so. A button that opens a real wallet prompt for a card that cannot be minted is worse than no button. The page copy is written as though the product existed — the banner at the top, that notice, and the footer are what keep it honest.

License

MIT — see LICENSE.

public/img/metamask-fox.svg is the exception: it is MetaMask's mark, taken byte-for-byte from the official pack at https://metamask.io/assets and not covered by the license above. It is kept as its own file, unaltered, so it stays easy to identify and to remove. Their guidance allows the mark to signal MetaMask support — so if this ever stops being a mock and starts pretending to connect, or if the button is dropped, take the file with it.

About

MapleStory Universe Cards (ideation only)

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages