Feat/lanyard front back images#977
Merged
DavidHDev merged 12 commits intoJun 8, 2026
Merged
Conversation
Replace the single `cardImage` prop with `frontImage` and `backImage`, plus
an `imageFit` ('cover' | 'contain') option. The card model's atlas maps the
front face to the left half and the back face to the right half, so each
image is composited into its own half of a canvas texture and the two faces
render independently. Images are drawn aspect-preserving (no stretching).
When no image is supplied, the original baked texture is returned unchanged,
so default rendering is untouched.
Mirror the front/back compositing API (frontImage, backImage, imageFit) in the JavaScript + Tailwind variant. Default rendering is preserved when no custom image is provided.
Mirror the front/back compositing API (frontImage, backImage, imageFit) in the TypeScript + CSS variant, with prop types on LanyardProps and BandProps. Default rendering is preserved when no custom image is provided.
Mirror the front/back compositing API (frontImage, backImage, imageFit) in the TypeScript + Tailwind variant. Default rendering is preserved when no custom image is provided.
Expose the band's meshline lineWidth as a `lanyardWidth` prop (default 1). Widening the band gives a custom band image more room and reduces texture stretching. Default value preserves the current appearance.
Mirror the lanyardWidth prop (maps to meshline lineWidth, default 1) in the JavaScript + Tailwind variant.
Mirror the lanyardWidth prop (maps to meshline lineWidth, default 1) in the TypeScript + CSS variant, typed on LanyardProps and BandProps.
Mirror the lanyardWidth prop (maps to meshline lineWidth, default 1) in the TypeScript + Tailwind variant.
Owner
|
Pretty nice, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When I was using the Lanyard component, I noticed that it was not very convenient to customize the card artwork and the lanyard band texture.
This PR adds new props for customizing the card's front face, back face, and band texture:
frontImagebackImageimageFitlanyardImagelanyardWidthThe front and back card images are rendered independently and preserve their original aspect ratio, so they will not be stretched or distorted. The lanyard band can also use a custom texture, with an adjustable width to give custom artwork more visible space.
Motivation
The card model uses a single texture atlas. The front face is UV-mapped to the left half of the texture, and the back face is UV-mapped to the right half.
Because of this, simply replacing the card material's
mapwith a custom image does not work correctly. The image can bleed across both sides of the card, or appear cropped and zoomed, because each face only samples part of the atlas.This PR solves that by compositing the custom front and back images into the correct regions of the original texture atlas.
The lanyard band also benefits from more flexible customization. Custom band textures can now be passed in directly, and
lanyardWidthcan be adjusted to give the artwork more room to display clearly.New Props
frontImagestring | nullnullbackImagestring | nullnullimageFit'cover' | 'contain''cover'lanyardImagestring | nullnulllanyardWidthnumber1Example
How It Works
For the card, the front and back UV regions were measured from
card.glb. The front face uses the left half of the texture, and the back face uses the right half.When
frontImageorbackImageis provided, the component creates a newCanvasTextureat the atlas resolution. It first draws the original baked texture, preserving the card edges and any untouched areas. Then it draws each custom image into its corresponding region of the atlas.The card images are drawn with aspect-ratio preserving behavior:
coverfills the target area and may crop part of the image.containkeeps the full image visible and may leave empty space.For the lanyard band,
lanyardImageis used as the band texture, andlanyardWidthcontrols the visual width of the band.Backwards Compatibility
This change does not affect existing usage.
If no custom card image is provided, the component keeps using the original baked card texture.
lanyardWidthalso defaults to1, so the existing demo should render the same as before.Notes
Card and band images should use raster formats such as PNG or JPG.
SVG images may not work reliably when drawn onto a canvas, so they may be skipped.
The changes have been applied consistently across all four variants: JS/CSS, JS/Tailwind, TS/CSS, and TS/Tailwind.
The demo prop table and usage snippet have also been updated.
Commits
The changes are split into separate commits for easier review. It's currently working fine in my own project.
If you have any better suggestions for this feature, please let me know, and I will continue to make changes. Thank you.
2026-06-07.20.26.53.mov