Skip to content

Add Church History Timeline 2.0 with depth layering and parallax - #153

Open
hawkandheron-dev wants to merge 2 commits into
mainfrom
claude/ch-timeline-2-redesign-jwewvc
Open

Add Church History Timeline 2.0 with depth layering and parallax#153
hawkandheron-dev wants to merge 2 commits into
mainfrom
claude/ch-timeline-2-redesign-jwewvc

Conversation

@hawkandheron-dev

Copy link
Copy Markdown
Owner

Summary

This PR introduces Church History Timeline 2.0, a new unified timeline application that merges the Church History and Heresies timelines into a single view with a sophisticated depth-layering system. The background layer (emperors, heresiarchs, movements, and events) is rendered as a blurred watercolour wash by default and comes into focus when a foreground figure is selected, revealing their contextual background without cluttering the main view.

Key Changes

  • New CH Timeline 2.0 App (ChurchHistory2App.jsx): Main application component with authentication, tour support, and depth-focus management

    • Integrates Clerk authentication with role-based access (admin/contributor)
    • Manages two-layer dataset (front/back) with independent filter sets
    • Supports tour mode with scene-based navigation
    • Provides note-taking and suggestion features for authenticated users
  • Data Adapter (churchHistory2Adapter.js): Unified Supabase adapter combining Church History and Heresies data sources

    • Fetches and transforms people, events, movements, connections, and sources
    • Implements layer assignment logic (background roles: heresiarchs, contested figures, emperors)
    • Builds comprehensive index maps for focus set computation
    • Re-exports tour and media functionality from existing adapters
  • Depth Layering System (DepthLayers.jsx): Two-canvas rendering for background layer

    • Watercolour wash canvas with blur, desaturation, and opacity filters
    • Focus overlay canvas for crisp rendering of related background items
    • Smooth transitions between depth modes (hidden/watercolour/forward)
    • Supports both hover preview and click-lock focus interactions
  • Focus Set Computation (focusSet.js): Determines which background items relate to a selected foreground figure

    • Four sources of belonging: direct connections, movement participation, event attendance, reign overlap
    • Efficiently computes transitive relationships through the index maps
  • Era System (churchHistory2Eras.js): Date-derived era assignment replacing database-stored values

    • Contiguous, half-open era ranges from Apostolic period through modern era
    • Enables era scheme changes without database migrations
    • Provides era lookup by year and by ID
  • Parallax Field (ParallaxField.jsx): Depth-cue background using layered grey rules

    • Three strata of vertical rules moving at different speeds during pan
    • Replaces the manuscript photograph from 1.0 with a lightweight gradient-based approach
    • Creates visual depth without texture or image downloads
  • Configuration (churchHistory2Data.js): Presentation config for the new timeline

    • White-ground palette overrides (vs. parchment in other apps)
    • Back-layer styling for emperors, heresiarchs, movements, councils, documents, events
    • Depth effect parameters (blur, opacity, saturation, scale)
    • Separate filter key sets for front and back layers
  • Timeline Component Updates: Extended Timeline.jsx and TimelineCanvas.jsx to support:

    • Optional background data layer rendering
    • Depth mode control and focus ID filtering
    • Palette customization for white-ground rendering
    • Y-offset registration for multi-layer alignment
    • Layer-specific rendering modes (front axis/labels vs. back markers/washes)
  • Detail Panel Variant (TimelineModal.jsx): New 'panel' layout option

    • Docks detail panel beside timeline instead of modal overlay
    • Allows background layer to remain visible and interactive while reading details
    • Flex-based layout integration with timeline container
  • Legend Updates (TimelineLegend.jsx): Support for two independent filter sets

    • Separate sections for era filters (front layer) and background item filters
    • Section headings to organize the expanded legend
  • Testing: Comprehensive test coverage

    • E2E smoke tests (church-history-2.spec.js) with minimal fixture data
    • Unit tests for focus set computation (church-history-2-focus.test.js)
    • Unit tests for era assignment boundaries (church-history-2-eras.test.js)

https://claude.ai/code/session_01U7bEJazMWsAznBk65t9ei1

The Church History and Heresies timelines are two pages over the same CH_
tables, rendered by the same Timeline component and differing only in adapter
and config. Between them they put 258 people, 85 events, 20 movements and 9
era brackets on one screen over a manuscript photograph — too dense to read,
and split so that following Athanasius means changing pages to see the Arian
crisis he was fighting.

CH Timeline 2.0 is a third page that keeps the data, the tour, the overlapping
lifespans, the drilldown and the Cormorant / Alegreya Sans type, and changes
three things:

  * White ground. The photograph is replaced by strata of grey rules that
    drift at different fractions of the pan.
  * No period brackets. Eras survive as colour only, remapped from the old
    scheme to the conventional historical periods and derived from dates
    rather than read from CH_People.era_id — so no migration.
  * Depth. Emperors, heresiarchs, contested figures, movements and every
    event move to a watercolour layer behind the main figures, and come into
    focus for the person being read: their connections, their movements,
    their councils, and the emperors who reigned in their lifetime.

Because the drilldown has to stay readable while that background is in focus,
TimelineModal gains a docked side-panel variant and the detail now renders
outside .timeline-container, so panel and timeline are flex siblings and the
timeline narrows rather than being covered.

Every change to shared code is opt-in behind a new prop or a defaulted
argument, so the two existing pages render exactly as before; both gain a link
across, and 2.0 joins the site nav.

