Skip to content

Pokémon Cards Holographic

Gotta catch ‘em all!

Let’s demonstrate the <HoverTilt /> component applied to Pokémon cards! I’ll show a few examples of basic cards and some more advanced foil effects if you’re willing to customise some CSS!

We simply wrap the Clefairy card <img /> element inside <hover-tilt> with matching rounded corners. No extra props here, so you get the default overlay blend mode and subtle shadow.

Using TailwindCSS we apply a child-selector border radius ([&::part(container)]:rounded-[4.55%/3.5%]) to the container element, and the inner parts of the web-component will inherit this radius. (see Styling Reference -> Border Radius for more details)

index.html
<hover-tilt
shadow
class="[&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/sv3-5_en_035_std.webp"
alt="Pokémon #0035: Clefairy"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
Preview
Pokémon #0035: Clefairy Clefairy is so happy to be tilting with you!

Basic cards often come with a reverse-holo version!

So here we are using the glare-mask prop to point to a PNG that already matches the reverse-holo layout.

The masks we got from PTCG-Live are luminance-based, so we set glare-mask-mode="luminance" to ensure the glare is only applied to the parts of the card that are not black.

Finally we set the blend-mode to luminosity which combined with glare-intensity of 4 gives us a nice shiny semi-metallic effect.

index.html
<hover-tilt
shadow
glare-mask="url(/pokemon/sv3-5_en_035_ph.foil.webp)"
glare-mask-mode="luminance"
glare-intensity={4}
blend-mode="luminosity"
class="[&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/sv3-5_en_035_std.webp"
alt="Pokémon #0035: Clefairy Reverse Holo"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
Preview
Pokémon #0035: Clefairy Reverse Holo OoooOOoohhh... shiny!

Full Art cards have a metallic-style sheen to them, with complex masking.

Setting blend-mode="plus-lighter" lets the foil texture add brightness, while a low glare-intensity keeps the glare controlled. We also point glare-mask to a PNG that already matches the foil layout.

index.html
<hover-tilt
shadow
scale-factor={1.1}
glare-mask="url(/pokemon/me1_en_169_std.foil.webp)"
glare-mask-mode="luminance"
glare-intensity={2}
blend-mode="hard-light"
class="[&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/me1_en_169_std.webp"
alt="Pokémon Trainer Lillie (Full Art)"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
Preview
Pokémon Trainer Lillie (Full Art) Lillie shows off her determination!

To create a card that looks a little like the SV Era ex cards, we can utilise a linear gradient and a star-pattern image, as well as the radial gradient glare.

I won’t explain this fully, but the code is shown below.

The main things to note are;

  • creating a new ::after pseudo-element to apply the holo effect
  • using the calc(50% + var(--hover-tilt-x, 0) * 5px) function to move the holo image
  • applying mix-blend-mode and background-blend-mode for the holo effect
index.html
<hover-tilt
shadow
scale-factor={1.1}
glare-mask="url(/pokemon/sv9_en_056_std.foil.webp)"
glare-mask-mode="luminance"
glare-intensity={1.5}
blend-mode="hard-light"
class="ex-holo [&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/sv9_en_056_std.webp"
alt="Pokémon Lillie's Clefairy (ex Holo)"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
<style>
.ex-holo::part(tilt)::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background-image:
url(https://poke-holo.b-cdn.net/foils/151/birthday-holo-dank-2.webp),
var(--hover-tilt-default-gradient);
background-size: 120% 160%, cover;
background-position:
calc(50% + var(--hover-tilt-x, 0) * 5px)
calc(50% + var(--hover-tilt-y, 0) * 5px),
center;
background-repeat: no-repeat;
background-blend-mode: color-burn;
mix-blend-mode: soft-light;
opacity: calc(var(--hover-tilt-opacity, 0) * 0.75);
will-change: background-image, opacity;
}
</style>
Preview
Pokémon Lillie's Clefairy (ex Holo) Is it Clefairy's Birthday!?

So here’s a very special, sparkly design!

This type of card has a single foil mask but with some special effects applied to the glare layer with background images and blend modes.

This is not a 100% accurate representation of the real-world card, I have chosen to ignore the ‘etching’ here.

I won’t go into too much detail, but you can see the code and demo below. I’m basically layering three images on top of each other; a rainbow gradient, a sparkles image, and the default glare gradient. When blending effects are applied between these layers we end up with a pretty cool effect!

will-change is used to hint to the browser that these properties are likely to change, so the browser can optimize the rendering of the element.

