{"id":50306691,"url":"https://github.com/muratdemirci/anim8-grid","last_synced_at":"2026-05-28T17:01:18.166Z","repository":{"id":350660531,"uuid":"1202381072","full_name":"muratdemirci/anim8-grid","owner":"muratdemirci","description":"Animated responsive image grid. Zero dependencies. Framework-agnostic.","archived":false,"fork":false,"pushed_at":"2026-04-11T11:57:33.000Z","size":82,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-04-11T13:23:21.806Z","etag":null,"topics":["animation","css-grid","framework-agnostic","frontend","image-gallery","javascript-library","responsive","typescript","web-components","zero-dependency"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/muratdemirci.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-06T00:49:43.000Z","updated_at":"2026-04-11T11:57:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/muratdemirci/anim8-grid","commit_stats":null,"previous_names":["muratdemirci/anim8-grid"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/muratdemirci/anim8-grid","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muratdemirci%2Fanim8-grid","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muratdemirci%2Fanim8-grid/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muratdemirci%2Fanim8-grid/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muratdemirci%2Fanim8-grid/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/muratdemirci","download_url":"https://codeload.github.com/muratdemirci/anim8-grid/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/muratdemirci%2Fanim8-grid/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33617718,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-28T02:00:06.440Z","response_time":99,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["animation","css-grid","framework-agnostic","frontend","image-gallery","javascript-library","responsive","typescript","web-components","zero-dependency"],"created_at":"2026-05-28T17:01:15.661Z","updated_at":"2026-05-28T17:01:18.150Z","avatar_url":"https://github.com/muratdemirci.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# anim8-grid\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/i0TbGrx.png\" alt=\"anim8-grid\" width=\"540\"\u003e\n\u003c/p\u003e\n\n[![npm version](https://img.shields.io/npm/v/anim8-grid.svg)](https://www.npmjs.com/package/anim8-grid)\n[![npm downloads](https://img.shields.io/npm/dm/anim8-grid.svg)](https://www.npmjs.com/package/anim8-grid)\n[![bundle size](https://img.shields.io/bundlephobia/minzip/anim8-grid)](https://bundlephobia.com/package/anim8-grid)\n[![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](https://www.npmjs.com/package/anim8-grid)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue.svg)](https://www.typescriptlang.org/)\n[![license](https://img.shields.io/npm/l/anim8-grid.svg)](https://github.com/muratdemirci/anim8-grid/blob/main/LICENSE)\n\nAnimated responsive image grid. Zero dependencies. Framework-agnostic. Works everywhere.\n\n## Install\n\n```bash\nnpm install anim8-grid\n```\n\n## Usage\n\n```ts\nimport { createGrid } from 'anim8-grid'\n\nconst grid = createGrid(document.getElementById('grid')!, {\n  images: ['/photos/01.jpg', '/photos/02.jpg', '/photos/03.jpg', '/photos/04.jpg', '/photos/05.jpg', '/photos/06.jpg'],\n  gridRows: 3,\n  gridColumns: 5,\n  animationType: 'rotateLeft',\n  animationDuration: 600,\n  rotationInterval: 2000,\n})\n\ngrid.stop()\ngrid.start()\ngrid.update({ animationDuration: 300, maxItemsPerCycle: 10 })\ngrid.destroy()\n```\n\n### CDN / Script Tag\n\n```html\n\u003cscript src=\"https://unpkg.com/anim8-grid\"\u003e\u003c/script\u003e\n\u003cscript\u003e\n  const grid = anim8Grid.createGrid(document.getElementById('grid'), {\n    images: ['/photos/01.jpg', '/photos/02.jpg', '/photos/03.jpg'],\n  })\n\u003c/script\u003e\n```\n\n## Options\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `images` | `string[]` | **(required)** | Image URLs. Provide more than grid cells for rotation |\n| `gridRows` | `number` | `4` | Number of rows |\n| `gridColumns` | `number` | `10` | Number of columns |\n| `animationType` | `AnimationType` | `'random'` | Animation type (see below) |\n| `animationDuration` | `number` | `800` | Transition duration in ms |\n| `animationEasing` | `string` | `'linear'` | CSS easing function |\n| `rotationInterval` | `number` | `3000` | Time between cycles in ms (min 300) |\n| `itemsPerCycle` | `number \\| 'random'` | `'random'` | Cells to animate per cycle |\n| `maxItemsPerCycle` | `number` | `3` | Max cells when `itemsPerCycle` is `'random'` |\n| `autoplay` | `boolean` | `true` | Auto-start rotation |\n| `hoverTrigger` | `boolean` | `false` | Rotate on hover instead of timer |\n| `frozenIndices` | `number[]` | `[]` | Cell indices that never animate |\n| `preventClick` | `boolean` | `true` | Block clicks on grid items |\n| `responsive` | `Record\u003cnumber, Partial\u003cGridDimensions\u003e\u003e` | `{}` | Breakpoint overrides |\n| `fullscreen` | `boolean` | `false` | Fill entire viewport, auto-calculate grid |\n| `cellSize` | `number` | `120` | Target cell size in px (fullscreen mode) |\n\n## Methods\n\n| Method | Description |\n| --- | --- |\n| `start()` | Start or resume rotation |\n| `stop()` | Pause rotation |\n| `update(opts)` | Change options at runtime without recreating the grid |\n| `destroy()` | Remove grid, cleanup all listeners |\n\n### Runtime Updates\n\nChange animation speed, interval, items per cycle, animation type, or cell size without destroying the grid:\n\n```ts\nconst grid = createGrid(container, { images, fullscreen: true, cellSize: 120 })\n\n// These apply instantly — no rebuild\ngrid.update({ animationDuration: 300 })\ngrid.update({ rotationInterval: 800 })\ngrid.update({ maxItemsPerCycle: 15 })\ngrid.update({ animationType: 'rotateLeft' })\n\n// This rebuilds the grid in fullscreen mode\ngrid.update({ cellSize: 80 })\n```\n\n**Updatable options:** `animationType`, `animationDuration`, `animationEasing`, `rotationInterval`, `itemsPerCycle`, `maxItemsPerCycle`, `cellSize`\n\n## Animation Types\n\n17 built-in types:\n\n| 2D | 3D | Combo | Special |\n| --- | --- | --- | --- |\n| `fadeInOut` | `rotateLeft` | `rotateLeftScale` | `showHide` |\n| `slideLeft` | `rotateRight` | `rotateRightScale` | `random` |\n| `slideRight` | `rotateTop` | `rotateTopScale` | |\n| `slideTop` | `rotateBottom` | `rotateBottomScale` | |\n| `slideBottom` | `scale` | | |\n| | `rotate3d` | | |\n\n## Responsive\n\nBreakpoint-based grid dimensions using `ResizeObserver`:\n\n```ts\ncreateGrid(container, {\n  images,\n  gridRows: 4,\n  gridColumns: 8,\n  responsive: {\n    1024: { gridRows: 3, gridColumns: 6 },\n    768: { gridRows: 2, gridColumns: 4 },\n    480: { gridRows: 1, gridColumns: 2 },\n  },\n})\n```\n\n## Fullscreen Mode\n\nFill the entire viewport. Rows and columns auto-calculated from `window.innerWidth / innerHeight` and `cellSize`. Recalculates on resize.\n\n```ts\ncreateGrid(container, {\n  images,\n  fullscreen: true,\n  cellSize: 120,\n  animationType: 'random',\n  rotationInterval: 1500,\n  maxItemsPerCycle: 5,\n})\n```\n\n| Resolution | cellSize: 120 | cellSize: 80 |\n|---|---|---|\n| 1920x1080 (Full HD) | 16x9 = 144 cells | 24x14 = 336 cells |\n| 2560x1440 (2K) | 22x12 = 264 cells | 32x18 = 576 cells |\n| 3840x2160 (4K) | 32x18 = 576 cells | 48x27 = 1296 cells |\n| 1366x768 (laptop) | 12x7 = 84 cells | 18x10 = 180 cells |\n| 390x844 (iPhone) | 4x8 = 32 cells | 5x11 = 55 cells |\n| 768x1024 (iPad) | 7x9 = 63 cells | 10x13 = 130 cells |\n\nContainer gets `position: fixed; width: 100vw; height: 100vh` — layer content on top with higher `z-index`.\n\n## Framework Examples\n\n### React\n\n```tsx\nimport { createGrid, type GridInstance, type UpdatableOptions } from 'anim8-grid'\nimport { useRef, useEffect, useCallback } from 'react'\n\nfunction Anim8Grid({ images, ...options }) {\n  const ref = useRef(null)\n\n  useEffect(() =\u003e {\n    const grid = createGrid(ref.current, { images, ...options })\n    return () =\u003e grid.destroy()\n  }, [])\n\n  return \u003cdiv ref={ref} /\u003e\n}\n\n// With runtime updates via hook\nfunction useAnim8Grid() {\n  const gridRef = useRef\u003cGridInstance | null\u003e(null)\n  const containerRef = useRef\u003cHTMLDivElement\u003e(null)\n\n  const init = useCallback((opts) =\u003e {\n    gridRef.current?.destroy()\n    gridRef.current = createGrid(containerRef.current!, opts)\n  }, [])\n\n  const update = useCallback((opts: UpdatableOptions) =\u003e {\n    gridRef.current?.update(opts)\n  }, [])\n\n  return { containerRef, init, update }\n}\n```\n\n### Vue\n\n```vue\n\u003cscript setup lang=\"ts\"\u003e\nimport { ref, onMounted, onBeforeUnmount } from 'vue'\nimport { createGrid, type GridInstance, type UpdatableOptions } from 'anim8-grid'\n\nconst props = defineProps\u003c{ images: string[], fullscreen?: boolean, cellSize?: number }\u003e()\nconst containerRef = ref\u003cHTMLElement | null\u003e(null)\nlet grid: GridInstance | null = null\n\nfunction update(opts: UpdatableOptions) { grid?.update(opts) }\n\nonMounted(() =\u003e {\n  grid = createGrid(containerRef.value!, { images: props.images, fullscreen: props.fullscreen, cellSize: props.cellSize })\n})\nonBeforeUnmount(() =\u003e { grid?.destroy() })\n\ndefineExpose({ update })\n\u003c/script\u003e\n\n\u003ctemplate\u003e\u003cdiv ref=\"containerRef\" /\u003e\u003c/template\u003e\n```\n\n### Angular\n\n```ts\n@Component({ selector: 'app-grid', template: '\u003cdiv #container\u003e\u003c/div\u003e', standalone: true })\nexport class Anim8GridComponent implements AfterViewInit, OnDestroy {\n  @ViewChild('container', { static: true }) ref!: ElementRef\n  @Input() images: string[] = []\n  @Input() fullscreen = false\n  @Input() cellSize = 120\n  private grid: GridInstance | null = null\n\n  ngAfterViewInit() {\n    this.grid = createGrid(this.ref.nativeElement, {\n      images: this.images, fullscreen: this.fullscreen, cellSize: this.cellSize\n    })\n  }\n\n  update(opts: UpdatableOptions) { this.grid?.update(opts) }\n  ngOnDestroy() { this.grid?.destroy() }\n}\n```\n\n### Astro\n\n```astro\n\u003cdiv id=\"grid\"\u003e\u003c/div\u003e\n\u003cscript\u003e\n  import { createGrid } from 'anim8-grid'\n  createGrid(document.getElementById('grid')!, {\n    images: Array.from({ length: 54 }, (_, i) =\u003e `/img/${i + 1}.jpg`),\n    fullscreen: true,\n    cellSize: 120,\n  })\n\u003c/script\u003e\n```\n\nFull working examples: [`examples/`](./examples/)\n\n## Demos\n\nRun `npx serve .` from the project root and open `/demo/`. 8 interactive demos included:\n\n| Demo | Description |\n|---|---|\n| [**Basic**](demo/basic.html) | Responsive grid with random animations and breakpoints |\n| [**Animations**](demo/animations.html) | All 15 animation types running side by side |\n| [**Hover**](demo/hover.html) | No auto-rotation — cells animate on mouse hover |\n| [**Fullscreen**](demo/fullscreen.html) | Viewport-filling grid with live sliders for cell size, speed, interval, items |\n| [**Hero**](demo/hero.html) | Fullscreen grid as a page background with gradient overlay and content on top |\n| [**Frozen**](demo/frozen.html) | Pin specific cells with `frozenIndices` while the rest rotate |\n| [**Speed**](demo/speed.html) | Slow / balanced / chaotic — same grid at 3 different speed configs |\n| [**Playground**](demo/playground.html) | Full control panel — tweak every parameter live with real-time code preview |\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuratdemirci%2Fanim8-grid","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmuratdemirci%2Fanim8-grid","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmuratdemirci%2Fanim8-grid/lists"}