RepoPilotOpen in app →

cubiq/iscroll

Smooth scrolling for the web

Mixed

Stale — last commit 7y ago

weakest axis
Use as dependencyMixed

last commit was 7y ago; no tests detected…

Fork & modifyMixed

no tests detected; no CI workflows detected…

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 7y ago; no CI workflows detected

  • 18 active contributors
  • Distributed ownership (top contributor 36% of recent commits)
  • MIT licensed
  • Stale — last commit 7y ago
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days; add a test suite
  • Fork & modify MixedHealthy if: add a test suite
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Earn the “Healthy” badge

Current signals for cubiq/iscroll are Mixed. The embed flow is reserved for repos showing Healthy signals — the rest stay informational on this page so we're not putting a public call-out on your README. Address the items in the What would change the summary? dropdown above, then return to grab the embed code.

Common quick wins: green CI on default branch, no Critical CVEs in dependencies, recent commits on the default branch, a permissive license, and a published README.md with a quickstart.

Onboarding doc

Onboarding: cubiq/iscroll

Generated by RepoPilot · 2026-05-06 · Source

Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/cubiq/iscroll shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

Verdict

WAIT — Stale — last commit 7y ago

  • 18 active contributors
  • Distributed ownership (top contributor 36% of recent commits)
  • MIT licensed
  • ⚠ Stale — last commit 7y ago
  • ⚠ No CI workflows detected
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live cubiq/iscroll repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/cubiq/iscroll.

What it runs against: a local clone of cubiq/iscroll — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in cubiq/iscroll | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 2731 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>cubiq/iscroll</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of cubiq/iscroll. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/cubiq/iscroll.git
#   cd iscroll
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of cubiq/iscroll and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "cubiq/iscroll(\\.git)?\\b" \\
  && ok "origin remote is cubiq/iscroll" \\
  || miss "origin remote is not cubiq/iscroll (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/core.js" \\
  && ok "src/core.js" \\
  || miss "missing critical file: src/core.js"
test -f "src/open.js" \\
  && ok "src/open.js" \\
  || miss "missing critical file: src/open.js"
test -f "src/default/handleEvent.js" \\
  && ok "src/default/handleEvent.js" \\
  || miss "missing critical file: src/default/handleEvent.js"
test -f "build.js" \\
  && ok "build.js" \\
  || miss "missing critical file: build.js"
test -f "src/utils.js" \\
  && ok "src/utils.js" \\
  || miss "missing critical file: src/utils.js"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 2731 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2701d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/cubiq/iscroll"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

iScroll is a dependency-free JavaScript library that implements smooth, hardware-accelerated scrolling for web content across desktop, mobile, and smart TV platforms. It provides fine-grained control over scroll position, momentum physics, zooming, infinite scroll, and parallax effects—all in ~4KB—handling platforms where native scrolling is unavailable or insufficient (like older Android devices or when granular scroll interception is needed). Build-targeted mono-distribution: source code is compiled via build.js into five specialized distributions in build/ (iscroll.js, iscroll-lite.js, iscroll-probe.js, iscroll-zoom.js, iscroll-infinite.js), with demos/ containing 20+ feature examples (horizontal, carousel, infinite, parallax, etc.) that serve as both documentation and integration tests.

Who it's for

Mobile web developers and hybrid app engineers who need custom scrolling behavior beyond native browser defaults, especially those targeting legacy devices (older Android, feature phones) or building interactive UI patterns like carousels, infinite lists, and parallax layers that require scroll position awareness during momentum phases.

Maturity & risk

Moderately mature and stable: v5.2.0-snapshot indicates active development, the codebase is 311KB of production-grade JavaScript with zero dependencies, but the project shows signs of slower maintenance—no visible CI/test infrastructure in the file list, and the snapshot version suggests incomplete release cycle. Production-ready for established use cases, but not under aggressive active development.

Single-maintainer project (Matteo Spinelli) with minimal test automation visible in the repo structure (no test/ directory listed), and the snapshot version tag suggests a stalled release cycle. The library's core strength—cross-browser compatibility—becomes a liability as older platforms (Android 2.x era) fade from use. Breaking changes to touch/pointer event handling could affect production integrations without clear deprecation paths.

