# Scroll Tilted Grid

> A two-column image gallery whose frames tilt, blur and dim at the viewport edges and settle into focus as they cross the center.

A two-column image gallery that reacts to scroll. Each frame tilts back in 3D, drifts sideways, blurs and dims near the top and bottom edges, then settles flat and sharp as it crosses the middle of the viewport. Scroll the demo to try it. Wheel scrolling is eased by default, and `loop` keeps adding image cycles as you reach the end.

<demo-scroll-tilted-grid>



</demo-scroll-tilted-grid>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/scroll-tilted-grid.json"
```

## Usage

```vue
<script setup lang="ts">
  import ScrollTiltedGrid from '~/components/ui/scroll-tilted-grid/ScrollTiltedGrid.vue';
  import type { ScrollTiltedGridImage } from '~/components/ui/scroll-tilted-grid/types';

  const images: ScrollTiltedGridImage[] = [
    {
      src: 'https://images.unsplash.com/photo-1511818966892-d7d671e672a2?auto=format&fit=crop&w=1200&q=85',
      alt: 'Curved concrete facade in soft daylight',
    },
    {
      src: 'https://images.unsplash.com/photo-1497366754035-f200968a6e72?auto=format&fit=crop&w=1200&q=85',
      alt: 'Sunlit modern interior with warm timber details',
    },
  ];
</script>

<template>
  <ScrollTiltedGrid :images="images" :max-tilt="62" :max-blur="7" />
</template>
```

The gallery tracks the window by default. To run it inside a scrolling panel, pass that element as `scroll-container`:

```vue
<script setup lang="ts">
  const panel = useTemplateRef<HTMLElement>('panel');
</script>

<template>
  <div ref="panel" class="h-160 overflow-y-auto">
    <ScrollTiltedGrid :images="images" :scroll-container="panel" />
  </div>
</template>
```

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        images
      </code>
    </td>
    
    <td>
      <code>
        readonly ScrollTiltedGridImage[]
      </code>
    </td>
    
    <td>
      required
    </td>
    
    <td>
      Images to render. Each item has a <code>
        src
      </code>
      
       and descriptive <code>
        alt
      </code>
      
       text.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        loop
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Appends more image cycles as the end of the gallery comes near.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        initial-cycles
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        2
      </code>
    </td>
    
    <td>
      Cycles rendered at first when looping is on.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max-cycles
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Most cycles the gallery grows to.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smooth-scroll
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      Eases wheel scrolling on the scroll target. Turn it off when the app already owns smooth scrolling.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aspect-ratio
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '4 / 5'
      </code>
    </td>
    
    <td>
      CSS aspect ratio of every frame.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        perspective
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1000
      </code>
    </td>
    
    <td>
      Perspective depth in pixels for every frame.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max-tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        62
      </code>
    </td>
    
    <td>
      Largest <code>
        rotateX
      </code>
      
       angle at the entry and exit edges.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max-blur
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        7
      </code>
    </td>
    
    <td>
      Largest blur in pixels away from the viewport focus point.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rounded
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '0.25rem'
      </code>
    </td>
    
    <td>
      CSS border radius of every frame.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        section-padding
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '18vh'
      </code>
    </td>
    
    <td>
      Top and bottom padding around the grid.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        scroll-container
      </code>
    </td>
    
    <td>
      <code>
        HTMLElement | null
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Scrolling element to track. Omit to track the window.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      Extra classes on the gallery section.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The gallery is a labelled `<section>`, and every image keeps its `alt` text.
- With `prefers-reduced-motion: reduce`, frames stay flat and sharp, and smooth wheel scrolling is turned off.
- Only wheel input is eased. Keyboard, touch and scrollbar scrolling stay native.

## Credits

- Ported from [componentry.fun](https://componentry.dev/docs/components/scroll-tilted-grid) by Harsh Jadhav.
