Observed since 20 Oct, 19:38 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
3d-whell-parallax-carousel
Smooth 3D parallax carousel with trapezoid perspective effect. Works with Vanilla JS, React, and Vue.
Smooth 3D parallax carousel with trapezoid perspective effect. Shows 5 cards at once — center card flat, side cards angled like a fan. Works with Vanilla JS, React, Vue 3, and TypeScript.
npm install 3d-whell-parallax-carousel
import { ParallaxCarousel } from "3d-whell-parallax-carousel";
const carousel = new ParallaxCarousel("#my-container", [
'<div style="color:white">Card 1</div>',
'<div style="color:white">Card 2</div>',
'<div style="color:white">Card 3</div>',
]);
import { ParallaxCarousel } from "3d-whell-parallax-carousel";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const carousel = new ParallaxCarousel("#my-container", products, {
renderItem: ({ item, index }) => `
<div style="text-align: center; padding: 20px;">
<img src="${item.image}" alt="${item.name}" style="width: 100%; border-radius: 4px;" />
<h3 style="margin-top: 10px; color: white;">${item.name}</h3>
</div>
`,
});
import { ParallaxCarousel, type ParallaxCarouselOptions } from "3d-whell-parallax-carousel";
interface Product {
id: number;
name: string;
image: string;
}
const products: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const options: ParallaxCarouselOptions<Product> = {
autoplay: true,
renderItem: ({ item }) => `
<div>
<img src="${item.image}" alt="${item.name}" />
<h3>${item.name}</h3>
</div>
`,
};
const carousel = new ParallaxCarousel<Product>("#my-container", products, options);
import { ParallaxCarouselReact } from "3d-whell-parallax-carousel/react";
const items = ["<div>Card 1</div>", "<div>Card 2</div>", "<div>Card 3</div>"];
function App() {
const ref = useRef(null);
return (
<>
<ParallaxCarouselReact
ref={ref}
items={items}
options={{ autoplay: true, interval: 3000 }}
onChange={({ index }) => console.log("Slide:", index)}
/>
<button onClick={() => ref.current.next()}>Next</button>
</>
);
}
import { ParallaxCarouselReact } from "3d-whell-parallax-carousel/react";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
// Your custom React component
function ProductCard({ product, index }) {
return (
<div style={{ padding: '20px', textAlign: 'center' }}>
<img src={product.image} alt={product.name} style={{ width: '100%', borderRadius: '4px' }} />
<h3 style={{ marginTop: '10px', color: 'white' }}>{product.name}</h3>
<p style={{ color: 'rgba(255,255,255,0.6)' }}>Index: {index}</p>
</div>
);
}
function App() {
const ref = useRef(null);
return (
<ParallaxCarouselReact
ref={ref}
items={products}
options={{
autoplay: true,
renderItem: ({ item, index }) => (
<ProductCard product={item} index={index} />
),
}}
onChange={({ index }) => console.log("Slide:", index)}
/>
);
}
import { useRef } from "react";
import {
ParallaxCarouselReact,
type ParallaxCarouselReactHandle,
type ParallaxCarouselReactProps,
} from "3d-whell-parallax-carousel/react";
interface Product {
id: number;
name: string;
image: string;
}
const items: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
function App() {
const carouselRef = useRef<ParallaxCarouselReactHandle>(null);
const handleChange: ParallaxCarouselReactProps["onChange"] = ({ index, total }) => {
console.log(`Slide ${index} of ${total}`);
};
return (
<>
<ParallaxCarouselReact<Product>
ref={carouselRef}
items={items}
options={{
autoplay: true,
renderItem: ({ item, index }) => (
<div>
<img src={item.image} alt={item.name} />
<h3>{item.name}</h3>
</div>
),
}}
onChange={handleChange}
/>
<button onClick={() => carouselRef.current?.next()}>Next</button>
</>
);
}
<template>
<ParallaxCarousel
ref="carousel"
:items="items"
:options="{ autoplay: true, interval: 3000 }"
@change="onSlideChange"
/>
<button @click="$refs.carousel.next()">Next</button>
</template>
<script setup>
import { ParallaxCarouselVue as ParallaxCarousel } from "3d-whell-parallax-carousel/vue";
const items = ["<div>Card 1</div>", "<div>Card 2</div>"];
const onSlideChange = ({ index, total }) => console.log(index, total);
</script>
<template>
<ParallaxCarousel
ref="carousel"
:items="products"
:options="{
autoplay: true,
renderItem: ({ item, index }) => h('div', {
style: { padding: '20px', textAlign: 'center' }
}, [
h('img', { src: item.image, style: { width: '100%', borderRadius: '4px' } }),
h('h3', { style: { marginTop: '10px', color: 'white' } }, item.name),
h('p', { style: { color: 'rgba(255,255,255,0.6)' } }, `Index: ${index}`),
]),
}"
@change="onSlideChange"
/>
</template>
<script setup>
import { h } from 'vue';
import { ParallaxCarouselVue as ParallaxCarousel } from "3d-whell-parallax-carousel/vue";
const products = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const onSlideChange = ({ index, total }) => console.log(index, total);
</script>
<template>
<ParallaxCarousel
ref="carouselRef"
:items="products"
:options="options"
@change="onSlideChange"
/>
<button @click="carouselRef?.next()">Next</button>
</template>
<script setup lang="ts">
import { ref, h, type VNode } from "vue";
import {
ParallaxCarouselVue as ParallaxCarousel,
type ParallaxCarouselInstance,
type ParallaxCarouselOptions,
type RenderItemContext,
} from "3d-whell-parallax-carousel/vue";
interface Product {
id: number;
name: string;
image: string;
}
const carouselRef = ref<ParallaxCarouselInstance | null>(null);
const products: Product[] = [
{ id: 1, name: "Product 1", image: "/img1.jpg" },
{ id: 2, name: "Product 2", image: "/img2.jpg" },
];
const options: ParallaxCarouselOptions<Product> = {
autoplay: true,
renderItem: ({ item, index }: RenderItemContext<Product>): VNode => {
return h('div', { style: { padding: '20px' } }, [
h('img', { src: item.image, style: { width: '100%' } }),
h('h3', item.name),
]);
},
};
const onSlideChange = ({ index, total }: { index: number; total: number }) => {
console.log(`Slide ${index} of ${total}`);
};
</script>
| Option | Type | Default | Description |
|---|---|---|---|
autoplay | boolean | true | Enable auto-advance |
interval | number | 2800 | Autoplay interval in ms |
pauseOnHover | boolean | true | Pause autoplay on hover |
duration | number | 650 | Transition duration in ms |
easing | string | 'cubic-bezier(0.4,0,0.2,1)' | CSS easing |
background | string | '#111111' | Card background color |
borderColor | string | 'rgba(255,255,255,0.1)' | Card border color |
borderWidth | string | '1.5px' | Card border width |
borderRadius | string | '4px' | Card border radius |
stageHeight | string | '420px' | Height of the carousel stage |
perspective | number | 900 | CSS perspective value in px |
showGrid | boolean | true | Show background grid |
gridColor | string | 'rgba(255,255,255,0.032)' | Grid line color |
gridSize | string | '38px' | Grid cell size |
slots | object | see below | Per-slot position config |
renderItem | function | undefined | Custom render function |
slots configCustomize each of the 5 visible positions (-2 to +2):
import type { ParallaxCarouselOptions } from "3d-whell-parallax-carousel";
const options: ParallaxCarouselOptions = {
slots: {
'-2': { x: -490, w: 220, h: 330, ry: 50, origin: 'right center', z: 1, op: 1 },
'-1': { x: -255, w: 192, h: 295, ry: 26, origin: 'right center', z: 2, op: 1 },
'0': { x: 0, w: 188, h: 275, ry: 0, origin: 'center center', z: 3, op: 1 },
'1': { x: 255, w: 192, h: 295, ry: -26, origin: 'left center', z: 2, op: 1 },
'2': { x: 490, w: 220, h: 330, ry: -50, origin: 'left center', z: 1, op: 1 },
},
};
| Field | Description |
|---|---|
x | Horizontal offset from center in px |
w | Card width in px |
h | Card height in px |
ry | rotateY angle in degrees |
origin | CSS transform-origin |
z | z-index |
op | opacity (0–1) |
renderItem callbackCustom render function for each item. Returns depend on framework:
| Framework | Return Type | Example |
|---|---|---|
| Vanilla JS | string | HTMLElement | '<div>Content</div>' |
| React | ReactNode | <MyComponent /> |
| Vue 3 | VNode | string | h('div', 'Content') |
Context object:
type RenderItem = (context: {
item: T; // The item data
index: number; // Item index
container: HTMLElement; // Card container element
}) => ReactNode | VNode | HTMLElement | string;
carousel.next(); // Go to next slide
carousel.prev(); // Go to previous slide
carousel.goTo(index); // Jump to specific index
carousel.updateOptions({
// Update options at runtime
interval: 5000,
background: "#222",
});
carousel.destroy(); // Clean up and remove from DOM
const ref = useRef<ParallaxCarouselReactHandle>(null);
ref.current?.next();
ref.current?.prev();
ref.current?.goTo(2);
ref.current?.updateOptions({ interval: 5000 });
ref.current?.destroy();
<script setup lang="ts">
const carouselRef = ref<ParallaxCarouselInstance | null>(null);
carouselRef.value?.next();
carouselRef.value?.prev();
carouselRef.value?.goTo(2);
carouselRef.value?.updateOptions({ interval: 5000 });
carouselRef.value?.destroy();
</script>
container.addEventListener("change", (e) => {
console.log(e.detail.index); // current index
console.log(e.detail.total); // total items
});
<ParallaxCarouselReact
items={items}
onChange={({ index, total }) => {
console.log(`Slide ${index} of ${total}`);
}}
/>
<ParallaxCarousel
:items="items"
@change="({ index, total }) => console.log(`Slide ${index} of ${total}`)"
/>
npm install
npm run build
Output goes to dist/.
# Watch mode
npm run dev
# Type check
npm run typecheck
This library includes full TypeScript support with:
<T>)renderItem callback with framework-specific return typesMIT
Download counts and popularity will appear here as the collector receives them.
| Package / target | Requirement | Relationship |
|---|---|---|
rollupEnvironment{
"local_name": "rollup",
"alias": false,
"peer_metadata": null
} | ^4.0.0 | development |
@babel/preset-reactEnvironment{
"local_name": "@babel/preset-react",
"alias": false,
"peer_metadata": null
} | ^7.0.0 | development |
@rollup/plugin-babelEnvironment{
"local_name": "@rollup/plugin-babel",
"alias": false,
"peer_metadata": null
} | ^6.0.0 | development |
@rollup/plugin-node-resolveEnvironment{
"local_name": "@rollup/plugin-node-resolve",
"alias": false,
"peer_metadata": null
} | ^15.0.0 | development |
rollup-plugin-peer-deps-externalEnvironment{
"local_name": "rollup-plugin-peer-deps-external",
"alias": false,
"peer_metadata": null
} | ^2.2.4 | development |
vueEnvironment{
"local_name": "vue",
"alias": false,
"peer_metadata": {
"optional": true
}
} | >=3.0.0 | peer |
reactEnvironment{
"local_name": "react",
"alias": false,
"peer_metadata": {
"optional": true
}
} | >=17.0.0 | peer |
react-domEnvironment{
"local_name": "react-dom",
"alias": false,
"peer_metadata": {
"optional": true
}
} | >=17.0.0 | peer |
Source distribution
{
"shasum": "9c1259d730a6eed664a0c1e14d136c558de2f97f",
"tarball": "https://registry.npmjs.org/3d-whell-parallax-carousel/-/3d-whell-parallax-carousel-1.0.1.tgz",
"fileCount": 15,
"integrity": "sha512-9MstHWp9ThygmaSL0AmZgcMhHGL91m1V3Y+x5gMeXJa87Tz+I0wewP6Qy+Ksh6SGy0Mm+rvr5bHSP8Ej+oW0EQ==",
"signatures": [
{
"sig": "MEQCIGWRJASsq9Oiy1wWoVj9ZcBUfCtXLt2W+Q22AjFocw85AiATnzw/S8rQVpwlNRgoeYJW3jAbIrDmr3CtnABFPoVFCQ==",
"keyid": "SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"
}
],
"unpackedSize": 87226
}Shared repository data · GitHub
Observed since 20 Oct, 19:38 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package_version:f9fb2482afd2e2e602bc4ac9e0944465f28bad37de2fb6770c3bcb9d2b2c6590