Active areas of work

No active development signals visible in the provided metadata—the snapshot version and absence of recent commit history suggest the project is in maintenance mode. The file structure shows all five build variants are stable, and demos cover the full feature set, but there is no indication of ongoing feature work or community pull requests being processed.

Get running

git clone https://github.com/cubiq/iscroll.git
cd iscroll
npm install
node build.js

Then open any demo in demos/*/ in a browser (e.g., demos/simple/index.html) to see iScroll in action.

Daily commands:

npm install
node build.js

Then serve the demos/ directory (e.g., python -m http.server or any local server) and open demos/simple/index.html in a browser. No dev server; changes to source require rebuilding with node build.js.

Map of the codebase

  • src/core.js — Core iScroll engine handling scroll mechanics, event binding, and state management—every feature depends on this.
  • src/open.js — Entry point that initializes the iScroll constructor and assembles modular features via build system.
  • src/default/handleEvent.js — Touch and pointer event dispatcher for scroll start, move, and end—critical for responsiveness.
  • build.js — Build system that combines modular source files into multiple release bundles (lite, probe, zoom, infinite).
  • src/utils.js — Utility functions for DOM manipulation, transform detection, and cross-browser compatibility.
  • src/default/_animate.js — Animation loop using requestAnimationFrame for smooth momentum and easing—performance-critical path.

Components & responsibilities

  • Core Engine (src/core.js) (Pure JS, Object prototype extension) — Maintains scroll position state, calculates velocity, manages lifecycle events, coordinates feature modules
    • Failure mode: Incorrect scroll position, velocity lag, event loop breakage; entire scroller unusable
  • Event Handler (src/default/handleEvent.js) (Touch Events, Pointer Events, event delegation) — Captures Touch/Pointer/Mouse events, calculates deltas, triggers core scroll calculations
    • Failure mode: Gestures not recognized, scroll unresponsive, false drag triggers
  • Animation Loop (src/default/_animate.js) (requestAnimationFrame, CSS transforms, easing functions) — Applies easing & momentum decay, runs requestAnimationFrame, updates DOM transforms, stops when complete
    • Failure mode: Stuttering, jank, over-scrolling, momentum not stopping
  • Feature Modules (src/zoom, src/snap, src/infinite, etc.) (JS mixins, event hooks, optional DOM manipulation) — Extend core with specific behaviors (pinch zoom, snap-to-grid, virtual scrolling, scrollbar indicators)
    • Failure mode: Feature-specific breakage (zoom doesn't work, snap points misaligned); core scroll still functional
  • Build System (build.js) (Node.js fs, custom bundler, uglify-js) — Combines source modules into pre-configured bundles (iscroll.js, iscroll-lite.js, iscroll-zoom.js, etc.)
    • Failure mode: Release bundles have wrong feature set, size bloat, or syntax errors

Data flow

  • User (Touch/Pointer input)Event Handler (src/default/handleEvent.js) — Raw touch/pointer/mouse events captured and normalized
  • Event HandlerCore Engine (src/core.js) — Parsed position delta, velocity, direction, and timestamp
  • Core EngineFeature Modules (zoom, snap, indicators, infinite) — Scroll state (x, y, directionX, directionY, velocity) broadcast via custom events for module hooks
  • Core EngineAnimation Loop (src/default/_animate.js) — Initiates requestAnimationFrame if momentum detected; provides easing function and target velocity
  • Animationundefined — undefined

How to make changes

Add a New Feature Module (e.g., new gesture type)

  1. Create a new folder under src/ with a build.json config listing dependent modules (src/newfeature/build.json)
  2. Implement the feature in src/newfeature/newfeature.js, extending or hooking into core.js events (src/newfeature/newfeature.js)
  3. Add a build config entry in build.js to merge this module into desired bundles (lite, probe, etc.) (build.js)
  4. Create a demo HTML file in demos/ to test and showcase the feature (demos/newfeature/index.html)

Customize Scroll Easing & Animation

  1. Edit src/default/_animate.js to modify ease function or add custom easing (bounce, elastic, etc.) (src/default/_animate.js)
  2. Pass easing options via constructor config in your HTML or update demo examples (demos/bounce-easing/index.html)

Build a Custom Release Bundle

  1. Define a new bundle entry in build.js with included/excluded modules via build.json references (build.js)
  2. Run 'npm run build' to generate the minified output in build/iscroll-custom.js (build/iscroll.js)

Why these technologies

  • Vanilla JavaScript (no dependencies) — Minimizes bundle size (~4KB) and avoids version conflicts; runs anywhere modern browsers are available
  • requestAnimationFrame + CSS transforms — Leverages GPU acceleration and browser vsync for 60 FPS smooth scrolling without main-thread jank
  • Touch & Pointer Events API — Single API covering mobile (iOS/Android) and desktop input; fallback to mouse events for older devices
  • Modular build system (custom bundler in build.js) — Allows users to bundle only needed features (lite, probe, zoom, infinite) instead of one monolithic bundle
  • UMD pattern (open.js / close.js) — Supports CommonJS, AMD, and global variable usage—works in browsers, Node, and any module system

Trade-offs already made

  • Custom build system instead of webpack/rollup

    • Why: Tight control over feature composition and minimal overhead; aligns with library's performance-first philosophy
    • Consequence: Harder for new contributors to customize builds; less standardized than mainstream bundlers
  • No native scroll event delegation; synthetic event system

    • Why: Allows granular control over scroll position mid-momentum, which native scroll can't intercept
    • Consequence: Must handle all scroll state manually; higher complexity, but enables unique features
  • 4KB payload (minified) over more abstractions and utilities

    • Why: Mobile-first design; small bundle is critical for real-world perf on slow networks
    • Consequence: Limited error handling and logging; less defensive programming

Non-goals (don't propose these)

  • Does not provide native browser scrolling—entirely custom scrolling engine
  • Does not include HTTP routing or server-side rendering
  • Does not handle real-time multi-touch gesture recognition (e.g., custom pinch angle detection)
  • Does not provide accessibility features (ARIA, keyboard nav) out of the box—must be added by integrator
  • Does not offer a React/Vue component wrapper—designed as vanilla JS for portability

Traps & gotchas

No visible test suite means regressions are caught only by manual demo testing—be cautious with touch event changes. The five build variants (lite, probe, zoom, infinite) are built from a single build.js merge, so source organization is invisible in the repo; modification requires understanding the compiler. CSS transforms (translate3d) rely on hardware acceleration; rendering performance degrades on older devices despite the library's claim to support them. No TypeScript definitions or JSDoc; API surface must be learned from demos and minified build output. The infinite demo requires a PHP server (dataset.php), but most developers will test with static builds.

Architecture

Concepts to learn

  • Hardware-accelerated CSS transforms (translate3d) — iScroll's core performance trick: using GPU-backed translate3d instead of DOM reflow avoids expensive layout recalculations during scroll, essential for 60fps on mobile—understanding this explains why the library doesn't manipulate top/left and why some CSS properties (position, margin) can break iScroll
  • Momentum scrolling with cubic easing — iScroll implements physics-based deceleration using cubic easing functions rather than simple velocity decay; this produces natural 'flick' behavior and is why the library needs to know scroll position during momentum—critical to understand for customizing easing in demos/bounce-easing/
  • Virtual DOM / element recycling (caching) — iScroll-infinite.js uses a caching strategy where DOM nodes are reused and repositioned rather than destroyed/created for each list item; understanding this pattern is why infinite scroll on mobile requires special handling and why the library includes a dedicated variant
  • Pointer vs. Touch vs. Mouse events (multi-input) — iScroll must handle three overlapping event types across platforms (Pointer API for modern browsers, Touch for iOS/Android, Mouse for desktop); the build variants suggest different platforms have different event patterns—critical when debugging scroll issues on specific devices
  • RequestAnimationFrame (RAF) for scroll animation — iScroll uses RAF instead of setTimeout to animate scroll position, syncing with browser repaint cycles; understanding RAF timing is why momentum stops at different scroll positions on different frame rates
  • Snap-to-position (pagination) — Several demos (carousel, snap) use snap points that quantize final scroll position to grid boundaries; this is a distinct feature from momentum and requires understanding how the library intercepts scroll end events—critical for carousel implementations
  • Deferred scroll position refresh (resize handling) — The library exposes a refresh() method because window resizes, content changes, and dynamic DOM insertions invalidate cached scroll boundaries; understanding when to call refresh() is non-obvious and causes subtle bugs in responsive layouts

Related repos

  • matteo/zooming — Companion library by the same author for image zooming; often used alongside iScroll for pinch-zoom gallery interactions
  • chrisvfritz/vue-lazyload — Common integration pattern: iScroll paired with lazy-loading to handle infinite scrolling of images without memory overhead
  • desandro/infinite-scroll — Alternative infinite scroll library; iScroll-infinite.js solves the same problem with caching, useful for understanding competitive trade-offs
  • peacepostman/hammerjs — Touch gesture library; many iScroll users layer Hammer.js on top for tap, swipe, and multi-touch gestures beyond scrolling
  • WICG/virtual-scroller — Emerging web standard for efficient virtualized scrolling; understanding iScroll-infinite's caching strategy clarifies why this standard is needed

PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add unit tests for core scrolling functionality (src/core.js and src/default/_animate.js)

The repo has no visible test suite despite being a high-performance library where scroll behavior, momentum, and easing are critical. With many build variants (iscroll.js, iscroll-lite.js, iscroll-probe.js, iscroll-zoom.js), regression testing is essential. This would catch breaking changes and improve contributor confidence.

  • [ ] Set up a test runner (Jest or Mocha) in package.json with dev dependency
  • [ ] Create test/core.test.js for src/core.js covering initialization, scroll position getters/setters
  • [ ] Create test/animate.test.js for src/default/_animate.js covering easing functions and momentum calculations
  • [ ] Add npm test script and .npmignore to exclude tests from published package
  • [ ] Document test running instructions in CONTRIBUTING.md

Create indicator module documentation (src/indicator/ has no README)

The src/indicator/ directory contains specialized scroll indicator functionality (_initIndicators.js, _translate.js, _transitionTime.js) with a build.json config, but no documentation exists. Multiple demos (scrollbars, styled-scrollbars, minimap) use indicators, making this a complex feature that contributors need guidance on.

  • [ ] Create src/indicator/README.md explaining the purpose and API of indicator modules
  • [ ] Document the build.json pattern and how indicators are composed into builds
  • [ ] Add examples linking to demos/scrollbars/index.html and demos/styled-scrollbars/index.html
  • [ ] Explain the relationship between indicator methods (_translate, _transitionTime, _transitionTimingFunction)
  • [ ] Document how to create custom indicator implementations

Add GitHub Actions CI workflow for build verification and linting

The repo has build.js, jshint, and uglify-js in devDependencies but no automated CI. Contributors cannot know if their changes pass linting or produce valid builds until manually testing. This causes friction and inconsistent code quality across variants.

  • [ ] Create .github/workflows/build.yml GitHub Action workflow file
  • [ ] Add steps to run npm run lint (ensure jshint script exists in package.json) against src/ and demos/
  • [ ] Add step to run node build.js and verify all files in build/ are generated without errors
  • [ ] Verify all 4 variants build correctly (iscroll.js, iscroll-lite.js, iscroll-probe.js, iscroll-zoom.js)
  • [ ] Add build status badge to README.md

Good first issues

  • Add JSDoc comments to build/iscroll.js public API: The compiled distribution has zero inline documentation; adding comprehensive JSDoc for constructor options, methods (scrollTo, refresh, destroy), and event callbacks would enable IDE autocomplete and reduce onboarding friction. Target: document all public properties in the main IScroll class.
  • Create a test suite covering touch event handling across variants: No test/ directory exists; the five variants (lite, probe, zoom, infinite) lack automated regression tests for pointer/touch/mouse event sequences. Starting point: write unit tests for momentum calculation and scroll position tracking using a mocking library, initially for iscroll-lite.js.
  • Add TypeScript type definitions (index.d.ts): Modern web projects expect .d.ts files; creating a single DefinitelyTyped-style definition file for iScroll would unlock IDE support and allow TypeScript users to adopt the library without type-casting workarounds. Start by extracting types from demos/ and build/iscroll.js public API.

Top contributors

Recent commits

  • 60ed6f8 — change version name (sculove)
  • bd0fd7f — update dist file (sculove)
  • 9520169 — fix(core,util): add defence code for some devices (sculove)
  • a128da4 — Merge pull request #1122 from cubiq/chrome55 (sculove)
  • 97e7b26 — add touchAction property when using PointEvent (sculove)
  • 2671565 — Merge pull request #1121 from cubiq/passiveChrome (sculove)
  • 975bf52 — fix isPassive function (sculove)
  • 72bdb89 — Merge pull request #1120 from cubiq/passiveChrome (sculove)
  • 0788ab9 — apply passive options to fix chrome54+ bugs (sculove)
  • 056cecf — Merge pull request #1098 from catgofire/master (sculove)

Security observations

The iScroll codebase has a moderate security posture with primary concerns centered on severely outdated dependencies (uglify-js and jshint from 2016). While the core library itself is a vanilla JavaScript scrolling utility with low intrinsic risk, the development dependencies contain unpatched vulnerabilities. The demo applications require review for potential XSS vulnerabilities, particularly the PHP backend script. The project lacks modern security practices such as vulnerability disclosure policies and automated dependency scanning. The absence of security.json or regular security updates is concerning for a library with such widespread adoption.

  • High · Outdated Dependency: uglify-js — package.json - devDependencies. The package.json specifies uglify-js ~2.6.2, which is severely outdated (released in 2016). This version contains known security vulnerabilities and lacks security patches. Current versions are in the 3.x range. Fix: Update uglify-js to the latest stable version (3.17.x or higher). Run: npm install uglify-js@latest --save-dev
  • High · Outdated Dependency: jshint — package.json - devDependencies. The package.json specifies jshint ~2.9.1, which is outdated (released in 2016). Using old linting tools means missing out on security-related code analysis improvements and bug fixes. Fix: Update jshint to the latest stable version (2.13.x or higher). Run: npm install jshint@latest --save-dev
  • Medium · Missing npm audit Configuration — package.json / build.js. No npm audit, security scanning, or dependency vulnerability checking tools are configured in the build process. This means vulnerable dependencies could be introduced without detection. Fix: Add npm audit to CI/CD pipeline. Include 'npm audit' in build scripts. Consider adding tools like snyk or dependabot for automated vulnerability scanning.
  • Medium · Potential XSS Risk in Demo Applications — demos/infinite/dataset.php, demos/ (general). The demos directory contains HTML files that may be vulnerable to XSS if user input is improperly handled. The file structure shows dataset.php which could be injecting data into the DOM without proper sanitization. Fix: Review all demo files to ensure proper output encoding. Use textContent instead of innerHTML where possible. Validate and sanitize any server-side data before rendering in the DOM.
  • Low · Missing Security Documentation — Repository root. No SECURITY.md or security policy file found in the repository. This makes it difficult for security researchers to report vulnerabilities responsibly. Fix: Create a SECURITY.md file documenting the vulnerability disclosure process, security contact information, and supported versions.
  • Low · No Subresource Integrity (SRI) Guidance — build/ directory, README.md. Build artifacts are provided but no SRI hashes are documented for CDN usage, increasing the risk of compromised script delivery. Fix: Document SRI hashes for all build artifacts and recommend their use in the README. Generate SRI hashes using: npm install -g sri-hash && sri-hash build/iscroll.js

LLM-derived; treat as a starting point, not a security audit.

Where to read next


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · cubiq/iscroll — RepoPilot