diff --git a/.babelrc b/.babelrc
deleted file mode 100644
index 1320b9a..0000000
--- a/.babelrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "presets": ["@babel/preset-env"]
-}
diff --git a/.eslintrc.cjs b/.eslintrc.cjs
new file mode 100644
index 0000000..e178e9d
--- /dev/null
+++ b/.eslintrc.cjs
@@ -0,0 +1,23 @@
+module.exports = {
+ root: true,
+ parser: '@typescript-eslint/parser',
+ plugins: ['@typescript-eslint'],
+ extends: [
+ 'eslint:recommended',
+ 'plugin:@typescript-eslint/recommended',
+ ],
+ parserOptions: {
+ ecmaVersion: 2020,
+ sourceType: 'module',
+ },
+ env: {
+ browser: true,
+ es2020: true,
+ node: true,
+ },
+ rules: {
+ '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
+ '@typescript-eslint/no-explicit-any': 'warn',
+ },
+ ignorePatterns: ['dist/', 'dist-demo/', 'node_modules/', 'coverage/'],
+};
diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml
new file mode 100644
index 0000000..919100f
--- /dev/null
+++ b/.github/workflows/deploy-pages.yml
@@ -0,0 +1,39 @@
+name: Deploy to GitHub Pages
+
+on:
+ push:
+ branches: [master]
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+concurrency:
+ group: pages
+ cancel-in-progress: true
+
+jobs:
+ build-and-deploy:
+ runs-on: ubuntu-latest
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ steps:
+ - uses: actions/checkout@v4
+
+ - uses: actions/setup-node@v4
+ with:
+ node-version: 20
+ cache: npm
+
+ - run: npm ci
+ - run: npm run build:demo
+
+ - uses: actions/configure-pages@v5
+ - uses: actions/upload-pages-artifact@v3
+ with:
+ path: dist-demo
+
+ - id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index a56a7ef..1ecdec6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,40 @@
-node_modules
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+# build output — only CDN bundles are tracked
+/dist/*
+!/dist/js-cloudimage-carousel.min.js
+!/dist/js-cloudimage-carousel.min.js.map
+/dist-demo
+
+# testing
+/coverage
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# typescript
+*.tsbuildinfo
+
+# IDE
+.idea
+/.idea
+.vscode/
+
+# husky
+.husky/
+
+# claude
+.claude
+CLAUDE.md
diff --git a/.npmignore b/.npmignore
deleted file mode 100644
index 90bba8f..0000000
--- a/.npmignore
+++ /dev/null
@@ -1,7 +0,0 @@
-# .npmignore
-src
-examples
-build
-dist
-.babelrc
-.gitignore
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..a903283
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,83 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+## [1.0.2] - 2026-03-20
+
+### Fixed
+
+- **Type declarations path** — `package.json` types field now points to correct `dist/index.d.ts` (was pointing to non-existent `dist/types/`)
+- **UMD global** — `window.CloudImageCarousel` is now the class directly, not a namespace object (CDN `
+
```
-The carousel is exposed as a UMD module, so it works with:
+## Quick Start
-- Browser globals (`window.CloudImageCarousel`)
-- AMD modules
-- CommonJS/Node.js modules
+### JavaScript API
-## Basic Usage
+```js
+import { CloudImageCarousel } from 'js-cloudimage-carousel'
-```javascript
-const carousel = new CloudImageCarousel('#carousel', {
- // your options here
- images: ['path/to/image1.jpg', 'path/to/image2.jpg'],
+const carousel = new CloudImageCarousel('#my-carousel', {
+ images: ['photo1.jpg', 'photo2.jpg', 'photo3.jpg'],
+ theme: 'light',
+ showBullets: true,
+ transitionEffect: 'slide',
})
-// initialize carousel
carousel.init()
```
-## Available Options
+### HTML Data-Attributes
-### `autoplay` (boolean)
-
-- **Default**: `false`
-- **Description**: Enables automatic slideshow of images
-- **Example**:
-
-```javascript
-{
- autoplay: true
-}
-```
-
-### `autoplayInterval` (number)
-
-- **Default**: `3000` (3 seconds)
-- **Description**: Sets the time interval (in milliseconds) between slides when autoplay is enabled
-- **Example**:
-
-```javascript
-{
- autoplayInterval: 5000 // Changes slide every 5 seconds
-}
-```
-
-### `cycle` (boolean)
-
-- **Default**: `true`
-- **Description**: Determines if the carousel should loop back to the first image after reaching the last one
-- **Example**:
-
-```javascript
-{
- cycle: false // Stops at the last image
-}
+```html
+
+
+
```
-### `showFilenames` (boolean)
+## API Reference
-- **Default**: `false`
-- **Description**: Shows/hides the filename caption below each image. Filenames are automatically extracted from the image URL
-- **Example**:
+### Constructor
-```javascript
-{
- showFilenames: true // Displays image filenames
-}
+```ts
+new CloudImageCarousel(element: HTMLElement | string, config?: Partial)
```
-### `showThumbnails` (boolean)
-
-- **Default**: `true`
-- **Description**: Shows/hides the thumbnail navigation bar at the bottom of the carousel
-- **Example**:
-
-```javascript
-{
- showThumbnails: false // Hides thumbnail navigation
-}
+### Config
+
+| Option | Type | Default | Description |
+| ------------------ | --------------------------------------- | ---------- | ----------------------------------------------- |
+| `images` | `ImageSource[]` | `[]` | Array of image URLs or `{ src, alt }` objects |
+| `autoplay` | `boolean` | `false` | Enable automatic slide advancement |
+| `autoplayInterval` | `number` | `3000` | Autoplay interval in ms (min 100) |
+| `cycle` | `boolean` | `true` | Loop from last slide back to first |
+| `showFilenames` | `boolean` | `false` | Show filename overlay on each slide |
+| `showThumbnails` | `boolean` | `true` | Show thumbnail strip below the carousel |
+| `showBullets` | `boolean` | `false` | Show bullet indicators |
+| `showControls` | `boolean` | `true` | Show navigation controls (prev/next/fullscreen) |
+| `controlsPosition` | `'center' \| 'bottom'` | `'center'` | Position of navigation arrows |
+| `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
+| `transitionEffect` | `'slide' \| 'fade' \| 'zoom' \| 'flip'` | `'fade'` | Slide transition effect |
+| `zoomMin` | `number` | `1` | Minimum zoom level |
+| `zoomMax` | `number` | `4` | Maximum zoom level |
+| `zoomStep` | `number` | `0.3` | Zoom step increment |
+| `onSlideChange` | `(index: number) => void` | — | Callback fired after a slide change |
+| `onError` | `(src: string, index: number) => void` | — | Callback fired when an image fails to load |
+| `cloudimage` | `CloudimageConfig` | — | Cloudimage CDN config |
+
+### CloudimageConfig
+
+| Field | Type | Default | Description |
+| ------------- | -------- | --------------- | ---------------------------------------------- |
+| `token` | `string` | — | Cloudimage customer token (required) |
+| `apiVersion` | `string` | `'v7'` | API version |
+| `domain` | `string` | `'cloudimg.io'` | Custom domain |
+| `limitFactor` | `number` | `100` | Round widths to nearest N pixels |
+| `params` | `string` | — | Custom URL params (e.g. `'q=80&org_if_sml=1'`) |
+
+### Instance Methods
+
+```ts
+carousel.init(): void
+carousel.next(): void
+carousel.prev(): void
+carousel.goToSlide(index: number): void
+carousel.zoomIn(): void
+carousel.zoomOut(): void
+carousel.resetZoom(): void
+carousel.toggleFullscreen(): void
+carousel.startAutoplay(): void
+carousel.stopAutoplay(): void
+carousel.pauseAutoplay(): void
+carousel.resumeAutoplay(): void
+carousel.setTheme(theme: 'light' | 'dark'): void
+carousel.loadImages(sources: ImageSource[]): void
+carousel.destroy(): void
```
-### `showControls` (boolean)
+### Static Methods
-- **Default**: `true`
-- **Description**: Shows/hides the control buttons (previous/next navigation, zoom controls, fullscreen toggle)
-- **Example**:
-
-```javascript
-{
- showControls: false // Hides all control buttons
-}
+```ts
+CloudImageCarousel.autoInit(root?: HTMLElement | Document): CloudImageCarousel[]
```
-### `showBullets` (boolean)
-
-- **Default**: `false`
-- **Description**: Shows/hides bullet navigation indicators below the carousel
-- **Example**:
-
-```javascript
-{
- showBullets: true // Shows bullet navigation
+## React Usage
+
+```tsx
+import { CloudImageCarouselViewer, useCloudImageCarousel } from 'js-cloudimage-carousel/react'
+
+// Component
+function Gallery() {
+ return (
+ console.log('Slide:', index)}
+ />
+ )
}
-```
-
-### `transitionEffect` (string)
-
-- **Default**: `'fade'`
-- **Options**: `'fade'`, `'slide'`
-- **Description**: Sets the transition effect when changing slides
-- **Example**:
-```javascript
-{
- transitionEffect: 'fade' // Uses fade transition between slides
+// Hook
+function Gallery() {
+ const { containerRef, instance } = useCloudImageCarousel({
+ images: ['photo1.jpg', 'photo2.jpg'],
+ controlsPosition: 'bottom',
+ })
+
+ return (
+ <>
+
+
+ >
+ )
}
-```
-
-### `thumbnailFitMode` (string)
-
-- **Default**: `'crop-fit'`
-- **Options**: `'crop-fit'`, `'fit'`
-- **Description**: Controls how thumbnail images are fitted within their containers
-- **Example**:
-```javascript
-{
- thumbnailFitMode: 'fit' // Makes thumbnails fit within their container without cropping
+// Ref API
+function Gallery() {
+ const ref = useRef(null)
+
+ return (
+ <>
+
+
+
+
+ >
+ )
}
```
-### `thumbnailAlignment` (string)
+## Theming
-- **Default**: `'space-evenly'`
-- **Options**: `'left'`, `'center'`, `'right'`, `'space-evenly'`, `'space-between'`
-- **Description**: Controls the horizontal alignment of thumbnails in the thumbnail container
-- **Example**:
+All visuals are customizable via CSS variables:
-```javascript
-{
- thumbnailAlignment: 'space-between' // Distributes thumbnails with equal space between them
+```css
+.my-carousel .ci-carousel {
+ --ci-carousel-bg: #0f172a;
+ --ci-carousel-btn-bg: rgba(59, 130, 246, 0.85);
+ --ci-carousel-btn-color: #ffffff;
+ --ci-carousel-btn-hover-bg: rgba(59, 130, 246, 1);
+ --ci-carousel-bullet-active-bg: #3b82f6;
+ --ci-carousel-thumbnail-active-border: 0 0 0 2px #3b82f6;
+ --ci-carousel-thumbnails-bg: #0f172a;
}
```
-## Complete Example
-
-Here's an example showing all options with their default values:
-
-```html
-
-```
-
-```javascript
-const carousel = new CloudImageCarousel('#my-carousel', {
- autoplay: false,
- autoplayInterval: 3000,
- cycle: true,
- showFilenames: false,
- showThumbnails: true,
- showControls: true,
- showBullets: false,
- transitionEffect: 'fade',
- thumbnailFitMode: 'crop-fit',
- thumbnailAlignment: 'space-evenly',
- images: ['path/to/image1.jpg', 'path/to/image2.jpg', 'path/to/image3.jpg'],
+Set `theme: 'dark'` for the built-in dark theme.
+
+## Accessibility
+
+- All interactive elements are `