index.html
<hover-tilt
shadow
scale-factor={1.2}
glare-mask="url(/pokemon/sv9_en_184_std.foil.webp)"
glare-mask-mode="luminance"
glare-intensity={3}
blend-mode="hard-light"
class="sparkles [&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/sv9_en_184_std.webp"
alt="Pokémon Trainer Lille's Clefairy (Special Illustration Art)"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
<style>
.sparkles::part(tilt)::before {
--sparkle-rainbow-gradient: linear-gradient(to top left, #f9b3eb, #e2a6fc, #88a2f8, #a2f5a9 90%);
--sparkles-image: url(/pokemon/sparkles.webp);
--sparkles-offset: calc(50% + var(--hover-tilt-x, 0) * 1.5px) calc(50% + var(--hover-tilt-y, 0) * 1.5px);
background-image:
var(--sparkle-rainbow-gradient),
var(--sparkles-image),
var(--hover-tilt-default-gradient);
background-size: cover, 200px 200px, cover;
background-position: center, var(--sparkles-offset), center;
background-repeat: no-repeat, repeat, no-repeat;
background-blend-mode: color-burn, color-dodge;
opacity: calc(var(--hover-tilt-opacity, 0) * 0.6);
will-change: background-image, background-position, opacity;
}
</style>
Preview
Pokémon Trainer Lille's Clefairy (Special Illustration Art) Clefairy shows off it's signature derpy tooth.

The Masterball holo cards have two masks; an etched pattern plus a foil plate.

We use multiple glare-mask values and combine them with glare-mask-composite="intersect" so only the overlapping areas shine.

Here I’m also bumping the glare-intensity, scale-factor and shadow-blur to exaggerate the ‘gallery’ effect!

index.html
<hover-tilt
shadow
shadow-blur={60}
scale-factor={1.5}
glare-mask="url(/pokemon/sv8-5_en_074_mph.etch.png), url(/pokemon/sv8-5_en_074_mph.foil.webp)"
glare-mask-mode="luminance"
glare-intensity={4}
glare-mask-composite="intersect"
blend-mode="luminosity"
class="[&::part(container)]:rounded-[4.55%/3.5%]"
>
<img
src="/pokemon/sv8-5_en_074_std.webp"
alt="Pokémon #0133: Eevee Reverse Holo Masterball"
loading="lazy"
class="rounded-[inherit]"
/>
</hover-tilt>
Preview
Pokémon #0133: Eevee Reverse Holo Masterball Eevee is a boosted n00b.

Here’s an alternate version of the Masterball holo taking a slightly different approach.

We still use the same two masks, but instead of applying the “etch” mask to the gradient ::before layer; we instead create a new layer (.reverse-ball-etch) and style definition, and blend the etch image with the radial gradient.

Using hard-light gives it a slightly more metallic shine.

Again, this is a very advanced use-case, but it demonstrates the power of the component and the ability to create custom effects.

Pokémon #0197: Umbreon Reverse Holo Masterball
Umbreon's the GOAT.
Pokémon #0700: Sylveon Reverse Holo Masterball
Sylveon's cute, tho.
index.html
<hover-tilt
shadow
shadow-blur={60}
scale-factor={1.2}
glare-mask="url(/pokemon/sv8-5_en_059_mph.foil.webp)"
glare-mask-mode="luminance"
glare-mask-composite="intersect"
blend-mode="hard-light"
class="reverse-ball [&::part(container)]:rounded-[4.55%/3.5%] hover:z-10"
style="--hover-tilt-etch-image: url(/pokemon/sv8-5_en_059_mph.etch.webp);"
>
<img
src="/pokemon/sv8-5_en_059_std.webp"
alt="Pokémon #0197: Umbreon Reverse Holo Masterball"
loading="lazy"
class="rounded-[inherit]"
/>
<div class="reverse-ball-etch"></div>
</hover-tilt>
<style>
.reverse-ball::part(container) {
/* create a simple custom gradient for the glare / etch layers */
--hover-tilt-custom-gradient: radial-gradient(
farthest-corner circle at var(--gradient-x) var(--gradient-y),
rgb(237 237 245) 8%,
rgb(13 13 18) 90%
);
}
/* create a new layer inside the component slot, this is purely so
we can fade the opacity -- as layers with masks cannot set transparency */
.reverse-ball-etch {
position: absolute;
inset: 0;
border-radius: 4.55%/3.5%;
pointer-events: none;
mix-blend-mode: overlay;
/* set the opacity to the same as the glare layer,
so that the etching image is visible while hovered over the card */
opacity: calc(var(--hover-tilt-opacity, 0) * 0.75);
will-change: opacity;
}
/* place the masked-layers inside the etching layer */
.reverse-ball-etch::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
/* set the background image to the etching image and the radial gradient */
background-image: var(--hover-tilt-etch-image), var(--hover-tilt-custom-gradient);
background-size: cover, cover;
background-position: center, center;
background-repeat: no-repeat, no-repeat;
/* blend the etching image and the radial gradient in difference mode, so that
the etching image is has a kind of dark/light contrast effect */
background-blend-mode: difference;
/* mask the etching effect with the radial gradient (glare) */
mask-image: var(--hover-tilt-custom-gradient);
mask-size: cover;
mask-position: center;
mask-repeat: no-repeat;
mask-mode: var(--hover-tilt-glare-mask-mode);
will-change: background-image, mask-image, opacity;
}
</style>