Skip to content

Instantly share code, notes, and snippets.

@pbnkp
Created January 24, 2024 05:54
Show Gist options
  • Save pbnkp/5d42a827e49be3cc06d21ebe86a20c8d to your computer and use it in GitHub Desktop.
Save pbnkp/5d42a827e49be3cc06d21ebe86a20c8d to your computer and use it in GitHub Desktop.

Revisions

  1. pbnkp created this gist Jan 24, 2024.
    1 change: 1 addition & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    <div id="app"></div>
    7 changes: 7 additions & 0 deletions infinite-marquee-effect-broken-down.markdown
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    Infinite Marquee Effect Broken Down
    -----------------------------------


    A [Pen](https://codepen.io/jh3y/pen/LYaLBVX) by [Jhey](https://codepen.io/jh3y) on [CodePen](https://codepen.io).

    [License](https://codepen.io/license/pen/LYaLBVX).
    86 changes: 86 additions & 0 deletions script.babel
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,86 @@
    import React from 'https://cdn.skypack.dev/react'
    import { render } from 'https://cdn.skypack.dev/react-dom'
    import tweakpane from 'https://cdn.skypack.dev/tweakpane'
    import { useTweaks } from 'https://cdn.skypack.dev/use-tweaks'

    const ROOT_NODE = document.querySelector('#app')

    const App = () => {
    const { speed, diff, items, pad, direction, translate, spill, state, reverse, scale, inset, outset } =
    useTweaks({
    speed: 10,
    spill: false,
    scale: { value: 1, min: 0.1, max: 2, step: 0.1 },
    items: { value: 10, min: 1, max: 20, step: 1 },
    state: {
    value: 'running',
    options: ['running', 'paused'],
    },
    translate: {
    value: 'items',
    options: ['track', 'items'],
    },
    direction: {
    value: 'horizontal',
    options: ['horizontal', 'vertical'],
    },
    pad: { value: false, name: 'Pad out' },
    diff: false,
    reverse: false,
    inset: { value: 0, min: -10, max: 10, step: 0.1 },
    outset: { value: 0, min: -10, max: 10, step: 0.1 },
    })

    const renderStamp = Date.now()
    return (
    <div
    className="container"
    data-direction={direction}
    data-pad={pad}
    data-pad-diff={diff}
    data-translate={translate}
    data-play-state={state}
    data-spill={spill}
    data-reverse={reverse}
    style={{ '--speed': speed, '--count': items, '--scale': scale, '--inset': inset, '--outset': outset }}
    >
    <ul>
    {pad && translate === 'track'
    ? new Array(items).fill(0).map((item, index) => {
    return (
    <li
    aria-hidden="true"
    className="pad pad--negative"
    key={`pad-negative-${renderStamp}--${index}`}
    >
    {index}
    </li>
    )
    })
    : null}
    {new Array(items).fill(0).map((item, index) => {
    return (
    <li key={`index-${renderStamp}--${index}`} style={{ '--index': index }}>
    {index}
    </li>
    )
    })}
    {pad && translate === 'track'
    ? new Array(items).fill(0).map((item, index) => {
    return (
    <li
    aria-hidden="true"
    className="pad pad--positive"
    key={`pad-positive-${renderStamp}--${index}`}
    >
    {index}
    </li>
    )
    })
    : null}
    </ul>
    </div>
    )
    }

    render(<App />, ROOT_NODE)
    192 changes: 192 additions & 0 deletions style.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,192 @@
    @import "normalize.css";

    *,
    *:after,
    *:before {
    box-sizing: border-box;
    }

    body {
    display: grid;
    place-items: center;
    min-height: 100vh;
    font-family: monospace , sans-serif, system-ui;
    overflow: hidden;
    }

    body::before {
    --line: hsl(0 0% 5% / 0.25);
    --size: 60px;
    content: "";
    height: 100vh;
    width: 100vw;
    position: fixed;
    background:
    linear-gradient(90deg, var(--line) 1px, transparent 1px var(--size)) 0 -5vmin / var(--size) var(--size),
    linear-gradient(var(--line) 1px, transparent 1px var(--size)) 0 -5vmin / var(--size) var(--size);
    mask: linear-gradient(-15deg, transparent 60%, white);
    top: 0;
    z-index: -1;
    }

    .container {
    width: 50vmin;
    outline: 1px solid black;
    padding: 1rem;
    border-radius: 6px;
    container-type: size;
    scale: var(--scale);
    }

    .container[data-spill=true]::after {
    --padding-x: 1rem;
    --padding-y: 1rem;
    content: "";
    position: fixed;
    top: 50%;
    left: 50%;
    background: hsl(10 80% 0% / 0.25);
    width: calc(var(--scale) * 10000vw);
    height: calc(var(--scale) * 10000vh);
    pointer-events: none;
    translate: -50% -50%;
    mask:
    linear-gradient(white, white) 50% 50% / 100% 100% no-repeat,
    linear-gradient(white, white) 50% 50% / calc(100cqi + (var(--padding-x) * 2)) calc(100cqh + (var(--padding-y) * 2)) no-repeat;
    mask-composite: exclude;
    }

    .container:not([data-spill=true]) {
    resize: both;
    overflow: hidden;
    }

    [data-direction=horizontal] {
    aspect-ratio: 16 / 9;
    min-height: 180px;
    min-width: 300px;
    }

    [data-direction=vertical] {
    aspect-ratio: 9 / 16;
    min-width: 180px;
    min-height: 300px;
    }

    ul {
    display: flex;
    gap: 1rem;
    padding: 0;
    margin: 0;
    list-style-type: none;
    }

    [data-reverse=true] * {
    animation-direction: reverse !important;
    }

    [data-translate=track][data-direction=horizontal] ul {
    --destination-x: -100%;
    animation: track-translate calc(var(--speed) * 1s) infinite linear;
    }

    [data-translate=track][data-direction=vertical] ul {
    --destination-y: -100%;
    animation: track-translate calc(var(--speed) * 1s) infinite linear;
    }

    [data-translate=track][data-direction=horizontal][data-pad=true] ul {
    --destination-x: calc((100% / -3) * 2);
    translate: calc(100% / -3) 0;
    }

    [data-translate=track][data-direction=vertical][data-pad=true] ul {
    --destination-y: calc((100% / -3) * 2);
    translate: 0 calc(100% / -3);
    }


    [data-pad-diff=true] .pad {
    background: hsl(0 0% 10%);
    color: hsl(0 0% 98%);
    }

    @keyframes track-translate {
    to {
    translate: var(--destination-x, 0) var(--destination-y, 0);
    }
    }

    [data-direction=horizontal] ul {
    height: 100%;
    width: fit-content;
    align-items: center;
    }

    [data-direction=vertical] ul {
    width: 100%;
    height: fit-content;
    justify-items: center;
    flex-direction: column;
    }

    li {
    height: 80%;
    aspect-ratio: 4 / 3;
    background: hsl(0 0% 90%);
    border-radius: 6px;
    font-size: clamp(2rem, 4vw + 1rem, 8rem);
    display: grid;
    place-items: center;
    border: 1px solid hsl(0 0% 50%);
    }

    [data-play-state=running] :is(ul, li) {
    animation-play-state: running !important;
    }
    [data-play-state=paused] :is(ul, li) {
    animation-play-state: paused !important;
    }


    /* The animation stuff */
    @media(prefers-reduced-motion: no-preference) {
    [data-translate=items] ul {
    gap: 0;
    }
    [data-translate=items][data-direction=horizontal].container {
    padding-inline: 0;
    }
    [data-translate=items][data-direction=vertical].container {
    padding-block: 0;
    }
    [data-translate=items][data-spill=true][data-direction=horizontal].container::after {
    --padding-x: 0rem;
    }
    [data-translate=items][data-direction=vertical][data-spill=true].container::after {
    --padding-y: 0rem;
    }
    [data-translate=items] li {
    --duration: calc(var(--speed) * 1s);
    --delay: calc((var(--duration) / var(--count)) * (var(--index, 0) - (var(--count) * 0.5)));
    animation: slide var(--duration) calc(var(--delay) - (var(--count) * 0.5s)) infinite linear paused;
    translate: var(--origin-x) var(--origin-y);
    }
    [data-translate=items][data-direction=horizontal] li {
    --origin-x: calc(((var(--count) - var(--index)) + var(--inset, 0)) * 100%);
    --origin-y: 0;
    --destination-x: calc(calc((var(--index) + 1 + var(--outset, 0)) * -100%));
    --destination-y: 0;
    }
    [data-translate=items][data-direction=vertical] li {
    --origin-x: 0;
    --origin-y: calc(((var(--count) - var(--index)) + var(--inset, 0)) * 100%);
    --destination-x: 0;
    --destination-y: calc(calc((var(--index) + 1 + var(--outset, 0)) * -100%));
    }
    @keyframes slide {
    100% {
    translate: var(--destination-x) var(--destination-y);
    }
    }
    }