NUKnightLab/TimelineJS
TimelineJS: A Storytelling Timeline built in JavaScript.
Stale — last commit 4y ago
weakest axisnon-standard license (Other); last commit was 4y ago…
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
last commit was 4y ago; no CI workflows detected
- ✓11 active contributors
- ✓Other licensed
- ✓Tests present
- ⚠Stale — last commit 4y ago
- ⚠Concentrated ownership — top contributor handles 71% of recent commits
- ⚠Non-standard license (Other) — review terms
- ⚠No CI workflows detected
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
- →Deploy as-is Mixed → Healthy 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.
Embed the "Forkable" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/nuknightlab/timelinejs)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/nuknightlab/timelinejs on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: NUKnightLab/TimelineJS
Generated by RepoPilot · 2026-05-07 · 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:
- 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. - 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.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/NUKnightLab/TimelineJS 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 4y ago
- 11 active contributors
- Other licensed
- Tests present
- ⚠ Stale — last commit 4y ago
- ⚠ Concentrated ownership — top contributor handles 71% of recent commits
- ⚠ Non-standard license (Other) — review terms
- ⚠ No CI workflows 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 NUKnightLab/TimelineJS
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/NUKnightLab/TimelineJS.
What it runs against: a local clone of NUKnightLab/TimelineJS — 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 NUKnightLab/TimelineJS | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | 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 ≤ 1486 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of NUKnightLab/TimelineJS. If you don't
# have one yet, run these first:
#
# git clone https://github.com/NUKnightLab/TimelineJS.git
# cd TimelineJS
#
# 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 NUKnightLab/TimelineJS and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "NUKnightLab/TimelineJS(\\.git)?\\b" \\
&& ok "origin remote is NUKnightLab/TimelineJS" \\
|| miss "origin remote is not NUKnightLab/TimelineJS (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other 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 "source/js/Core/Core/VMM.js" \\
&& ok "source/js/Core/Core/VMM.js" \\
|| miss "missing critical file: source/js/Core/Core/VMM.js"
test -f "source/js/Core/Core/VMM.Library.js" \\
&& ok "source/js/Core/Core/VMM.Library.js" \\
|| miss "missing critical file: source/js/Core/Core/VMM.Library.js"
test -f "source/js/Core/Language/VMM.Language.js" \\
&& ok "source/js/Core/Language/VMM.Language.js" \\
|| miss "missing critical file: source/js/Core/Language/VMM.Language.js"
test -f "source/js/Core/Core/VMM.Date.js" \\
&& ok "source/js/Core/Core/VMM.Date.js" \\
|| miss "missing critical file: source/js/Core/Core/VMM.Date.js"
test -f "source/embed/index.html" \\
&& ok "source/embed/index.html" \\
|| miss "missing critical file: source/embed/index.html"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 1486 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1456d)"
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/NUKnightLab/TimelineJS"
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).
⚡TL;DR
TimelineJS is a JavaScript library that renders interactive, media-rich timelines from multiple data sources (Google Sheets, JSON, JSONP, Storify). It embeds YouTube, Twitter, Flickr, Vimeo, Google Maps, and SoundCloud content directly into timeline slides and handles responsive layout across devices. Monolithic structure: source/js/Core/ contains the VMM (Verite Media Metastructure) framework with utilities (VMM.Browser, VMM.Date, VMM.Library, VMM.Util); source/js/Core/Embed/ handles CDN embedding logic; source/css/ has theme variants (dark, texture); examples/ provides runnable demos with Google Sheets, JSON, JSONP, and Storify sources.
👥Who it's for
Journalists, educators, and content creators who need to publish historical narratives or event sequences with embedded multimedia without writing custom JavaScript. Museum curators and researchers building interactive exhibits.
🌱Maturity & risk
Actively maintained but deprecated by design. This is the v1 version; Knight Lab released TimelineJS3 as the successor (https://github.com/NUKnightLab/TimelineJS3) and explicitly halted development on this codebase. Issues and PRs are disabled. However, the library is served via CDN (cdn.knightlab.com) and remains production-stable for existing deployments.
High deprecation risk. No future development is planned; the JSON format is incompatible with TimelineJS3 and no automatic converter exists. The codebase depends on legacy Python tooling (Fabric 1.6.1, Flask 0.10.1 from ~2013) with known security vulnerabilities. Forking or upgrading to TimelineJS3 is strongly recommended for new projects.
Active areas of work
Development is frozen—no active commits, no pull requests accepted, issues disabled per README. The library is maintained only as a static artifact served via CDN for backward compatibility with existing deployed timelines.
🚀Get running
git clone https://github.com/NUKnightLab/TimelineJS.git
cd TimelineJS
pip install -r requirements.txt
fab build
Python/Fabric build system is required; see fabfile.py for build targets.
Daily commands:
fab build # Builds minified JS/CSS into build/ directory
fab serve # Starts local Flask dev server (port 5000)
View examples in examples/example_*.html by opening in browser after build. TimelineJS is embedded via <script> tag with timeline_config object—no separate server required for use.
🗺️Map of the codebase
source/js/Core/Core/VMM.js— Primary entry point and namespace for the entire VMM (Verite Media Machine) framework; all other modules extend this core object.source/js/Core/Core/VMM.Library.js— Abstraction layer for DOM manipulation and AJAX; critical dependency for all UI interactions and data loading.source/js/Core/Language/VMM.Language.js— Internationalization system managing 50+ language locales; essential for multi-language timeline rendering.source/js/Core/Core/VMM.Date.js— Date parsing and formatting engine supporting multiple calendar systems and date formats; core to timeline event processing.source/embed/index.html— Embed generation entry point; demonstrates how TimelineJS is loaded and initialized in external pages.source/js/Core/Embed/Embed.js— CDN embed loader and initialization logic; handles dynamic timeline creation from external sources.config.json— Build and deployment configuration; defines output paths, CDN targets, and module compilation settings.
🛠️How to make changes
Add a new language/locale
- Create new locale file following the structure of source/js/Core/Language/locale/en.js (contains month/day names, UI strings) (
source/js/Core/Language/locale/xx.js) - Register the locale by adding an import statement in VMM.Language.js referencing your new file (
source/js/Core/Language/VMM.Language.js) - Test initialization with lang='xx' parameter in your timeline embed or config object (
examples/example_json.html)
Add a new data source format
- Create a new parser module in source/js following VMM.Date.js patterns for data transformation (
source/js/YourDataSource.js) - Hook parser into Embed.CDN.Generator.js or Embed.js to detect and transform your format (
source/js/Core/Embed/Embed.CDN.Generator.js) - Create example HTML demonstrating the new source type with sample data (
examples/example_yoursource.html)
Create a custom theme
- Create new CSS file referencing theme sprites in source/css/themes/ (see timeline-dark.png pattern) (
source/css/themes/timeline-custom.css) - Design/export new spritesheet covering all UI states (closed, open, hover, active) (
source/gfx/timeline-custom.psd) - Pass theme name via 'font-family' or 'theme' parameter when initializing timeline (
examples/example_json.html)
Support a new date format
- Add format parsing logic to VMM.Date.js parseDate() method or create a new date parser function (
source/js/Core/Core/VMM.Date.js) - Test with example timelines containing events in your new date format (
examples/example_json.json) - Document the format in README.markdown for end users (
README.markdown)
🔧Why these technologies
- VMM Framework (custom) — Lightweight jQuery-based abstraction enabling rapid timeline UI development without heavy framework dependencies (2012-era constraints)
- jQuery Library.js wrapper — Provides consistent DOM/AJAX API across browsers without requiring full jQuery as external dependency
- Fabric (Python) + Fabfile — Automates multi-step deployment to CDN (boto S3 integration) and build pipeline orchestration
- Spritesheet + CSS backgrounds — Minimizes HTTP requests and provides Retina (@2x) support for timeline UI elements
- JSONP + Google Sheets API — Enables no-backend timeline creation; users can edit timelines in familiar spreadsheet UIs
⚖️Trade-offs already made
-
No external framework dependencies (jQuery optional)
- Why: Minimize payload and compatibility issues; enable lightweight CDN delivery for embed use case
- Consequence: Higher custom code maintenance burden; reinvented common utilities (DOM selectors, AJAX, events)
-
Client-side date parsing (no server-side normalization)
- Why: Reduce backend complexity and enable offline timeline rendering
- Consequence: Complex date logic (BCE support, multiple calendars) duplicated in JavaScript; harder to test
-
CDN-based embed architecture
- Why: Allow embeds on any website without backend integration; reduce hosting costs
- Consequence: CORS limitations; cross-origin data fetching requires JSONP or hosting on same CDN
-
Hard-coded language files (50+ locales)
- Why: Avoid runtime translation lookups; support offline UIs; enable bundle optimization per language
- Consequence: Increased bundle size; manual locale maintenance; no real-time translation updates
🚫Non-goals (don't propose these)
- Real-time collaborative editing (Google Sheets sync is one-way, spreadsheet is source-of-truth)
- Native mobile apps (web-only; responsive but not optimized for touch gestures)
- Backend user authentication or timeline access control
- Automatic data format migration or API versioning (breaking changes between TimelineJS v1 and v3)
- Server-side rendering or progressive enhancement (requires JavaScript to function)
🪤Traps & gotchas
- VMM namespace collision: The library uses global
VMMnamespace—conflicts likely if other libraries use it. 2. Python 2 codebase: Fabric 1.6.1 and build system may not run on Python 3 without modification. 3. No test suite visible: No test directory in file list; quality assurance unknown. 4. jQuery dependency implied but not listed: Examples reference jQuery; check if VMM.Library assumes jQuery presence. 5. CDN-only supported: After deprecation, library only guaranteed to work from cdn.knightlab.com URLs; self-hosting may require careful version pinning.
🏗️Architecture
💡Concepts to learn
- VMM (Verite Media Metastructure) Framework — Custom utility framework at the core of this codebase; understanding VMM.js, VMM.Library, VMM.Util is required to extend or modify any functionality
- Module Pattern (JavaScript Namespace) — TimelineJS uses global
VMMnamespace with nested modules (VMM.Browser, VMM.Date, etc.) to avoid global scope pollution—common pattern in pre-ES6 JavaScript libraries - Media Embed Parsers — VMM.Library contains URL regex patterns and embed generators for YouTube, Twitter, Flickr, etc.—understanding this pattern is essential to add new media types
- JSONP (JSON with Padding) — TimelineJS supports JSONP for cross-origin data loading (pre-CORS era); understanding callback wrapping is needed for certain data source configurations
- Google Sheets as Database — Primary data source for non-technical users; library queries Sheets API via GET parameters, avoiding explicit API key management—useful pattern for public data publishing
- Responsive Web Design (pre-mobile-first era) — TimelineJS uses CSS and JavaScript-based layout adjustments for different screen sizes; predates CSS media queries best practices, worth understanding legacy approaches
- Custom Event System — VMM implements custom event dispatching for timeline state changes (slide navigation, media loading); critical for understanding data flow and hooking into timeline lifecycle
🔗Related repos
NUKnightLab/TimelineJS3— Official successor to this repository; uses new JSON format but provides better maintenance, TypeScript support, and modern toolingcharto/timelinejs-webpack— Community webpack wrapper for v2 TimelineJS; demonstrates how to modernize the build system and integrate with contemporary JS toolchainsNUKnightLab/StorylineJS— Sibling Knight Lab project using similar VMM framework architecture; useful reference for understanding VMM utility patternsvisjs/vis-timeline— Active alternative timeline library with similar feature set (media embedding, responsive layout) but modern maintenance and Vue/React compatibilityalmende/vis.js— Parent project of vis-timeline; broader data visualization toolkit from same maintainers, useful if timeline is part of larger analytics application
🪄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 VMM.Date.js date parsing and locale handling
VMM.Date.js is a critical core module used across TimelineJS for parsing various date formats and applying locale-specific date formatting. Currently, there are no visible test files in the repo (no test/ or spec/ directory). Given that TimelineJS supports 30+ locales (af, ar, be, bg, ca, cz, da, de, el, en, en-24hr, en-week, eo, es, et, eu, fa, etc.) in source/js/Core/Language/locale/, adding comprehensive unit tests would prevent regressions when users submit date formats in different languages or edge cases. This is high-value because date parsing bugs directly break the timeline visualization.
- [ ] Create tests/ directory with test framework (Jasmine or QUnit, matching codekit-config.json usage)
- [ ] Add test file tests/VMM.Date.test.js covering: ISO dates, US dates, European dates, timestamp parsing, and multi-format edge cases
- [ ] Add tests for locale-aware date formatting by testing multiple locale files from source/js/Core/Language/locale/
- [ ] Document test running instructions in DEVELOPER.md (currently sparse on testing guidance)
Create MIGRATION.md guide for converting TimelineJS v1 JSON to TimelineJS3 format
The README explicitly states 'The new version of TimelineJS requires a new JSON format, and there is no direct conversion tool.' However, many users likely have existing TimelineJS v1 instances using the old JSON format (evident from examples/example_json.json and examples/model.json). A migration guide with before/after JSON examples and a documented conversion script would provide significant value to the maintenance burden, reducing duplicate support questions. This is concrete and specific to this repo's known compatibility gap.
- [ ] Analyze examples/example_json.json and examples/model.json to document the old TimelineJS v1 JSON schema
- [ ] Reference TimelineJS3 JSON schema from the new repo at https://github.com/NUKnightLab/TimelineJS3
- [ ] Create MIGRATION.md with side-by-side JSON examples showing old format → new format transformations
- [ ] Include a simple Python/Node.js conversion script as examples/convert_json_v1_to_v3.py or similar
Add integration tests for Google Spreadsheet data source parsing in source/js/Core/
The examples/ directory includes example_googlespreadsheet.html, indicating Google Sheets is a primary data source. The Core loader modules (VMM.LoadLib.js, VMM.Library.js, Embed.LoadLib.js) handle external data fetching, but there are no visible tests validating that spreadsheet parsing works correctly. Given that the README mentions 'The new library should work with existing Google Spreadsheets,' regression testing here is critical. This ensures the deprecated v1 version remains functional for users who can't migrate yet.
- [ ] Create tests/integration/ directory for external data source tests
- [ ] Add tests/integration/google-spreadsheet-parser.test.js that mocks Google Sheets responses and validates parsing
- [ ] Test the spreadsheet→JSON transformation in Embed.js and related loaders using fixtures from examples/
- [ ] Document how to run integration tests in DEVELOPER.md with notes on mocking external APIs
🌿Good first issues
- Add unit tests for
VMM.Date.jsdate parsing logic—no test framework visible butsource/js/Core/Core/VMM.Date.jshandles date normalization across multiple formats (ISO, relative dates) with no coverage visible. - Document the complete timeline JSON schema in a markdown file—
examples/model.jsonexists but lacks inline documentation of required vs. optional fields, media type constraints, and nested object structures. - Add support for new media type (e.g., Podcast/audio embeds via Podbean)—extend
VMM.Library.jsparser pattern; requires adding URL detection regex and embed code generation, similar to existing Flickr/Vimeo handlers.
⭐Top contributors
Click to expand
- @JoeGermuska — 71 commits
- @jywsn — 11 commits
- [@Luke Rague](https://github.com/Luke Rague) — 6 commits
- @hbillings — 3 commits
- @alaasdk — 3 commits
📝Recent commits
Click to expand
f1f59d3— Explain why ISSUES have been disabled (JoeGermuska)448574f— Use adhoc ssl context instead of bogus self-signed certificate (jywsn)c41bdd7— explain official end of development for this code (JoeGermuska)adb0fc2— we are trying not to include in the repo (JoeGermuska)120df50— fix wikipedia URL bug which was finding google search results and mixing 'this is a wikipedia' detection with a differen (JoeGermuska)66c33af— explicit favicon (JoeGermuska)a0ff4d0— remove ref to change for https now that cdn.knightlab.com is served as https (JoeGermuska)aa353f1— protocols are nice (JoeGermuska)f003788— Merge branch 'master' of github.com:NUKnightLab/TimelineJS (hbillings)ae692a0— teaser for timeline3 in 'make' (hbillings)
🔒Security observations
- Critical · Extremely Outdated and Unmaintained Codebase —
README.markdown, entire project. The project is explicitly stated as no longer under development. All dependencies are from 2013-2014 era and have not been updated. No security patches will be applied. This poses a critical risk as any vulnerabilities discovered in dependencies will never be addressed. Fix: Migrate to TimelineJS3 or another actively maintained timeline library. If continued use is necessary, conduct a comprehensive security audit and implement mitigations for all known CVEs in dependencies. - Critical · Multiple Severely Outdated Python Dependencies with Known CVEs —
requirements.txt. Dependencies include: pycrypto (2.6, deprecated), pyOpenSSL (0.15.1, from 2014), paramiko (1.10.1, from 2014), Fabric (1.6.1, from 2013), and Flask (0.10.1, from 2013). These versions contain numerous known security vulnerabilities including crypto weaknesses, SSL/TLS issues, and authentication bypasses. Fix: Update all dependencies to latest versions: pycrypto→pycryptodome, pyOpenSSL→latest, paramiko→latest, Fabric→latest, Flask→latest. Note: This project appears abandoned, so these dependencies may not be actively used. - High · Deprecated pycrypto Library —
requirements.txt (pycrypto==2.6). pycrypto (version 2.6) is officially deprecated and no longer maintained. It contains known cryptographic weaknesses and is vulnerable to timing attacks. Fix: Replace with pycryptodome (drop-in replacement) or use Python's native cryptography library for new code. - High · Ancient OpenSSL/TLS Library Version —
requirements.txt (pyOpenSSL==0.15.1). pyOpenSSL 0.15.1 (2014) lacks modern TLS 1.2/1.3 support and contains multiple CVEs related to certificate validation and SSL/TLS handling. Fix: Update to pyOpenSSL 23.x or latest stable version that supports TLS 1.2+ and modern cryptography. - High · Insecure SSH/SFTP Library Version —
requirements.txt (paramiko==1.10.1). paramiko 1.10.1 (2014) contains multiple known CVEs including weak key exchange algorithms and authentication vulnerabilities. Fix: Update to paramiko 3.x or latest version. Ensure SSH key sizes are minimum 2048-bit RSA or use ED25519. - Medium · Potential XSS Vulnerabilities in Timeline Rendering —
source/js/Core/Core/VMM.js, source/js/Core/Embed/Embed.js, examples/ (data loading patterns). The project loads JSON data from external sources (Google Spreadsheets, URLs) and renders timeline content. Without explicit analysis of VMM.js and timeline rendering code, there's a risk of stored/reflected XSS if user-supplied content isn't properly sanitized before DOM insertion. Fix: Review all DOM manipulation code. Ensure user content is sanitized using textContent instead of innerHTML. Implement Content Security Policy (CSP) headers. Use DOMPurify or similar library for any HTML content rendering. - Medium · JSONP Endpoint Security Risk —
examples/example_jsonp.html, source/js/Core/Core/VMM.Library.js. The codebase includes JSONP data loading (example_jsonp.html, example_jsonp.jsonp). JSONP is inherently vulnerable to CSRF attacks as it bypasses same-origin policy. Any malicious site can trigger requests to JSONP endpoints. Fix: Migrate from JSONP to CORS-enabled JSON endpoints. If JSONP must be used, implement CSRF tokens and validate origins. Consider implementing token-based authentication. - Medium · Absence of Security Headers —
source/embed/index.html. No evidence of security headers (CSP, X-Frame-Options, X-Content-Type-Options, HSTS) in configuration or examples. The embed implementation (source/embed/index.html) could be vulnerable to clickjacking and header injection attacks. Fix: undefined
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.