Commit graph

17 commits

Author SHA1 Message Date
Your Name
94475da936 Project create/list API, clip uploads, CORS, public read
- Project gains a clip FileField; POST /api/projects/ creates one from an
  uploaded otio + clip (<=100 MB), owned by the requester
- add /api/me/ and project-detail; scene GET is public (view without login),
  PUT stays owner/collaborator-only
- serve media in DEBUG (range requests for video seek); CORS for the cljs dev
  origin with credentials
- seed_demo now builds the Challengers project from the bundled otio + 480p clip

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 01:39:54 -04:00
Your Name
60fb4df795 Merge scene saves as per-id deltas instead of clobbering
PUT now takes {changed, deleted} and merges per annotation id, so concurrent
edits to different annotations both survive; same-annotation edits are
last-write-wins by arrival. No version/locking. No-op saves don't write a
revision. Tests cover merge, LWW, stale-client safety, attribution
(server-stamped/spoof-resistant, creator preserved), revisions, and access.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 01:34:52 -04:00
Your Name
36054ac329 Attribute annotations and scene saves to users
Server-authoritative attribution: on each scene PUT the server diffs incoming
annotation groups and stamps createdBy/editedBy (+ timestamps) from request.user,
ignoring client-sent stamps so authorship can't be forged. Each save also writes
a Revision (user, time, +N ~N −N summary, snapshot of the annotation layer),
visible in the admin and via /revisions/. Projects gain collaborators so several
users can edit one project and get distinct attribution.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 00:12:13 -04:00
Your Name
57ef570539 Add Django backend: users, admin, OTIO + scene persistence
A Project (owner, OTIO file, fps, scene JSON) persists the timeline. Session
API: list projects, GET/PUT scene, serve OTIO. Admin manages users/projects;
seed_demo creates a project from the bundled one_two_three.otio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 23:45:49 -04:00
Your Name
7a960afb5c Detect broken child mark-refs; restore the timeline/top divider
- scene: point-frame rejects out-of-range offsets so broken-marks catches
  boundary shifts and cascades, not just deleted refs; add broken-reason
- subs: annotations carry :broken/:reason and sort broken ones to the bottom
- views: ⚠ on broken annotations (hover = reason); drag-resize the top/timeline
  split via --top-h (vh)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 23:45:43 -04:00
Your Name
c03756d3e1 Rebuild annotation editor on the mark-group model
- scene: mark-group model (resolve/selection->marks/seg-local/marks->rows);
  drop legacy tl.marks/tl.md
- authoring: draft is a normal annotation group flagged :draft; generic
  put-group + with-let cancel; two-input click-to-fill editor in mark time
- timeline: dashed draft preview, numeric track ordering
- video frame readout (track+clip, mark time) clickable to fill an endpoint
- discontinuity jump popover; nested-annotation count badge
- localStorage persistence of the authored annotation layer

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28 23:18:07 -04:00
Your Name
9d0302c367 data model added 2026-06-28 14:02:14 -04:00
Your Name
ea181911cb clearing everything starting again basically 2026-06-28 14:02:11 -04:00
Your Name
60d1a641ee feat: broken fixes lol 2026-06-28 09:12:28 -04:00
Your Name
ec236e93cb feat: prev/next frame buttons flanking play
Transport row is now |◀ ▶/⏸ ▶|. step-frame! pauses, rounds the video
clock to the nearest frame and seeks ±1; the rAF clock reports the new
position back into :playhead, so the red line follows (same single
seek-only path as jump/scrub).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:19:02 -04:00
Your Name
ea78a9ee08 fix: video won't seek — playhead clock had no element handle
seek-to-frame! and the rAF clock both reach the <video> through the
shared video-el atom, which was populated by an inline :ref closure —
recreated every render and callable with nil by React, so video-el ended
up nil. That made set! currentTime (jumps + scrubs) and the clock's
currentTime read both silent no-ops: the red line moved (separate
:playhead dispatch) but the picture never seeked or followed.

Capture the element with a stable ref that ignores nil, and collapse the
clock to a single source of truth: one always-on rAF copies currentTime
into :playhead, and jump/scrub only seek (no optimistic :playhead write),
so the line and the picture can't disagree. Replaces the old
push!/tick/stop + on-play/on-pause/on-seeked bookkeeping.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:05:14 -04:00
Your Name
24558b1cae feat: pack annotation lanes into shared rows
The annotation lane above the tracks now collapses non-overlapping
annotations onto a single row. Each annotation is assigned a lane by
greedy first-fit in definition order (:created): it takes the topmost
lane it doesn't time-overlap, so overlapping annotations stack with the
earlier-defined one on top and the newer beneath.

- annotations carry :created (new ones stamp Date.now; seed has explicit
  values; old saved data defaults to 0 = oldest)
- pane order: by start, then longest-first so a section leads a tie
- seed data reworked to overlap (Act I / rally / baseline / glance / net,
  plus an overlapping nested child) so the packing is visible; one-time
  localStorage reset bumped so it lands

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 17:05:05 -04:00
Your Name
30cfbf3a1f feat: expandable annotations with nested timelines
Each annotation can be expanded into its own nested timeline. Reuses the
dormant :timeline-stack: annotations carry a :parent (:root = top level),
expanding pushes the annotation id, and only annotations whose :parent
matches the stack top are surfaced — so nested annotations stay invisible
on the main timeline.

- crop: the expanded annotation's own spans define a time window + the set
  of involved tracks; non-involved tracks collapse to height 0 (CSS-
  transitioned, so tracks animate away and survivors slide up), and the
  view offsets/crops to the window
- breadcrumb bar + back button (shown only when nested) fully restore the
  main timeline
- new annotations attach to the current context; the expand button shows a
  child count and delete removes the whole subtree
- seed data (Opening rally + 2 children, Net-cam beat) for testing, plus a
  one-time localStorage reset so it shows

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-27 16:01:11 -04:00
Your Name
f67baf4b99 claude before limit 2026-06-27 13:07:42 -04:00
Your Name
6ed11fbca5 local storage, mobile improvements, re-frame refactor, etc 2026-06-27 12:56:13 -04:00
Your Name
38367cd052 vaarious fixes 2026-06-27 12:00:43 -04:00
Your Name
bdc9928db8 feat: init 2026-06-27 11:11:20 -04:00