@@ -59,26 +59,6 @@ export class GIFGenerator {
5959 return true ;
6060 }
6161
62- // Count the set (non-zero) bitmap bytes on screen, i.e. how many pixel cells
63- // carry drawn content. The 0x6600 buffer is a 24-row top border, then 192
64- // rows of [16 left-border][32 (bitmap,attr) pairs][16 right-border], then a
65- // 24-row bottom border (see FrameDecoder). Only the bitmap byte of each pair
66- // is counted, so a blank/cleared screen reads ~0 regardless of paper colour,
67- // while text or graphics read higher.
68- private inkBytes ( a : Uint8Array ) : number {
69- let n = 0 ;
70- let p = 24 * 160 ; // skip top border
71- for ( let row = 0 ; row < 192 ; row ++ ) {
72- p += 16 ; // left border
73- for ( let i = 0 ; i < 32 ; i ++ ) {
74- if ( a [ p ] !== 0 ) n ++ ; // bitmap byte
75- p += 2 ; // step over this pair's attribute byte
76- }
77- p += 16 ; // right border
78- }
79- return n ;
80- }
81-
8262 // ZX Spectrum keyboard matrix cells.
8363 private static readonly KEY = {
8464 ENTER : [ 6 , 0x01 ] as [ number , number ] ,
@@ -159,7 +139,6 @@ export class GIFGenerator {
159139 let previousFrame : Uint8Array | null = null ;
160140 let staleCount = 0 ;
161141 let lastChangeIndex = - 1 ;
162- let lastLoadFrame = - 1 ; // last frame in which a tape-load trap fired
163142
164143 for ( let f = 0 ; f < maxFrames ; f ++ ) {
165144 if ( Date . now ( ) > renderDeadline ) {
@@ -173,7 +152,6 @@ export class GIFGenerator {
173152 }
174153 const frameBuffer = new Uint8Array ( this . emulator . runFrame ( ) ) ;
175154 frames . push ( frameBuffer ) ;
176- if ( this . emulator . getTapeTrapsLastFrame ( ) > 0 ) lastLoadFrame = f ;
177155
178156 // Audio activity counts as a change: a tune over a static screen must
179157 // not be cut short, nor its tail trimmed. Kept aligned 1:1 with frames.
@@ -210,48 +188,12 @@ export class GIFGenerator {
210188 return { frames : frames . slice ( 0 , keepStatic ) , audio : audio . slice ( 0 , keepStatic ) } ;
211189 }
212190
213- // Open on the program's first real content, not the ROM editor/loader
214- // pre-roll or the bare cleared screen. Capturing begins at the load
215- // keypress (so no opening draw is ever missed), which leaves the blank
216- // boot screen and the loader's "Program:" header at the head. Tape-load
217- // traps fire only while LOAD pulls blocks in, so the program takes
218- // control on the frame after the last trap. From there a program
219- // typically clears the loader screen (CLS) and then draws: open on the
220- // first frame that carries real drawn pixels after that clear, so the
221- // first frame (and thus the social preview, which is frame 0) shows
222- // content rather than a blank screen.
223- const INK_CONTENT = 16 ; // set bitmap bytes that count as real drawn content
224- const INK_CLEARED = 8 ; // at/below this the screen is effectively blank
225- let start = lastLoadFrame >= 0 ? Math . min ( lastLoadFrame + 1 , lastChangeIndex ) : 0 ;
226- if ( lastLoadFrame >= 0 ) {
227- // Find where the program clears the loader's screen (ink falls to
228- // ~blank) after taking control.
229- let clearedAt = - 1 ;
230- for ( let i = lastLoadFrame + 1 ; i <= lastChangeIndex ; i ++ ) {
231- if ( this . inkBytes ( frames [ i ] ) <= INK_CLEARED ) {
232- clearedAt = i ;
233- break ;
234- }
235- }
236- // Then open on the first frame drawing real content. Searching after
237- // the clear skips the loader header; if the program never clears,
238- // search from the load handoff so the clip still opens on content.
239- const from = clearedAt >= 0 ? clearedAt + 1 : lastLoadFrame + 1 ;
240- for ( let i = from ; i <= lastChangeIndex ; i ++ ) {
241- if ( this . inkBytes ( frames [ i ] ) >= INK_CONTENT ) {
242- start = i ;
243- break ;
244- }
245- }
246- // No content found after the clear (e.g. an audio-only program with a
247- // blank screen): fall back to the cleared frame rather than the
248- // loader header.
249- if ( clearedAt >= 0 && start < clearedAt ) start = clearedAt ;
250- }
251-
191+ // Keep every captured frame from the very first one. The social preview
192+ // is frame 0, so it may show the blank boot/loader screen before the
193+ // program draws, but no opening frames are ever skipped.
252194 const keep = Math . min ( frames . length , lastChangeIndex + 1 + tailFrames ) ;
253- console . log ( `Captured ${ frames . length } frames, keeping ${ start } .. ${ keep } ` ) ;
254- return { frames : frames . slice ( start , keep ) , audio : audio . slice ( start , keep ) } ;
195+ console . log ( `Captured ${ frames . length } frames, keeping ${ keep } ` ) ;
196+ return { frames : frames . slice ( 0 , keep ) , audio : audio . slice ( 0 , keep ) } ;
255197 }
256198
257199 private isAudioSilent ( left : Float32Array , right : Float32Array ) : boolean {
0 commit comments