@@ -10,6 +10,7 @@ import {
1010 createRoot ,
1111 createSignal ,
1212 For ,
13+ Index ,
1314 Match ,
1415 onCleanup ,
1516 Show ,
@@ -188,7 +189,7 @@ export function ClipTrack(
188189 systemAudioWaveforms,
189190 } = useEditorContext ( ) ;
190191
191- const { secsPerPixel, duration } = useTimelineContext ( ) ;
192+ const { secsPerPixel, duration, isSegmentVisible } = useTimelineContext ( ) ;
192193
193194 const segments = ( ) : Array < TimelineSegment > =>
194195 project . timeline ?. segments ?? [ { start : 0 , end : duration ( ) , timescale : 1 } ] ;
@@ -204,6 +205,21 @@ export function ClipTrack(
204205 return offsets ;
205206 } ) ;
206207
208+ const visibleSegmentIndices = createMemo ( ( ) => {
209+ const segs = segments ( ) ;
210+ const offsets = segmentOffsets ( ) ;
211+ const visible : number [ ] = [ ] ;
212+ for ( let i = 0 ; i < segs . length ; i ++ ) {
213+ const seg = segs [ i ] ;
214+ const segStart = offsets [ i ] ;
215+ const segEnd = segStart + ( seg . end - seg . start ) / seg . timescale ;
216+ if ( isSegmentVisible ( segStart , segEnd ) ) {
217+ visible . push ( i ) ;
218+ }
219+ }
220+ return visible ;
221+ } ) ;
222+
207223 function onHandleReleased ( ) {
208224 const { transform } = editorState . timeline ;
209225
@@ -223,8 +239,10 @@ export function ClipTrack(
223239 onMouseEnter = { ( ) => setEditorState ( "timeline" , "hoveredTrack" , "clip" ) }
224240 onMouseLeave = { ( ) => setEditorState ( "timeline" , "hoveredTrack" , null ) }
225241 >
226- < For each = { segments ( ) } >
227- { ( segment , i ) => {
242+ < Index each = { visibleSegmentIndices ( ) } >
243+ { ( segmentIndex ) => {
244+ const i = segmentIndex ;
245+ const segment = ( ) => segments ( ) [ i ( ) ] ;
228246 const [ startHandleDrag , setStartHandleDrag ] = createSignal < null | {
229247 offset : number ;
230248 initialStart : number ;
@@ -235,14 +253,15 @@ export function ClipTrack(
235253 const relativeSegment = createMemo ( ( ) => {
236254 const ds = startHandleDrag ( ) ;
237255 const offset = ds ?. offset ?? 0 ;
256+ const seg = segment ( ) ;
238257
239258 return {
240259 start : Math . max ( prevDuration ( ) + offset , 0 ) ,
241260 end :
242261 prevDuration ( ) +
243- ( offset + ( segment . end - segment . start ) ) / segment . timescale ,
244- timescale : segment . timescale ,
245- recordingSegment : segment . recordingSegment ,
262+ ( offset + ( seg . end - seg . start ) ) / seg . timescale ,
263+ timescale : seg . timescale ,
264+ recordingSegment : seg . recordingSegment ,
246265 } ;
247266 } ) ;
248267
@@ -269,9 +288,10 @@ export function ClipTrack(
269288 const isSelected = createMemo ( ( ) => {
270289 const selection = editorState . timeline . selection ;
271290 if ( ! selection || selection . type !== "clip" ) return false ;
291+ const seg = segment ( ) ;
272292
273293 const segmentIndex = project . timeline ?. segments ?. findIndex (
274- ( s ) => s . start === segment . start && s . end === segment . end ,
294+ ( s ) => s . start === seg . start && s . end === seg . end ,
275295 ) ;
276296
277297 if ( segmentIndex === undefined || segmentIndex === - 1 ) return false ;
@@ -283,7 +303,7 @@ export function ClipTrack(
283303 if ( project . audio . micVolumeDb && project . audio . micVolumeDb < - 30 )
284304 return ;
285305
286- const idx = segment . recordingSegment ?? i ( ) ;
306+ const idx = segment ( ) . recordingSegment ?? i ( ) ;
287307 return micWaveforms ( ) ?. [ idx ] ?? [ ] ;
288308 } ;
289309
@@ -294,7 +314,7 @@ export function ClipTrack(
294314 )
295315 return ;
296316
297- const idx = segment . recordingSegment ?? i ( ) ;
317+ const idx = segment ( ) . recordingSegment ?? i ( ) ;
298318 return systemAudioWaveforms ( ) ?. [ idx ] ?? [ ] ;
299319 } ;
300320
@@ -401,8 +421,9 @@ export function ClipTrack(
401421 if ( editorState . timeline . interactMode === "split" ) {
402422 const rect = e . currentTarget . getBoundingClientRect ( ) ;
403423 const fraction = ( e . clientX - rect . left ) / rect . width ;
424+ const seg = segment ( ) ;
404425
405- const splitTime = fraction * ( segment . end - segment . start ) ;
426+ const splitTime = fraction * ( seg . end - seg . start ) ;
406427
407428 projectActions . splitClipSegment ( prevDuration ( ) + splitTime ) ;
408429 } else {
@@ -486,41 +507,41 @@ export function ClipTrack(
486507 }
487508 } }
488509 >
489- { segment . timescale === 1 && (
510+ { segment ( ) . timescale === 1 && (
490511 < WaveformCanvas
491512 micWaveform = { micWaveform ( ) }
492513 systemWaveform = { systemAudioWaveform ( ) }
493- segment = { segment }
514+ segment = { segment ( ) }
494515 />
495516 ) }
496517
497- < Markings segment = { segment } prevDuration = { prevDuration ( ) } />
518+ < Markings segment = { segment ( ) } prevDuration = { prevDuration ( ) } />
498519
499520 < SegmentHandle
500521 position = "start"
501522 class = "opacity-0 group-hover:opacity-100"
502523 onMouseDown = { ( downEvent ) => {
503524 if ( split ( ) ) return ;
525+ const seg = segment ( ) ;
504526
505- const initialStart = segment . start ;
527+ const initialStart = seg . start ;
506528 setStartHandleDrag ( {
507529 offset : 0 ,
508530 initialStart,
509531 } ) ;
510532
511533 const maxSegmentDuration =
512534 editorInstance . recordings . segments [
513- segment . recordingSegment ?? 0
535+ seg . recordingSegment ?? 0
514536 ] . display . duration ;
515537
516538 const availableTimelineDuration =
517539 editorInstance . recordingDuration -
518540 segments ( ) . reduce (
519- ( acc , segment , segmentI ) =>
541+ ( acc , s , segmentI ) =>
520542 segmentI === i ( )
521543 ? acc
522- : acc +
523- ( segment . end - segment . start ) / segment . timescale ,
544+ : acc + ( s . end - s . start ) / s . timescale ,
524545 0 ,
525546 ) ;
526547
@@ -532,24 +553,23 @@ export function ClipTrack(
532553 const prevSegment = segments ( ) [ i ( ) - 1 ] ;
533554 const prevSegmentIsSameClip =
534555 prevSegment ?. recordingSegment !== undefined
535- ? prevSegment . recordingSegment ===
536- segment . recordingSegment
556+ ? prevSegment . recordingSegment === seg . recordingSegment
537557 : false ;
538558
539559 function update ( event : MouseEvent ) {
540560 const newStart =
541561 initialStart +
542562 ( event . clientX - downEvent . clientX ) *
543563 secsPerPixel ( ) *
544- segment . timescale ;
564+ seg . timescale ;
545565
546566 const clampedStart = Math . min (
547567 Math . max (
548568 newStart ,
549569 prevSegmentIsSameClip ? prevSegment . end : 0 ,
550- segment . end - maxDuration ,
570+ seg . end - maxDuration ,
551571 ) ,
552- segment . end - 1 ,
572+ seg . end - 1 ,
553573 ) ;
554574
555575 setStartHandleDrag ( {
@@ -590,22 +610,23 @@ export function ClipTrack(
590610 < SegmentContent class = "relative justify-center items-center" >
591611 { ( ( ) => {
592612 const ctx = useSegmentContext ( ) ;
613+ const seg = segment ( ) ;
593614
594615 return (
595616 < Show when = { ctx . width ( ) > 100 } >
596617 < div class = "flex flex-col gap-1 justify-center items-center text-xs whitespace-nowrap text-gray-12" >
597618 < span class = "text-white/70" >
598619 { hasMultipleRecordingSegments ( )
599- ? `Clip ${ segment . recordingSegment } `
620+ ? `Clip ${ seg . recordingSegment } `
600621 : "Clip" }
601622 </ span >
602623 < div class = "flex gap-1 items-center text-md dark:text-gray-12 text-gray-1" >
603624 < IconLucideClock class = "size-3.5" /> { " " }
604- { formatTime ( segment . end - segment . start ) }
605- < Show when = { segment . timescale !== 1 } >
625+ { formatTime ( seg . end - seg . start ) }
626+ < Show when = { seg . timescale !== 1 } >
606627 < div class = "w-0.5" />
607628 < IconLucideFastForward class = "size-3" />
608- { segment . timescale } x
629+ { seg . timescale } x
609630 </ Show >
610631 </ div >
611632 </ div >
@@ -617,37 +638,36 @@ export function ClipTrack(
617638 position = "end"
618639 class = "opacity-0 group-hover:opacity-100"
619640 onMouseDown = { ( downEvent ) => {
620- const end = segment . end ;
641+ const seg = segment ( ) ;
642+ const end = seg . end ;
621643
622644 if ( split ( ) ) return ;
623645 const maxSegmentDuration =
624646 editorInstance . recordings . segments [
625- segment . recordingSegment ?? 0
647+ seg . recordingSegment ?? 0
626648 ] . display . duration ;
627649
628650 const availableTimelineDuration =
629651 editorInstance . recordingDuration -
630652 segments ( ) . reduce (
631- ( acc , segment , segmentI ) =>
653+ ( acc , s , segmentI ) =>
632654 segmentI === i ( )
633655 ? acc
634- : acc +
635- ( segment . end - segment . start ) / segment . timescale ,
656+ : acc + ( s . end - s . start ) / s . timescale ,
636657 0 ,
637658 ) ;
638659
639660 const nextSegment = segments ( ) [ i ( ) + 1 ] ;
640661 const nextSegmentIsSameClip =
641662 nextSegment ?. recordingSegment !== undefined
642- ? nextSegment . recordingSegment ===
643- segment . recordingSegment
663+ ? nextSegment . recordingSegment === seg . recordingSegment
644664 : false ;
645665
646666 function update ( event : MouseEvent ) {
647667 const deltaRecorded =
648668 ( event . clientX - downEvent . clientX ) *
649669 secsPerPixel ( ) *
650- segment . timescale ;
670+ seg . timescale ;
651671 const newEnd = end + deltaRecorded ;
652672
653673 setProject (
@@ -658,13 +678,12 @@ export function ClipTrack(
658678 Math . max (
659679 Math . min (
660680 newEnd ,
661- // availableTimelineDuration is in timeline seconds; convert to recorded seconds
662- end + availableTimelineDuration * segment . timescale ,
681+ end + availableTimelineDuration * seg . timescale ,
663682 nextSegmentIsSameClip
664683 ? nextSegment . start
665684 : maxSegmentDuration ,
666685 ) ,
667- segment . start + 1 ,
686+ seg . start + 1 ,
668687 ) ,
669688 ) ;
670689 }
@@ -737,7 +756,7 @@ export function ClipTrack(
737756 </ >
738757 ) ;
739758 } }
740- </ For >
759+ </ Index >
741760 </ TrackRoot >
742761 ) ;
743762}
0 commit comments