Three defects found by rendering the real dataset rather than a fixture:

  * Point stacking sized its collision boxes for the HTML callout each point
    renders. A layer drawing bare markers inherited that ~360-year box and
    stacked 85 events into dozens of rows — a cascade off the bottom of the
    screen. stackPoints takes a markerWidth for label-less layers.
  * Scaling the background's pan offset to fake a parallax silently
    unregistered the two axes, sliding the background's axis (1-k)*panOffsetY
    away from the foreground's. The CSS scale about the shared axis already
    carries the foreshortening honestly; the pan multiplier is gone.
  * Movements sat below the axis, stranding an empty band between the axis
    and the reigns everywhere outside the fourth century. They now sit above
    it, behind the figures they were currents among.

Tests: 34 unit (eras, focus sets, point stacking) and 7 e2e covering the white
ground, the remapped legend, the blurred background, the depth control and the
docked panel. The tour was walked scene for scene against both pages and is
identical.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cd1a53d4d4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

{ id: 'forward', label: 'Front', title: 'Bring the whole background into focus — or hold Alt' },
];

export const Timeline = forwardRef(function Timeline({ data, config, onViewportChange, onItemClick, suppressModal = false, authContext, allPeople, adminContext, contributorContext, onEntityUpdated, onDataChanged, showBackgroundImage = false, layoutSizes, animatingIds, animatingPointIds, hideLegend = false, isTourMode = false, backData, focusIds, depthMode, isFocusPreview = false, detailVariant = 'modal', onPersonHover, onPersonSelect, onDepthModeChange }, ref) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include the background dataset on mobile

When useMobileDetect() is true, the early return passes only data to MobileTimeline and drops the newly accepted backData prop. Because this adapter deliberately puts every event, movement, emperor, heresiarch, and contested figure in backData, mobile users receive only the foreground lifespans rather than the unified timeline; flatten both layers for the mobile swimlane even if depth effects remain desktop-only.

Useful? React with 👍 / 👎.

Comment on lines +196 to +198
const filteredBackData = useMemo(
() => (backData ? applyFilters(backData, filters) : null),
[backData, filters]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Include background items in year summaries

Although the background is filtered here, getYearSummary() later reads only filteredData, so every CH 2.0 summary omits all events, councils, documents, movements, and reigning monarchs. This also breaks the bundled year-530 tour scene, whose narrative explicitly opens the summary to show the reigning monarch and nearby events; merge filteredBackData into the summary inputs.

Useful? React with 👍 / 👎.

Comment on lines +78 to +79
transform: `scale(${scale})`,
transformOrigin: `50% ${axisScreenY}px`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve the background layer's horizontal time alignment

In watercolour and hover modes, CSS scale(...) scales both axes, despite the depth configuration requiring vertical foreshortening only. Consequently, background dates are compressed toward the viewport center—for example, at the configured 0.965 scale an item near a 1400px viewport edge shifts about 25px away from its foreground year—and the focus overlay repeats the same transform; use a Y-only transform so background reigns and events remain time-aligned.

Useful? React with 👍 / 👎.

if (!suppressModal) {
setSelectedItem({ type, item });
}
onPersonSelect?.(type === 'person' ? item?.id ?? null : null, type, item);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update depth focus when navigating within the detail panel

This updates depth focus for direct canvas clicks, but connection and reference pills navigate through handleModalItemSelect, which only replaces selectedItem. After opening person A and selecting person B—or an event—from the docked panel, the panel shows the new item while the canvas remains focused on A's background; route modal selections through the same onPersonSelect update, clearing focus for non-person items.

Useful? React with 👍 / 👎.

The deployed page threw on load:

  @clerk/clerk-react: useAuth can only be used within the <ClerkProvider />
  component.

ChurchHistory2App is a fork of ChurchHistorySupabaseApp, which renders its
Clerk-aware branch — and so calls useAuth — whenever a publishable key is
present. That branch needs a provider above it. main-church-history-supabase.jsx
supplies one; main-church-history-2.jsx was copied from main-church-history.jsx,
which mounts the provider-free ChurchHistoryApp, so it had none.

The entry point now mirrors the Supabase one, gating on the same two globals
the app reads. If those conditions ever diverge the app throws, so a test
asserts they stay in step.

Nothing caught this because every e2e case passed `clerkKey: ''`, leaving
`hasClerk` false and rendering only the unauthenticated branch. The suite
exercised one half of a fork and never the half that ships. Two additions
close that gap:

  * tests/unit/clerk-provider-wiring.test.js — a static invariant over every
    src/main-*.jsx: an entry point mounting an app that touches Clerk context
    must import ClerkProvider. Verified to fail on the broken entry point,
    naming it and the app it mounts.
  * A case in the 2.0 e2e spec that loads with a key present and asserts the
    canvas renders with no missing-provider error. Also verified against the
    broken build, where it reproduces the reported error exactly.

Audited all thirteen entry points against the invariant: no other instance.
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 20, 2026

Copy link
Copy Markdown

Deploying profile-site with  Cloudflare Pages  Cloudflare Pages

Latest commit: 4ee3fc5
Status: ✅  Deploy successful!
Preview URL: https://dec98530.profile-site-bgf.pages.dev
Branch Preview URL: https://claude-ch-timeline-2-redesig.profile-site-bgf.pages.dev

View logs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants