<body class="bg-gray-100 p-8">
  <div class="max-w-4xl mx-auto">
    <h1 class="text-2xl font-bold mb-6">Carousel Infini Scroll Fluide</h1>
    <div class="carousel-container relative w-full border rounded-lg bg-white overflow-hidden">
      <div id="carousel-track" class="carousel-track flex will-change-transform select-none">
        <div class="carousel-item flex-shrink-0 ">
          <div class="card rounded-xl">
            <p>Post title de l'article en cours... Post 1</p>
            </div>
        </div>
        <div class="carousel-item flex-shrink-0 ">
          <div class="card rounded-xl">
          <p>Post 2</p>
            </div>
        </div>
        <div class="carousel-item flex-shrink-0 ">
          <div class="card rounded-xl">
          <p>Post 3</p>
            </div>
        </div>
        <div class="carousel-item flex-shrink-0">
          <div class="card rounded-xl">
          <p>Post 4</p>
            </div>
        </div>
        <div class="carousel-item flex-shrink-0">
          <div class="card rounded-xl">
          <p>Post 5</p>
            </div>
        </div>

      </div>
    </div>
  </div>


.carousel-container {
    overflow: hidden;
 }

  .carousel-track {
    display: flex;
  }

  .carousel-item {
    flex-shrink: 0;
    width: 5000px;
    height:200px; 
  }
.card {
  padding: 2rem;
  border: 1px solid red;
  height: 100%;
  margin-left: 1rem;
}

const track = document.getElementById("carousel-track");
    let visibleCount = 3;
    let slideWidth = 0;
    let position = 0;
    const speed = 0.15; // px/ms
    let animationId;
    let lastTimestamp = null;

    let totalItems = 0;
    let totalWidth = 0;

    function cloneItems() {
      const items = Array.from(track.children);
      const clones1 = items.map(item => item.cloneNode(true));
      const clones2 = items.map(item => item.cloneNode(true));
      clones1.forEach(clone => track.appendChild(clone));
      clones2.forEach(clone => track.appendChild(clone));
    }

    function getItemTotalWidth(item) {
      const style = getComputedStyle(item);
      const width = item.getBoundingClientRect().width;
      const marginRight = parseFloat(style.marginRight);
      return width + marginRight;
    }

    function updateVisibleCount() {
      const w = window.innerWidth;
      if (w < 640) visibleCount = 1;
      else if (w < 1024) visibleCount = 2;
      else visibleCount = 3;

      // On met à jour la largeur des items en % (JS obligatoire pour dynamique)
      const items = document.querySelectorAll(".carousel-item");
      items.forEach(item => {
        item.style.width = ${100 / visibleCount}%;
      });
    }

    function updateWidths() {
      const items = document.querySelectorAll(".carousel-item");
      slideWidth = getItemTotalWidth(items[0]);
      totalItems = items.length;
      totalWidth = totalItems * slideWidth;
    }

    function animate(timestamp) {
      if (!lastTimestamp) lastTimestamp = timestamp;
      const delta = timestamp - lastTimestamp;
      lastTimestamp = timestamp;

      position -= speed * delta;

      // Remise à zéro modulo largeur d'un set d'items (1/3 du total)
      if (position <= -totalWidth / 3) {
        position += totalWidth / 3;
      }

      track.style.transform = translateX(${position}px);
      animationId = requestAnimationFrame(animate);
    }

    function setup() {
      cloneItems();
      updateVisibleCount();
      updateWidths();

      position = 0;
      lastTimestamp = null;

      if (animationId) cancelAnimationFrame(animationId);
      animationId = requestAnimationFrame(animate);
    }

    window.addEventListener("load", setup);
    window.addEventListener("resize", () => {
      updateVisibleCount();
      updateWidths();
      position = 0;
    });



je ne souhaite pas avoir de largeur minimum sur les cards