835835 cursor : not-allowed;
836836 background : # 6c757d !important ;
837837 }
838+
839+ .textarea-wrapper {
840+ position : relative;
841+ }
842+
843+ .textarea-watermark {
844+ position : absolute;
845+ top : 12px ;
846+ right : 12px ;
847+ color : # ccc ;
848+ font-size : 0.85em ;
849+ pointer-events : none;
850+ font-family : -apple-system, BlinkMacSystemFont, 'Segoe UI' , Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
851+ font-style : italic;
852+ z-index : 1 ;
853+ }
838854 </ style >
839855</ head >
840856< body >
@@ -848,13 +864,16 @@ <h1>Random Number Validator</h1>
848864 < div class ="help-text " style ="margin-bottom: 8px; ">
849865 Positive integers (commas, spaces, or newlines) or base64 • < a href ="/static/poor-rng.html " style ="color: #9fef00; text-decoration: none; border-bottom: 1px dashed #9fef00; "> Generate test data</ a >
850866 </ div >
851- < textarea
852- id ="numbers "
853- name ="numbers "
854- rows ="5 "
855- placeholder ="Loading... "
856- required
857- > </ textarea >
867+ < div class ="textarea-wrapper ">
868+ < div id ="exampleWatermark " class ="textarea-watermark " style ="display: none; "> example</ div >
869+ < textarea
870+ id ="numbers "
871+ name ="numbers "
872+ rows ="5 "
873+ placeholder ="Loading... "
874+ required
875+ > </ textarea >
876+ </ div >
858877
859878 < div style ="display: flex; justify-content: space-between; align-items: center; margin-top: 10px; ">
860879 < button type ="submit "> Validate Numbers</ button >
@@ -1581,86 +1600,92 @@ <h1>Random Number Validator</h1>
15811600 updateInputStats ( ) ;
15821601 validateInputRealtime ( ) ;
15831602
1584- // Flip-board animation for textbox
1603+ // Flip-board animation for textbox - all numbers visible, digits stabilize left to right
15851604 function startFlipBoardAnimation ( ) {
15861605 const textarea = document . getElementById ( 'numbers' ) ;
1587- const targetCount = 25 ; // Generate 25 random 8-bit numbers
1588- const numbers = [ ] ;
1606+ const watermark = document . getElementById ( 'exampleWatermark' ) ;
1607+ const targetCount = 15 ;
1608+
1609+ // Show watermark
1610+ watermark . style . display = 'block' ;
15891611
1590- // Generate random 8-bit numbers (0-255)
1612+ // Generate target numbers
1613+ const targetNumbers = [ ] ;
15911614 for ( let i = 0 ; i < targetCount ; i ++ ) {
1592- numbers . push ( Math . floor ( Math . random ( ) * 256 ) ) ;
1615+ targetNumbers . push ( Math . floor ( Math . random ( ) * 256 ) ) ;
15931616 }
15941617
1595- let completedNumbers = [ ] ;
1596- let currentIndex = 0 ;
1597-
1598- function animateNumber ( numberValue , callback ) {
1599- const targetStr = numberValue . toString ( ) ;
1600- const numDigits = targetStr . length ;
1601-
1602- // Start fast (15ms), gradually slow to 50ms based on progress
1603- const baseInterval = Math . min ( 15 + currentIndex * 1.3 , 50 ) ;
1604- const cyclesPerDigit = 6 ; // How many flips before each digit settles
1605-
1606- let currentDigitIndex = 0 ;
1607- let cycleCount = 0 ;
1608- let displayDigits = [ ] ;
1618+ // Create display state - array of digit arrays for each number
1619+ const displayState = targetNumbers . map ( num => {
1620+ const targetStr = num . toString ( ) ;
1621+ return targetStr . split ( '' ) . map ( ( ) => Math . floor ( Math . random ( ) * 10 ) . toString ( ) ) ;
1622+ } ) ;
16091623
1610- // Initialize with random digits
1611- for ( let i = 0 ; i < numDigits ; i ++ ) {
1612- displayDigits . push ( Math . floor ( Math . random ( ) * 10 ) . toString ( ) ) ;
1624+ // Build a flat list of digit positions in left-to-right order
1625+ const digitPositions = [ ] ;
1626+ for ( let numIdx = 0 ; numIdx < targetNumbers . length ; numIdx ++ ) {
1627+ for ( let digitIdx = 0 ; digitIdx < displayState [ numIdx ] . length ; digitIdx ++ ) {
1628+ digitPositions . push ( { numIdx, digitIdx } ) ;
16131629 }
1630+ }
16141631
1615- const intervalId = setInterval ( ( ) => {
1616- if ( currentDigitIndex < numDigits ) {
1617- // Cycle all unsettled digits
1618- for ( let i = currentDigitIndex ; i < numDigits ; i ++ ) {
1619- displayDigits [ i ] = Math . floor ( Math . random ( ) * 10 ) . toString ( ) ;
1620- }
1632+ let settledCount = 0 ;
1633+ const totalDigits = digitPositions . length ;
16211634
1622- // Update display
1623- const currentDisplay = displayDigits . join ( '' ) ;
1624- const fullText = [ ...completedNumbers , currentDisplay ] . join ( ', ' ) ;
1625- textarea . value = fullText ;
1635+ // Clear placeholder and show initial random state
1636+ textarea . placeholder = '' ;
1637+ textarea . value = displayState . map ( digits => digits . join ( '' ) ) . join ( ', ' ) ;
1638+
1639+ // Animation loop - settle digits left to right
1640+ let frameCount = 0 ;
1641+ const intervalId = setInterval ( ( ) => {
1642+ // Update all unsettled digits with random values
1643+ for ( let i = settledCount ; i < digitPositions . length ; i ++ ) {
1644+ const { numIdx, digitIdx } = digitPositions [ i ] ;
1645+ displayState [ numIdx ] [ digitIdx ] = Math . floor ( Math . random ( ) * 10 ) . toString ( ) ;
1646+ }
16261647
1627- cycleCount ++ ;
1648+ // Settle digits slower - about every 2 frames to reach ~2 seconds total
1649+ frameCount ++ ;
1650+ if ( frameCount % 2 === 0 && settledCount < totalDigits ) {
1651+ const { numIdx, digitIdx } = digitPositions [ settledCount ] ;
1652+ const targetStr = targetNumbers [ numIdx ] . toString ( ) ;
1653+ displayState [ numIdx ] [ digitIdx ] = targetStr [ digitIdx ] ;
1654+ settledCount ++ ;
1655+ }
16281656
1629- // After enough cycles, settle this digit
1630- if ( cycleCount >= cyclesPerDigit ) {
1631- displayDigits [ currentDigitIndex ] = targetStr [ currentDigitIndex ] ;
1632- currentDigitIndex ++ ;
1633- cycleCount = 0 ;
1634- }
1635- } else {
1636- // All digits settled
1637- clearInterval ( intervalId ) ;
1638- completedNumbers . push ( numberValue ) ;
1639- textarea . value = completedNumbers . join ( ', ' ) ;
1640- callback ( ) ;
1641- }
1642- } , baseInterval ) ;
1643- }
1657+ // Update display
1658+ textarea . value = displayState . map ( digits => digits . join ( '' ) ) . join ( ', ' ) ;
16441659
1645- function animateNext ( ) {
1646- if ( currentIndex >= numbers . length ) {
1647- // Animation complete - update stats
1660+ // Check if complete
1661+ if ( settledCount >= totalDigits ) {
1662+ clearInterval ( intervalId ) ;
16481663 updateInputStats ( ) ;
1649- return ;
16501664 }
1665+ } , 25 ) ; // Run at ~40fps for smooth animation
1666+ }
16511667
1652- animateNumber ( numbers [ currentIndex ] , ( ) => {
1653- currentIndex ++ ;
1654- // Shorter pauses as we progress (faster overall)
1655- const pause = Math . max ( 30 , 150 - currentIndex * 3 ) ;
1656- setTimeout ( animateNext , pause ) ;
1657- } ) ;
1668+ // Clear textbox and hide watermark when user clicks in it
1669+ let hasCleared = false ;
1670+ document . getElementById ( 'numbers' ) . addEventListener ( 'focus' , function ( ) {
1671+ if ( ! hasCleared ) {
1672+ this . value = '' ;
1673+ const watermark = document . getElementById ( 'exampleWatermark' ) ;
1674+ if ( watermark ) {
1675+ watermark . style . display = 'none' ;
1676+ }
1677+ hasCleared = true ;
1678+ updateInputStats ( ) ;
16581679 }
1680+ } ) ;
16591681
1660- // Clear placeholder and start animation
1661- textarea . placeholder = '' ;
1662- animateNext ( ) ;
1663- }
1682+ // Also hide watermark when user starts typing
1683+ document . getElementById ( 'numbers' ) . addEventListener ( 'input' , function ( ) {
1684+ const watermark = document . getElementById ( 'exampleWatermark' ) ;
1685+ if ( watermark ) {
1686+ watermark . style . display = 'none' ;
1687+ }
1688+ } ) ;
16641689
16651690 // Check for pending test data from other pages (e.g., poor-rng generator)
16661691 window . addEventListener ( 'DOMContentLoaded' , ( ) => {
0 commit comments