diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 2001e7d5e..f305f6ed8 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "hyperframes", - "description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", + "description": "HyperFrames by HeyGen. Write HTML, render video. Compositions, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", "version": "0.1.0", "author": { "name": "HeyGen", diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index c8e705b7b..c0d973c80 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "hyperframes", "version": "0.1.0", - "description": "Write HTML, render video. Compositions, GSAP animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", + "description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", "author": { "name": "HeyGen", "email": "hyperframes@heygen.com", @@ -14,7 +14,12 @@ "hyperframes", "video", "html", + "tailwind", "gsap", + "lottie", + "three", + "waapi", + "animejs", "animation", "composition", "rendering", @@ -26,7 +31,7 @@ "interface": { "displayName": "HyperFrames by HeyGen", "shortDescription": "Write HTML, render video", - "longDescription": "Build videos from HTML with HyperFrames. Author compositions with HTML + CSS + GSAP, use the CLI for init/preview/render/transcribe/tts, install reusable registry blocks and components, follow the GSAP animation reference, and turn any website into a video with the 7-step capture-to-video pipeline.", + "longDescription": "Build videos from HTML with HyperFrames. Author compositions with HTML, CSS, Tailwind v4 browser-runtime styles, GSAP, Anime.js, Lottie, Three.js, and WAAPI adapter patterns, use the CLI for the dev loop (init/preview/render), preprocess assets (tts/transcribe/remove-background) for compositions, install reusable registry blocks and components, and turn any website into a video with the 7-step capture-to-video pipeline.", "developerName": "HeyGen", "category": "Design", "capabilities": ["Read", "Write"], diff --git a/.cursor-plugin/plugin.json b/.cursor-plugin/plugin.json index fe4be1d35..8d0d060d3 100644 --- a/.cursor-plugin/plugin.json +++ b/.cursor-plugin/plugin.json @@ -3,7 +3,7 @@ "name": "hyperframes", "displayName": "HyperFrames by HeyGen", "version": "0.1.0", - "description": "Write HTML, render video. Compositions, GSAP animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", + "description": "Write HTML, render video. Compositions, Tailwind v4 styles, GSAP and runtime adapter animations, captions, voiceovers, audio-reactive visuals, and website-to-video capture for HyperFrames.", "author": { "name": "HeyGen", "email": "hyperframes@heygen.com" @@ -18,7 +18,12 @@ "hyperframes", "video", "html", + "tailwind", "gsap", + "lottie", + "three", + "waapi", + "animejs", "animation", "composition", "rendering", diff --git a/.github/workflows/catalog-previews.yml b/.github/workflows/catalog-previews.yml index 7597e6c08..adcfd102b 100644 --- a/.github/workflows/catalog-previews.yml +++ b/.github/workflows/catalog-previews.yml @@ -7,6 +7,7 @@ on: - "registry/blocks/**" - "registry/components/**" - "scripts/generate-catalog-previews.ts" + - ".github/workflows/catalog-previews.yml" concurrency: group: catalog-previews-${{ github.ref }} @@ -18,13 +19,13 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 @@ -33,18 +34,15 @@ jobs: - run: bun run build # Chrome headless shell for rendering - - uses: browser-actions/setup-chrome@v1 + - uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1 with: chrome-version: stable - # FFmpeg for video encoding - - uses: FedericoCarboni/setup-ffmpeg@v3 - - name: Render changed block/component previews run: | # Find which blocks/components changed in this PR BASE_SHA=${{ github.event.pull_request.base.sha }} - CHANGED_ITEMS=$(git diff --name-only "$BASE_SHA"...HEAD -- registry/blocks/ registry/components/ \ + CHANGED_ITEMS=$(git diff --name-only --diff-filter=ACMR "$BASE_SHA"...HEAD -- registry/blocks/ registry/components/ \ | grep -E '^registry/(blocks|components)/' \ | sed 's|^registry/[^/]*/\([^/]*\)/.*|\1|' \ | sort -u) @@ -72,7 +70,7 @@ jobs: - name: Upload preview artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: catalog-previews path: docs/images/catalog/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38b8c2837..f912bbc1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,10 +27,10 @@ jobs: # Force git-based change detection instead of the pull_request REST API. # The API path can fail the whole workflow on transient listFiles # timeouts before any real CI work starts. - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 id: filter with: token: "" @@ -51,11 +51,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -68,11 +68,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -83,11 +83,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -100,11 +100,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -118,11 +118,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -136,11 +136,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -153,11 +153,11 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 10 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 - run: bun install --frozen-lockfile @@ -217,13 +217,110 @@ jobs: echo "PASS: global install smoke test succeeded" + cli-smoke-required: + name: "CLI smoke (required)" + needs: changes + if: needs.changes.outputs.code == 'true' + runs-on: ubuntu-latest + timeout-minutes: 25 + steps: + - uses: actions/checkout@v4 + with: + lfs: true + - uses: oven-sh/setup-bun@v2 + - uses: actions/setup-node@v4 + with: + node-version: 22 + - name: Install FFmpeg + run: | + sudo apt-get update + sudo apt-get install -y ffmpeg + - name: Install dependencies + run: bun install --frozen-lockfile + - name: Build monorepo + run: bun run build + + - name: Create smoke input video + run: | + set -euo pipefail + ffmpeg -hide_banner -loglevel error \ + -f lavfi -i testsrc2=size=640x360:rate=30 \ + -f lavfi -i sine=frequency=880:sample_rate=48000 \ + -t 3 \ + -c:v libx264 \ + -pix_fmt yuv420p \ + -c:a aac \ + -shortest \ + -y /tmp/hf-cli-input.mp4 + test -s /tmp/hf-cli-input.mp4 + + - name: Smoke-test CLI from monorepo source + run: | + set -euo pipefail + rm -rf /tmp/hf-cli-inside + + bun run --filter @hyperframes/cli dev -- init /tmp/hf-cli-inside \ + --example warm-grain \ + --video /tmp/hf-cli-input.mp4 \ + --skip-transcribe \ + --non-interactive \ + --skip-skills + + bun run --filter @hyperframes/cli dev -- lint /tmp/hf-cli-inside + bun run --filter @hyperframes/cli dev -- validate /tmp/hf-cli-inside --timeout 3000 + bun run --filter @hyperframes/cli dev -- render /tmp/hf-cli-inside \ + --quality standard \ + --workers auto \ + --strict \ + --output /tmp/hf-cli-inside/renders/inside.mp4 + + test -s /tmp/hf-cli-inside/renders/inside.mp4 + + - name: Pack CLI tarball + run: | + set -euo pipefail + mkdir -p /tmp/hf-cli-pack + cd packages/cli + PACKED_TARBALL="$(npm pack --pack-destination /tmp/hf-cli-pack | tail -n 1)" + test -n "$PACKED_TARBALL" + test -f "/tmp/hf-cli-pack/$PACKED_TARBALL" + echo "HF_CLI_TARBALL=/tmp/hf-cli-pack/$PACKED_TARBALL" >> "$GITHUB_ENV" + + - name: Install packed CLI outside monorepo + run: | + set -euo pipefail + npm install -g --prefix /tmp/hf-cli-global "$HF_CLI_TARBALL" + + - name: Smoke-test packed CLI outside monorepo + run: | + set -euo pipefail + export PATH="/tmp/hf-cli-global/bin:$PATH" + rm -rf /tmp/hf-cli-outside + + hyperframes init /tmp/hf-cli-outside \ + --example warm-grain \ + --video /tmp/hf-cli-input.mp4 \ + --skip-transcribe \ + --non-interactive \ + --skip-skills + + hyperframes lint /tmp/hf-cli-outside + hyperframes validate /tmp/hf-cli-outside --timeout 3000 + hyperframes render /tmp/hf-cli-outside \ + --quality standard \ + --workers auto \ + --strict \ + --output /tmp/hf-cli-outside/renders/outside.mp4 + + test -s /tmp/hf-cli-outside/renders/outside.mp4 + semantic-pr-title: name: Semantic PR title if: github.event_name == 'pull_request' runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: amannn/action-semantic-pull-request@v5 + - uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cb44450ef..9aa60fa71 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -26,9 +26,9 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 5 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 diff --git a/.github/workflows/player-perf.yml b/.github/workflows/player-perf.yml index c22dbe6eb..c146665ee 100644 --- a/.github/workflows/player-perf.yml +++ b/.github/workflows/player-perf.yml @@ -19,10 +19,10 @@ jobs: steps: # Force git-based change detection instead of the pull_request REST API. # The API path can fail the perf workflow on transient listFiles timeouts. - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 id: filter with: token: "" @@ -60,11 +60,11 @@ jobs: scenarios: parity runs: "3" steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - - uses: oven-sh/setup-bun@v2 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 @@ -76,7 +76,7 @@ jobs: - name: Set up Chrome (headless shell) id: setup-chrome - uses: browser-actions/setup-chrome@v1 + uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1 with: chrome-version: stable @@ -104,7 +104,7 @@ jobs: - name: Upload perf results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: player-perf-${{ matrix.shard }} path: packages/player/tests/perf/results/ diff --git a/.github/workflows/preview-regression.yml b/.github/workflows/preview-regression.yml new file mode 100644 index 000000000..748b4f2ce --- /dev/null +++ b/.github/workflows/preview-regression.yml @@ -0,0 +1,137 @@ +name: preview-regression + +on: + pull_request: + push: + branches: + - main + +concurrency: + group: preview-regression-${{ github.ref }} + cancel-in-progress: true + +jobs: + changes: + name: Detect changes + runs-on: ubuntu-latest + timeout-minutes: 2 + outputs: + preview: ${{ steps.filter.outputs.preview }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + fetch-depth: 0 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 + id: filter + with: + token: "" + filters: | + preview: + - "packages/core/**" + - "packages/player/**" + - "packages/studio/**" + - "packages/cli/**" + - "packages/producer/src/parity-harness.ts" + - "packages/producer/src/parity-fixtures.ts" + - "packages/producer/tests/parity/**" + - "package.json" + - "bun.lock" + - ".github/workflows/preview-regression.yml" + + preview-parity: + name: Preview parity + needs: changes + if: needs.changes.outputs.preview == 'true' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 + with: + node-version: 22 + + - run: bun install --frozen-lockfile + + - name: Run Studio preview routing regression + run: | + bun run --cwd packages/studio test -- vite.thumbnail.test.ts src/utils/projectRouting.test.ts src/utils/frameCapture.test.ts + bun run --cwd packages/core test -- src/studio-api/routes/thumbnail.test.ts + + - name: Build preview runtime + run: bun run --cwd packages/core build:hyperframes-runtime + + - name: Prepare parity fixtures + run: bun run --cwd packages/producer parity:fixtures:ci + + - name: Install ffmpeg + uses: FedericoCarboni/setup-ffmpeg@36c6454b5a2348e7794ba2d82a21506605921e3d # v3 + + - name: Set up Chrome + id: setup-chrome + uses: browser-actions/setup-chrome@c785b87e244131f27c9f19c1a33e2ead956ab7ce # v1 + with: + chrome-version: stable + + - name: Start parity fixture server + run: | + cd packages/producer/tests/parity/fixtures + python3 -m http.server 4173 --bind 127.0.0.1 > /tmp/preview-parity-http.log 2>&1 & + echo "$!" > /tmp/preview-parity-http.pid + for _ in $(seq 1 30); do + if curl -fsS http://127.0.0.1:4173/minimal-wysiwyg.html >/dev/null; then + exit 0 + fi + sleep 1 + done + cat /tmp/preview-parity-http.log + exit 1 + + - name: Run preview parity check + working-directory: packages/producer + env: + PUPPETEER_EXECUTABLE_PATH: ${{ steps.setup-chrome.outputs.chrome-path }} + run: bun run parity:check:ci + + - name: Upload parity artifacts + if: failure() + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: preview-parity-artifacts + path: packages/producer/.debug/parity-harness-ci/ + if-no-files-found: ignore + retention-days: 30 + + preview-regression: + runs-on: ubuntu-latest + needs: [changes, preview-parity] + if: always() + steps: + - name: Check results + env: + PREVIEW_FILTER_RESULT: ${{ needs.changes.outputs.preview }} + PREVIEW_PARITY_RESULT: ${{ needs.preview-parity.result }} + run: | + { + echo "## Preview regression gate" + echo "" + echo "- paths-filter \`preview\` matched: \`${PREVIEW_FILTER_RESULT}\`" + echo "- preview-parity result: \`${PREVIEW_PARITY_RESULT}\`" + echo "" + } >> "$GITHUB_STEP_SUMMARY" + + if [ "${PREVIEW_FILTER_RESULT}" != "true" ]; then + echo "::notice title=Preview regression::SKIPPED — no preview/runtime changes. Auto-pass." + echo "**Status:** SKIPPED (no preview/runtime changes — auto-pass)" >> "$GITHUB_STEP_SUMMARY" + exit 0 + fi + + if [ "${PREVIEW_PARITY_RESULT}" != "success" ]; then + echo "**Status:** FAILED" >> "$GITHUB_STEP_SUMMARY" + echo "Preview parity check failed" + exit 1 + fi + + echo "**Status:** PASSED" >> "$GITHUB_STEP_SUMMARY" diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 08adf2320..c26a45512 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -30,7 +30,7 @@ jobs: (github.event.pull_request.merged == true && startsWith(github.event.pull_request.head.ref, 'release/v')) steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 # On manual dispatch, check out the existing tag so we publish the @@ -78,8 +78,8 @@ jobs: run: | git tag "v${{ steps.version.outputs.version }}" git push origin "v${{ steps.version.outputs.version }}" - - uses: oven-sh/setup-bun@v2 - - uses: actions/setup-node@v4 + - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 24 registry-url: "https://registry.npmjs.org" diff --git a/.github/workflows/regression.yml b/.github/workflows/regression.yml index 5d52bd702..c887a752e 100644 --- a/.github/workflows/regression.yml +++ b/.github/workflows/regression.yml @@ -17,10 +17,10 @@ jobs: # Force git-based change detection instead of the pull_request REST API. # The API path can fail the whole workflow on transient listFiles # timeouts before any regression shard even starts. - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 id: filter with: token: "" @@ -62,7 +62,7 @@ jobs: args: "overlay-montage-prod" steps: - name: Checkout (with LFS) - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: lfs: true @@ -81,10 +81,10 @@ jobs: done - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Build test Docker image (cached) - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 with: context: . file: Dockerfile.test @@ -106,7 +106,7 @@ jobs: - name: Upload failure artifacts if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: regression-failures-${{ matrix.shard }} path: packages/producer/tests/*/failures/ diff --git a/.github/workflows/windows-render.yml b/.github/workflows/windows-render.yml index feeeb7925..0a7db07d6 100644 --- a/.github/workflows/windows-render.yml +++ b/.github/workflows/windows-render.yml @@ -39,10 +39,10 @@ jobs: # Force git-based change detection instead of the pull_request REST API. # The API path can fail the workflow on transient listFiles timeouts # before the Windows render jobs even start. - - uses: actions/checkout@v4 + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 - - uses: dorny/paths-filter@v4 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4 id: filter with: token: "" @@ -63,7 +63,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ github.event.inputs.ref }} lfs: true @@ -134,10 +134,10 @@ jobs: } - name: Install Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - name: Install Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 @@ -201,12 +201,121 @@ jobs: Write-Host "canary.mp4 ok: ${width}x${height} @ $fps, ${duration}s" + - name: Scaffold issue #574 reused-video regression + shell: pwsh + run: | + $ErrorActionPreference = 'Stop' + + $project = "$env:RUNNER_TEMP\issue-574-reused-video" + New-Item -ItemType Directory -Force -Path $project | Out-Null + cd $project + + ffmpeg -y ` + -f lavfi -i "testsrc2=size=1920x1080:rate=30:duration=12" ` + -f lavfi -i "sine=frequency=880:sample_rate=48000:duration=12" ` + -c:v libx264 ` + -pix_fmt yuv420p ` + -r 30 ` + -g 250 ` + -keyint_min 250 ` + -c:a aac ` + -shortest ` + 1.mp4 + + @' + + + + + Issue 574 reused video regression + + + +
+ + + +
+ + + + '@ | Set-Content -Path index.html -Encoding utf8 + + - name: Render issue #574 reused-video regression + shell: pwsh + env: + PRODUCER_PLAYER_READY_TIMEOUT_MS: "15000" + run: | + cd "$env:RUNNER_TEMP\issue-574-reused-video" + node "$env:GITHUB_WORKSPACE\packages\cli\dist\cli.js" render ` + --fps 30 ` + --quality standard ` + --workers 1 ` + --output renders\issue-574.mp4 + + - name: Verify issue #574 rendered MP4 + shell: pwsh + run: | + $mp4 = "$env:RUNNER_TEMP\issue-574-reused-video\renders\issue-574.mp4" + if (-not (Test-Path $mp4)) { throw "issue-574.mp4 not produced" } + + $probe = ffprobe -v error -select_streams v:0 ` + -show_entries stream=width,height,r_frame_rate -show_entries format=duration ` + -of default=noprint_wrappers=1 $mp4 + Write-Host $probe + + $width = ($probe | Select-String '^width=(.+)$').Matches.Groups[1].Value + $height = ($probe | Select-String '^height=(.+)$').Matches.Groups[1].Value + $fps = ($probe | Select-String '^r_frame_rate=(.+)$').Matches.Groups[1].Value + $duration = [double]($probe | Select-String '^duration=(.+)$').Matches.Groups[1].Value + + if ([int]$width -ne 1920) { throw "expected 1920 width, got $width" } + if ([int]$height -ne 1080) { throw "expected 1080 height, got $height" } + if ($fps -ne "30/1") { throw "expected 30fps, got $fps" } + if ($duration -lt 11.5 -or $duration -gt 12.5) { throw "expected ~12s duration, got $duration" } + + Write-Host "issue-574.mp4 ok: ${width}x${height} @ $fps, ${duration}s" + - name: Upload rendered MP4 artifact if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: windows-render-${{ github.run_id }} - path: ${{ runner.temp }}/windows-canary/canary/renders/canary.mp4 + path: | + ${{ runner.temp }}/windows-canary/canary/renders/canary.mp4 + ${{ runner.temp }}/issue-574-reused-video/renders/issue-574.mp4 if-no-files-found: error retention-days: 7 @@ -226,7 +335,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: ref: ${{ github.event.inputs.ref }} lfs: true @@ -242,10 +351,10 @@ jobs: uses: ./.github/actions/install-ffmpeg-windows - name: Install Bun - uses: oven-sh/setup-bun@v2 + uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 - name: Install Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22 diff --git a/.gitignore b/.gitignore index 55b6babf0..24a7d2c79 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ coverage/ # Producer regression test failures (generated debugging artifacts) packages/producer/tests/*/failures/ +packages/producer/tests/parity/fixtures/hyperframe.runtime.iife.js # Player perf test results (generated each run, attached as CI artifact) packages/player/tests/perf/results/ diff --git a/ADOPTERS.md b/ADOPTERS.md new file mode 100644 index 000000000..04064559a --- /dev/null +++ b/ADOPTERS.md @@ -0,0 +1,25 @@ +# Adopters + +This page lists organizations using HyperFrames in production or actively evaluating it. If your team is shipping with HyperFrames — whether you're rendering hundreds of videos a day, building agent-driven composition tooling, or experimenting with HTML-as-video for the first time — we'd love to hear about it. + +Adding your organization helps the community understand how HyperFrames is being used in the wild and makes it easier for new users to find peers solving similar problems. + +## How to add your organization + +Open a pull request that adds a row to the table below. Keep entries short: + +- **Organization** — your company or project name, linked to your website. +- **Contact** — a GitHub handle or contact person who can answer questions about your usage. +- **How HyperFrames is used** — one sentence on the use case (e.g., "Personalized video at scale," "Agent-authored marketing assets," "Slides-to-video pipeline"). + +If you'd rather not be listed publicly, that's fine — drop a note in [our Discord](https://discord.gg/EbK98HBPdk) instead. We always like hearing about how the project is being used. + +## Production + +| Organization | Contact | How HyperFrames is used | +| -------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------ | +| [HeyGen](https://www.heygen.com) | [@jrusso1020](https://github.com/jrusso1020) | Powers AI-generated video composition and rendering across HeyGen's video product surface. | + +## Evaluating + +_Open a PR to add your organization here if you're trying HyperFrames in a non-production context._ diff --git a/CLAUDE.md b/CLAUDE.md index e9fc57bc4..4c8b6990a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -67,4 +67,4 @@ will not match CI. Use it only for local-only experimentation. ## Skills -Composition authoring (not repo development) is guided by skills installed via `npx skills add heygen-com/hyperframes`. See `skills/` for source. Invoke `/hyperframes`, `/hyperframes-cli`, `/hyperframes-registry`, or `/gsap` when authoring compositions. When a user provides a website URL and wants a video, invoke `/website-to-hyperframes` — it runs the full 7-step capture-to-video pipeline. +Composition authoring (not repo development) is guided by skills installed via `npx skills add heygen-com/hyperframes`. See `skills/` for source. Invoke `/hyperframes`, `/hyperframes-cli`, `/hyperframes-registry`, `/tailwind`, or `/gsap` when authoring compositions. Use `/tailwind` for projects created with `hyperframes init --tailwind` so agents follow the pinned Tailwind v4 browser-runtime contract instead of Studio's Tailwind v3 setup. Use `/animejs`, `/css-animations`, `/lottie`, `/three`, or `/waapi` when a composition uses those first-party runtime adapters. Invoke `/hyperframes-media` for asset preprocessing (TTS narration, audio/video transcription, background removal for transparent overlays) — these commands have their own skill so the CLI skill stays focused on the dev loop. When a user provides a website URL and wants a video, invoke `/website-to-hyperframes` — it runs the full 7-step capture-to-video pipeline. diff --git a/README.md b/README.md index e35c1e8c1..37ea6f165 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ npm downloads License Node.js + Discord

Write HTML. Render video. Built for agents.

@@ -31,7 +32,7 @@ Install the HyperFrames skills, then describe the video you want: npx skills add heygen-com/hyperframes ``` -This teaches your agent (Claude Code, Cursor, Gemini CLI, Codex) how to write correct compositions and GSAP animations. In Claude Code, the skills register as slash commands — invoke `/hyperframes` to author compositions, `/hyperframes-cli` for CLI commands, and `/gsap` for animation help. +This teaches your agent (Claude Code, Cursor, Gemini CLI, Codex) how to write correct compositions, GSAP timelines, Tailwind v4 browser-runtime styles, and first-party adapter animations. In Claude Code, the skills register as slash commands — invoke `/hyperframes` to author compositions, `/hyperframes-cli` for the dev-loop commands (init, lint, preview, render), `/hyperframes-media` for asset preprocessing (TTS, transcription, background removal), `/tailwind` for `init --tailwind` projects, `/gsap` for timeline animation help, or the adapter skills (`/animejs`, `/css-animations`, `/lottie`, `/three`, `/waapi`) when a composition uses those runtimes. For Claude Design, open [`docs/guides/claude-design-hyperframes.md`](https://github.com/heygen-com/hyperframes/blob/main/docs/guides/claude-design-hyperframes.md) on GitHub and click the download button (↓) to save it, then attach the file to your Claude Design chat. It produces a valid first draft; refine in any AI coding agent. See the [Claude Design guide](https://hyperframes.heygen.com/guides/claude-design). @@ -184,13 +185,20 @@ HyperFrames ships [skills](https://github.com/vercel-labs/skills) that teach AI npx skills add heygen-com/hyperframes ``` -| Skill | What it teaches | -| ------------------------ | -------------------------------------------------------------------------------------------- | -| `hyperframes` | HTML composition authoring, captions, TTS, audio-reactive animation, transitions | -| `hyperframes-cli` | CLI commands: init, lint, preview, render, transcribe, tts, doctor | -| `hyperframes-registry` | Block and component installation via `hyperframes add` | -| `website-to-hyperframes` | Capture a URL and turn it into a video — full website-to-video pipeline | -| `gsap` | GSAP animation API, timelines, easing, ScrollTrigger, plugins, React/Vue/Svelte, performance | +| Skill | What it teaches | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------- | +| `hyperframes` | HTML composition authoring, captions, TTS, audio-reactive animation, transitions | +| `hyperframes-cli` | Dev-loop CLI: init, lint, inspect, preview, render, doctor | +| `hyperframes-media` | Asset preprocessing: tts (Kokoro), transcribe (Whisper), remove-background (u2net) — voice/model/codec selection | +| `hyperframes-registry` | Block and component installation via `hyperframes add` | +| `website-to-hyperframes` | Capture a URL and turn it into a video — full website-to-video pipeline | +| `remotion-to-hyperframes` | Translate a Remotion (React) composition into a HyperFrames HTML composition | +| `gsap` | GSAP timelines for HyperFrames: paused registration, deterministic seeking, easing, sequencing, performance | +| `animejs` | Anime.js animations and timelines registered on `window.__hfAnime` for deterministic HyperFrames seeking | +| `css-animations` | CSS keyframe animation patterns that HyperFrames can discover, pause, and seek | +| `lottie` | `lottie-web` and dotLottie players registered on `window.__hfLottie` with local assets and paused playback | +| `three` | Three.js scenes that render from HyperFrames `hf-seek` events and `window.__hfThreeTime` instead of wall-clock time | +| `waapi` | Web Animations API `element.animate()` patterns seeked through `document.getAnimations()` | ## Contributing diff --git a/bun.lock b/bun.lock index 51eaf3a8d..cba993eed 100644 --- a/bun.lock +++ b/bun.lock @@ -21,7 +21,7 @@ }, "packages/cli": { "name": "@hyperframes/cli", - "version": "0.4.27", + "version": "0.4.45", "bin": { "hyperframes": "./dist/cli.js", }, @@ -35,6 +35,7 @@ "giget": "^3.2.0", "hono": "^4.0.0", "mime-types": "^3.0.2", + "onnxruntime-node": "^1.20.0", "open": "^10.0.0", "postcss": "^8.5.8", "prettier": "^3.8.1", @@ -58,14 +59,15 @@ "vitest": "^3.2.4", }, "optionalDependencies": { - "@google/genai": "^1.50.0", + "@google/genai": "^1.50.1", }, }, "packages/core": { "name": "@hyperframes/core", - "version": "0.4.27", + "version": "0.4.45", "dependencies": { "@chenglou/pretext": "^0.0.5", + "postcss": "^8.5.8", "sharp": "^0.34.5", }, "devDependencies": { @@ -90,7 +92,7 @@ }, "packages/engine": { "name": "@hyperframes/engine", - "version": "0.4.27", + "version": "0.4.45", "dependencies": { "@hono/node-server": "^1.13.0", "@hyperframes/core": "workspace:^", @@ -108,7 +110,7 @@ }, "packages/player": { "name": "@hyperframes/player", - "version": "0.4.27", + "version": "0.4.45", "devDependencies": { "@types/bun": "^1.1.0", "gsap": "^3.12.5", @@ -120,7 +122,7 @@ }, "packages/producer": { "name": "@hyperframes/producer", - "version": "0.4.27", + "version": "0.4.45", "dependencies": { "@fontsource/archivo-black": "^5.2.8", "@fontsource/eb-garamond": "^5.2.7", @@ -160,7 +162,7 @@ }, "packages/shader-transitions": { "name": "@hyperframes/shader-transitions", - "version": "0.4.27", + "version": "0.4.45", "dependencies": { "html2canvas": "^1.4.1", }, @@ -172,7 +174,7 @@ }, "packages/studio": { "name": "@hyperframes/studio", - "version": "0.4.27", + "version": "0.4.45", "dependencies": { "@codemirror/autocomplete": "^6.20.1", "@codemirror/commands": "^6.10.3", @@ -1008,8 +1010,12 @@ "default-browser-id": ["default-browser-id@5.0.1", "", {}, "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q=="], + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + "define-lazy-prop": ["define-lazy-prop@3.0.0", "", {}, "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg=="], + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "^1.0.1", "has-property-descriptors": "^1.0.0", "object-keys": "^1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "0.13.4", "escodegen": "2.1.0", "esprima": "4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="], "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], @@ -1046,12 +1052,18 @@ "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], "esbuild": ["esbuild@0.25.12", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.12", "@esbuild/android-arm": "0.25.12", "@esbuild/android-arm64": "0.25.12", "@esbuild/android-x64": "0.25.12", "@esbuild/darwin-arm64": "0.25.12", "@esbuild/darwin-x64": "0.25.12", "@esbuild/freebsd-arm64": "0.25.12", "@esbuild/freebsd-x64": "0.25.12", "@esbuild/linux-arm": "0.25.12", "@esbuild/linux-arm64": "0.25.12", "@esbuild/linux-ia32": "0.25.12", "@esbuild/linux-loong64": "0.25.12", "@esbuild/linux-mips64el": "0.25.12", "@esbuild/linux-ppc64": "0.25.12", "@esbuild/linux-riscv64": "0.25.12", "@esbuild/linux-s390x": "0.25.12", "@esbuild/linux-x64": "0.25.12", "@esbuild/netbsd-arm64": "0.25.12", "@esbuild/netbsd-x64": "0.25.12", "@esbuild/openbsd-arm64": "0.25.12", "@esbuild/openbsd-x64": "0.25.12", "@esbuild/openharmony-arm64": "0.25.12", "@esbuild/sunos-x64": "0.25.12", "@esbuild/win32-arm64": "0.25.12", "@esbuild/win32-ia32": "0.25.12", "@esbuild/win32-x64": "0.25.12" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg=="], "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "4.0.1", "estraverse": "5.3.0", "esutils": "2.0.3" }, "optionalDependencies": { "source-map": "0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], @@ -1128,18 +1140,26 @@ "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + "global-agent": ["global-agent@4.1.3", "", { "dependencies": { "globalthis": "^1.0.2", "matcher": "^4.0.0", "semver": "^7.3.5", "serialize-error": "^8.1.0" } }, "sha512-KUJEViiuFT3I97t+GYMikLPJS2Lfo/S2F+DQuBWzuzaMPnvt5yyZePzArx36fBzpGTxZjIpDbXLeySLgh+k76g=="], + "global-directory": ["global-directory@4.0.1", "", { "dependencies": { "ini": "4.1.1" } }, "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q=="], + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "^1.2.1", "gopd": "^1.0.1" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + "google-auth-library": ["google-auth-library@10.6.2", "", { "dependencies": { "base64-js": "^1.3.0", "ecdsa-sig-formatter": "^1.0.11", "gaxios": "^7.1.4", "gcp-metadata": "8.1.2", "google-logging-utils": "1.1.3", "jws": "^4.0.0" } }, "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw=="], "google-logging-utils": ["google-logging-utils@1.1.3", "", {}, "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA=="], + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + "gsap": ["gsap@3.15.0", "", {}, "sha512-dMW4CWBTUK1AEEDeZc1g4xpPGIrSf9fJF960qbTZmN/QwZIWY5wgliS6JWl9/25fpTGJrMRtSjGtOmPnfjZB+A=="], "happy-dom": ["happy-dom@20.9.0", "", { "dependencies": { "@types/node": ">=20.0.0", "@types/whatwg-mimetype": "^3.0.2", "@types/ws": "^8.18.1", "entities": "^7.0.1", "whatwg-mimetype": "^3.0.0", "ws": "^8.18.3" } }, "sha512-GZZ9mKe8r646NUAf/zemnGbjYh4Bt8/MqASJY+pSm5ZDtc3YQox+4gsLI7yi1hba6o+eCsGxpHn5+iEVn31/FQ=="], "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "^1.0.0" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], "hono": ["hono@4.12.8", "", {}, "sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A=="], @@ -1286,6 +1306,8 @@ "make-dir": ["make-dir@4.0.0", "", { "dependencies": { "semver": "7.7.4" } }, "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw=="], + "matcher": ["matcher@4.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-S6x5wmcDmsDRRU/c2dkccDwQPXoFczc5+HpQ2lON8pnvHlnvHAHj5WlLVvw6n6vNyHuVugYrFohYxbS+pvFpKQ=="], + "mdn-data": ["mdn-data@2.27.1", "", {}, "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ=="], "meow": ["meow@13.2.0", "", {}, "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA=="], @@ -1336,8 +1358,14 @@ "object-hash": ["object-hash@3.0.0", "", {}, "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw=="], + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + "onnxruntime-common": ["onnxruntime-common@1.25.1", "", {}, "sha512-kKvYQFdos4LWJqhZ+nmKu3NT8NXzw8I5x9fNUKe1rNKcPfNKnYXUtW7JBpcKFsvLtrJashRgVYSbFap4cHxvNg=="], + + "onnxruntime-node": ["onnxruntime-node@1.25.1", "", { "dependencies": { "adm-zip": "^0.5.16", "global-agent": "^4.1.3", "onnxruntime-common": "1.25.1" }, "os": [ "linux", "win32", "darwin", ] }, "sha512-N0M58CGTiTsLkPpx9bxmRFi24GT6r67Qei/GrBEIiDyntcYdXU5vQZp112ypydG9vEKRFgbgUYQJnEi+jll8dg=="], + "open": ["open@10.2.0", "", { "dependencies": { "default-browser": "5.5.0", "define-lazy-prop": "3.0.0", "is-inside-container": "1.0.0", "wsl-utils": "0.1.0" } }, "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA=="], "oxc-parser": ["oxc-parser@0.120.0", "", { "dependencies": { "@oxc-project/types": "0.120.0" }, "optionalDependencies": { "@oxc-parser/binding-android-arm-eabi": "0.120.0", "@oxc-parser/binding-android-arm64": "0.120.0", "@oxc-parser/binding-darwin-arm64": "0.120.0", "@oxc-parser/binding-darwin-x64": "0.120.0", "@oxc-parser/binding-freebsd-x64": "0.120.0", "@oxc-parser/binding-linux-arm-gnueabihf": "0.120.0", "@oxc-parser/binding-linux-arm-musleabihf": "0.120.0", "@oxc-parser/binding-linux-arm64-gnu": "0.120.0", "@oxc-parser/binding-linux-arm64-musl": "0.120.0", "@oxc-parser/binding-linux-ppc64-gnu": "0.120.0", "@oxc-parser/binding-linux-riscv64-gnu": "0.120.0", "@oxc-parser/binding-linux-riscv64-musl": "0.120.0", "@oxc-parser/binding-linux-s390x-gnu": "0.120.0", "@oxc-parser/binding-linux-x64-gnu": "0.120.0", "@oxc-parser/binding-linux-x64-musl": "0.120.0", "@oxc-parser/binding-openharmony-arm64": "0.120.0", "@oxc-parser/binding-wasm32-wasi": "0.120.0", "@oxc-parser/binding-win32-arm64-msvc": "0.120.0", "@oxc-parser/binding-win32-ia32-msvc": "0.120.0", "@oxc-parser/binding-win32-x64-msvc": "0.120.0" } }, "sha512-WyPWZlcIm+Fkte63FGfgFB8mAAk33aH9h5N9lphXVOHSXEBFFsmYdOBedVKly363aWABjZdaj/m9lBfEY4wt+w=="], @@ -1458,6 +1486,8 @@ "semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="], + "serialize-error": ["serialize-error@8.1.0", "", { "dependencies": { "type-fest": "^0.20.2" } }, "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ=="], + "sharp": ["sharp@0.34.5", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.2", "semver": "^7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.5", "@img/sharp-darwin-x64": "0.34.5", "@img/sharp-libvips-darwin-arm64": "1.2.4", "@img/sharp-libvips-darwin-x64": "1.2.4", "@img/sharp-libvips-linux-arm": "1.2.4", "@img/sharp-libvips-linux-arm64": "1.2.4", "@img/sharp-libvips-linux-ppc64": "1.2.4", "@img/sharp-libvips-linux-riscv64": "1.2.4", "@img/sharp-libvips-linux-s390x": "1.2.4", "@img/sharp-libvips-linux-x64": "1.2.4", "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", "@img/sharp-libvips-linuxmusl-x64": "1.2.4", "@img/sharp-linux-arm": "0.34.5", "@img/sharp-linux-arm64": "0.34.5", "@img/sharp-linux-ppc64": "0.34.5", "@img/sharp-linux-riscv64": "0.34.5", "@img/sharp-linux-s390x": "0.34.5", "@img/sharp-linux-x64": "0.34.5", "@img/sharp-linuxmusl-arm64": "0.34.5", "@img/sharp-linuxmusl-x64": "0.34.5", "@img/sharp-wasm32": "0.34.5", "@img/sharp-win32-arm64": "0.34.5", "@img/sharp-win32-ia32": "0.34.5", "@img/sharp-win32-x64": "0.34.5" } }, "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg=="], "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], @@ -1564,6 +1594,8 @@ "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "0.27.4", "get-tsconfig": "4.13.6" }, "optionalDependencies": { "fsevents": "2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], + "type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], + "typed-query-selector": ["typed-query-selector@2.12.1", "", {}, "sha512-uzR+FzI8qrUEIu96oaeBJmd9E7CFEiQ3goA5qCVgc4s5llSubcfGHq9yUstZx/k4s9dXHVKsE35YWoFyvEqEHA=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], diff --git a/docs/catalog/blocks/apple-money-count.mdx b/docs/catalog/blocks/apple-money-count.mdx new file mode 100644 index 000000000..34056c079 --- /dev/null +++ b/docs/catalog/blocks/apple-money-count.mdx @@ -0,0 +1,53 @@ +--- +title: "Apple Money Count" +description: "Apple-style finance counter that counts from $0 to $10,000, flashes green, and bursts money icons with sound." +--- + +# Apple Money Count + +Apple-style finance counter that counts from $0 to $10,000, flashes green, and bursts money icons with sound. + +`showcase` `finance` `kinetic` `youtube` `sfx` + +Created by [Stronkter](https://x.com/Stronkter). + +## Source Prompt + +```text +📷HyperFrames by HeyGen Make me a five-second video of, on a white background, of a Apple-style bold font counting from $0 to $10,000. Once it counts to $10,000, it changes to a green color and the screen also flashes green for a second, and then money icons come out of the $10,000 amount all over the screen and then disappear. +``` + +