டைப்ரைட்டர் விளைவு (typewriter effect) என்பது ஒருவர் சத்தமாகச் சிந்திப்பதைப் பார்ப்பதற்கு இணையான ஒரு டிஜிட்டல் அனுபவமாகும். ஒரு நிஜமான கை உண்மையான விசைகளை அழுத்துவது போல, உரை ஒவ்வொரு எழுத்தாகத் தோன்றும். இதை நீங்கள் போர்ட்ஃபோலியோ தளங்களின் ஹீரோ செக்ஷன்களிலும் (hero sections), பிரவுசர் சார்ந்த டெர்மினல் எமுலேட்டர்களிலும் (terminal emulators), மற்றும் ஒரு முன்கூட்டியே தயார் செய்யப்பட்ட உரையைத் தருவதற்குப் பதிலாக, தாங்கள் பதிலைத் "தட்டச்சு" செய்கிறோம் என்பதை நிரூபிக்க விரும்பும் AI உதவியாளர்களின் சாட் விண்டோக்களிலும் காணலாம். இது சரியாகச் செய்யப்பட்டால், ஒரு எதிர்பார்ப்பை உருவாக்குகிறது. தவறாகச் செய்யப்பட்டால், 1987-ல் சிக்கிக்கொண்ட ஒரு பிரிண்டரைப் போலத் தோன்றும்.

இந்த முறை ஏன் இன்றும் தொடர்கிறது

கணினிகள் தகவல்களை உடனடியாக வழங்குகின்றன. மனிதர்கள் அவ்வாறு செய்வதில்லை. அந்த இரண்டு வேகங்களுக்கு இடையிலான இடைவெளி பயனுள்ளது. டைப்ரைட்டர் விளைவு மனித வேகத்தைப் பிரதிபலிப்பதன் மூலம் அந்த இடைவெளியைக் குறைக்கிறது. ஒரு லேண்டிங் பக்கத்தில் (landing page), இது ஒரு தலைப்பை வார்த்தை வார்த்தையாகக் கண்ணைக் கவரும் வகையில் காட்டுவதால், பார்வையாளர்கள் மேலோட்டமாகப் பார்ப்பதற்குப் பதிலாக அதன் மதிப்பு முன்மொழிவை (value proposition) உண்மையில் வாசிக்கிறார்கள். ஒரு டெர்மினல் எமுலேட்டரில், கட்டளைகள் நிகழ்நேரத்தில் (real time) செயல்படுகின்றன என்ற மாயையை இது உருவாக்குகிறது. ஒரு சாட்பாட் இடைமுகத்தில், பதில் ஒரு தரவுத்தளத்திலிருந்து எடுக்கப்படுவதை விட, உடனுக்குடன் உருவாக்கப்படுகிறது என்பதை அதன் தாளம் (rhythm) உணர்த்துகிறது.

ஆனால், இந்தச் செயல்பாடு பயனரை மதிக்கின்ற போது மட்டுமே வேலை செய்யும். ஒரே மாதிரியான இடைவெளிகளுடன் மெட்ரோனோம் போலத் தொடர்ச்சியாகத் தட்டச்சு செய்வது இயந்திரத்தனமாகத் தோன்றும். அதைவிட மோசமாக, உதவித் தொழில்நுட்பங்களை (assistive technology) புறக்கணிக்கும் ஒரு செயல்படுத்தல், ஒரு வேடிக்கையான காட்சி அலங்காரத்தை எரிச்சலூட்டும் தடையாக மாற்றிவிடும். பயனர் செயல்படுவதைத் தடுப்பதே இலக்கல்ல; மாறாக, இடைமுகம் உயிரோட்டமாகத் தெரிவதற்குத் தேவையான அளவு சிறியத் தாமதத்தைச் (friction) சேர்ப்பதே இதன் நோக்கமாகும்.

Recursive setTimeout மூலம் இதை உருவாக்குங்கள்

setTimeout-இல் தொடங்குங்கள், setInterval-ஐத் தொடாதீர்கள். இதன் வித்தியாசம் நீங்கள் நினைப்பதை விட முக்கியமானது.

setInterval பிடிவாதமானது. உங்கள் ஸ்கிரிப்ட் அல்லது பிரவுசரின் மெயின் த்ரெட்டில் (main thread) என்ன நடந்தாலும் அது ஒவ்வொரு n மில்லிசெகண்டிற்கும் இயங்கும். உங்கள் லாஜிக்கிற்கு சாதாரண தட்டச்சுக்கு இடையில் 50 மில்லிசெகண்ட் இடைவெளியும், நிறுத்தற்குறிகளுக்குப் பிறகு 150 மில்லிசெகண்ட் இடைவெளியும் தேவைப்பட்டால், setInterval-ஆல் அதை மாற்றியமைக்க முடியாது. இறுதியில் நீங்கள் கூடுதல் நிபந்தனை லாஜிக்கைப் பயன்படுத்த வேண்டியிருக்கும், ரேஸ் கண்டிஷன்களை (race conditions) எதிர்கொள்ள வேண்டியிருக்கும், மேலும் இன்டர்வலைத் அடிக்கடி கிளியர் செய்து ரீசெட் செய்ய வேண்டியிருக்கும், இது குறியீட்டை ஒரு சிக்கலான நிலை மேலாண்மை (state-management) nightmares ஆக மாற்றிவிடும். மாறக்கூடிய வேகங்கள் தேவைப்படும்போது நிலையான இடைவெளிகள் (fixed intervals) தோல்வியடையும்.

தொடர்ச்சியான (Recursive) setTimeout ஒவ்வொரு படிநிலையும் அடுத்த படிநிலையின் விதிகளையே தீர்மானிக்க அனுமதிப்பதன் மூலம் இதைச் சரிசெய்கிறது. இதை ஒரு சிறிய ஸ்டேட் மெஷின் (state machine) என்று நினைத்துக் கொள்ளுங்கள். நீங்கள் சில மாறிகளைப் பராமரிக்கிறீர்கள்: தற்போதைய ஸ்டிரிங், தற்போதைய எழுத்தின் குறியீடு (index), நீங்கள் தட்டச்சு செய்கிறீர்களா அல்லது நீக்குகிறீர்களா என்பதற்கான ஒரு பூலியன் ஃபிளாக் (boolean flag), மற்றும் பல ஸ்டிரிங்க்கள் வழியாகச் சுழல ஒரு textIndex கவுண்டர். இந்தச் செயல்பாடு ஒரு எழுத்தைச் சேர்க்கிறது, வாக்கியத்தில் அது எங்குள்ளது என்பதைச் சரிபார்க்கிறது, பின்னர் சூழலுக்குப் பொருத்தமான தாமதத்துடன் தனது அடுத்த அழைப்பைத் திட்டமிடுகிறது.

உதாரணமாக, நீங்கள் பெரும்பாலான எழுத்துக்களை 50 மில்லிசெகண்டிலும், ஒரு கமாவுக்குப் பிறகு 150 மில்லிசெகண்டிலும், ஒரு முழு வாக்கியத்தின் முடிவில் நீக்கும் முறைக்கு (delete mode) மாறுவதற்கு முன்பு 800 மில்லிசெகண்டிலும் தட்டச்சு செய்யலாம். இதை setInterval மூலம் சுத்தமாகச் செய்ய முடியாது. Recursive setTimeout-இல், லாஜிக் மிகவும் எளிமையானது:

if typing:
  append next character
  if at end of string:
    switch to pause mode
    schedule next call after 1000ms
if deleting:
  remove last character
  if string empty:
    increment textIndex
    load next string
    switch to typing mode

இந்த அமைப்பு சுத்தம் செய்வதையும் (cleanup) எளிதாக்குகிறது. timeout ID-யைச் சேமித்து வையுங்கள். காம்பொனென்ட் அன்மவுண்ட் (unmount) ஆகும்போது அல்லது பயனர் வேறு பக்கத்திற்குச் செல்லும்போது, ஒருமுறை clearTimeout-ஐ அழைக்கவும். பின்னணியில் இயங்கிக்கொண்டிருக்கும் தேவையற்ற இன்டர்வல்கள் (orphaned intervals) இருக்காது.

கர்சர் தானாகவே மின்ன வேண்டும்

மின்னும் கர்சர் என்பது ஒரு காட்சித் தேவை மட்டுமே, அது தரவு சார்ந்த விஷயம் அல்ல. அதை உங்கள் ஜாவாஸ்கிரிப்ட் ஸ்டேட் என்ஜினில் (JavaScript state engine) வைக்காதீர்கள். ஒரு ::after சூடோ-எலிமெண்டிற்கு (pseudo-element) இணைக்கப்பட்ட தனித்த CSS அனிமேஷன் அல்லது உங்கள் உரை கொள்கலனின் (text container) இறுதியில் இருக்கும் ஒரு பிரத்யேக <span> ஐப் பயன்படுத்துங்கள்.

@keyframes blink மூலம் opacity அல்லது border-color-ஐ step-end டைமிங்குடன் மாற்றுவது, காம்போசிட்டரில் (compositor) இயங்கும் ஒரு தெளிவான மற்றும் ஹார்டுவேர்-நட்பான துடிப்பை உங்களுக்கு வழங்கும். கர்சர் தெரிவதைக் கட்டுப்படுத்துவது ஜாவாஸ்கிரிப்ட்டின் வேலை அல்ல. உங்கள் setTimeout தொடர்ச்சியிலிருந்து டிஸ்ப்ளே பண்புகளை மாற்றினால், ஒவ்வொரு எழுத்தின் போதும் தேவையற்ற ஸ்டைல் மறுகணக்கீடுகளை (style recalculations) நீங்கள் கட்டாயப்படுத்துகிறீர்கள். அழகியலை CSS கவனித்துக் கொள்ளட்டும். வரிசையை ஜாவாஸ்கிரிப்ட் கவனித்துக் கொள்ளட்டும்.

textIndex கவுண்டரைப் பயன்படுத்தி பல ஸ்டிரிங்க்கள் வழியாகச் சுழல்வது எளிது. உங்கள் ஸ்டிரிங்க்களை ஒரு அரேவில் (array) சேமிக்கவும். அனிமேஷன் அதன் நீக்கும் கட்டத்தை முடித்து, கொள்கலன் காலியாக இருக்கும்போது, அரே நீளத்தின் மாடுலோ (modulo) மதிப்பைக் கொண்டு textIndex-ஐ அதிகரிக்கவும், எழுத்து குறியீட்டை பூஜ்ஜியத்திற்கு ரீசெட் செய்யவும், மீண்டும் தட்டச்சு செய்யத் தொடங்கவும். போர்ட்ஃபோலியோ தளங்கள் பக்கத்தை ரீலோட் செய்யாமலேயே தங்கள் பங்குகளை—["Developer", "Designer", "Writer"]—இவ்வாறுதான் சுழற்சி முறையில் காட்டுகின்றன.

மாயையைச் சிதைக்கும் தவறுகள்

அமெச்சூர் (amateur) முறையில் செய்யப்படும் செயல்பாடுகளில் மூன்று தவறுகள் மீண்டும் மீண்டும் வருகின்றன.

setInterval-ஐப் பயன்படுத்துதல். நாம் ஏற்கனவே மாறுபடும் வேகப் பிரச்சனை பற்றிப் பார்த்துள்ளோம், ஆனால் இதில் ஒரு நுணுக்கமான சிக்கலும் உள்ளது. உங்கள் DOM புதுப்பிப்பு எப்போதாவது தாமதமானால்—உதாரணமாக, பிரவுசர் ஒரு லேஅவுட் மாற்றத்தை (layout shift) உருவாக்கும்போது—setInterval தொடர்ந்து இயங்கிக்கொண்டே இருக்கும். இதனால் ஒன்றன் மேல் ஒன்று எழுதுதல், நகல் எழுத்துக்கள் அல்லது பிரவுசர் திரையில் காண்பிக்கும் வேகத்தை விட வேகமாக எழுத்துக்கள் தோன்றுதல் போன்ற சிக்கல்கள் ஏற்படலாம். Recursive setTimeout என்பது அடுத்த கட்டத்திற்குச் செல்வதற்கு முன், தற்போதைய கட்டம் முடிவடையும் வரை காத்திருக்கும்.

HTML-ஐ escape செய்ய மறப்பது. உங்கள் மூலத் தொடர்களில் (source strings) கோண அடைப்புக்குறிகள் இருந்தால், மேலும் நீங்கள் innerHTML-ஐப் பயன்படுத்தி ஒவ்வொரு எழுத்தாக உள்ளடக்கத்தைச் செலுத்தினால், டேக்குகள் (tags) பாதியாகப் பிரிக்கப்படும். பிரவுசர் முதலில் <, பிறகு <s, பிறகு <st எனப் பார்க்கும். இது சரியான டேக் பார்சிங்கைத் (tag parsing) தடுப்பதோடு, சிதைந்த DOM நோட்கள் அல்லது எதிர்பாராத ஸ்டைலிங் மாற்றங்களை ஏற்படுத்தலாம். நீங்கள் அந்த எழுத்துக்களை அப்படியே காட்ட விரும்பினால், முதலில் அவற்றை escape செய்யுங்கள் அல்லது innerHTML-க்கு பதிலாக textContent-ஐப் பயன்படுத்துங்கள். டைப்ரைட்டர் வெளியீட்டில் உங்களுக்கு ஸ்டைல் செய்யப்பட்ட <span> டேக்குகள் தேவைப்பட்டால், எழுத்துக்களைத் தொடங்குவதற்கு முன்பே அந்தத் தொடரில் டேக்குகள் எங்கு தொடங்குகின்றன மற்றும் எங்கு முடிகின்றன என்பதைத் தீர்மானித்து, அந்தத் தொடரைத் தயார் செய்து கொள்ளுங்கள் (pre-process).

அணுகல்தன்மையை (accessibility) புறக்கணித்தல். ஸ்கிரீன் ரீடர்கள் ஒவ்வொரு எழுத்தாகப் படிக்கப்படுவதை விரும்புவதில்லை. உங்கள் ஸ்கிரிப்ட் ஒவ்வொரு புதிய எழுத்தையும் DOM-இல் சேர்க்கும்போது, சில உதவித் தொழில்நுட்பங்கள் முழு நோட்டையும் மீண்டும் அறிவிக்கும், இது துண்டு துண்டான வார்த்தைகளின் தொடர்ச்சியான சத்தத்தை ஏற்படுத்தும். கேட்டல் வழி வழிசெலுத்தலை (auditory navigation) நம்பியிருப்பவர்களுக்கு இது ஒரு nightmare போன்றது. இதற்குத் தீர்வு சிக்கலானது அல்ல: முழுமையான இறுதி உரையைத் தாங்கியுள்ள கண்டெய்னருக்கு (container) ஒரு aria-label-ஐச் சேர்க்கவும். மேலும், aria-hidden="true" மூலம் அனிமேஷன் செய்யப்படும் உறுப்பை உதவித் தொழில்நுட்பத்திடமிருந்து முழுமையாக மறைத்துவிட்டு, ஸ்கிரீன் ரீடர்களுக்காகத் திரையில் தெரியாத ஒரு நிலையான நகலை (visually hidden static copy) வழங்கலாம். எதுவாக இருந்தாலும், பயனர்களை உங்கள் அனிமேஷனைப் பார்க்கக் கட்டாயப்படுத்துவதற்குப் பதிலாக, முழு வாக்கியத்தையும் முன்னரே வழங்கவும்.

உங்கள் பதிப்பை மெருகூட்டும் வழிகள்

ஒருமுறை முக்கிய லூப் (core loop) சரியாகச் செயல்படத் தொடங்கியதும், நீங்கள் கூடுதல் அம்சங்களைச் சேர்க்கலாம். ஆனால் அடிப்படைகள் உறுதியாக இருக்கும் வரை அவற்றைச் சேர்க்கும் தூண்டுதலைத் தவிர்க்கவும்.

கீஸ்டிரோக் ஒலி விளைவுகள். ஒவ்வொரு எழுத்துக்கும் ஒரு மெல்லிய கிளிக் சத்தம் திருப்திகரமாக இருக்கலாம், ஆனால் இணையதளங்களில் ஆடியோவைப் பயன்படுத்துவது சவாலானது. Web Audio API அல்லது சிறிய பஃபர் (buffer) கொண்ட ஒரு இலகுவான Audio உறுப்பைப் பயன்படுத்தவும். ஒலிகள் செயற்கையாகத் தெரியாமல் இருக்க, பிளேபேக் ரேட்டை (playback rate) 0.95 முதல் 1.05 வரை சற்று மாற்றியமைக்கவும். எப்போதும் பிரவுசரின் autoplay கொள்கைகளை மதித்து, ஒரு மியூட் (mute) வசதியையும் வழங்கவும். காலை 9 மணிக்கு ஒரு போர்ட்ஃபோலியோ பக்கத்தில் தானாகவே டைப்பிங் சத்தங்கள் ஒலிப்பது பயனர்களை விரைவாகத் தள்ளிவிடும்.

பல வரி டைப்பிங். உண்மையான டெர்மினல் விண்டோக்கள் வரிகளைத் தாண்டிச் செல்லும் (wrap). உங்கள் உரை ஒரு வரி முறிவைக் (line break) கடந்து சென்றால், உங்கள் லேஅவுட் கணிக்கக்கூடியதாக இல்லாவிட்டால், ஒரு சாதாரண border-right கர்சர்awkward ஆகத் தாவும். புதிய வரி எழுத்துக்களின் அடிப்படையில் (newline characters) தொடர்களைப் பிரித்து, ஒவ்வொரு வரியையும் அதன் சொந்த <span>-இல் காட்டவும், அல்லது உள்ளடக்கத்தின் முடிவைக் கண்காணிக்கும் ஒரு positioned pseudo-element-ஐப் பயன்படுத்தவும். உரை சுருங்குவதில் (text wrapping) கவனமாக இருக்கவும்; கண்டெய்னர் அகலம் மாறினால், இன்லைன் பார்டராக (inline border) செயல்படுத்தப்பட்ட கர்சர் உரையில் இருந்து விலகிவிடக்கூடும். டெர்மினல் ஸ்டைல்களுக்கு white-space: pre-wrap மற்றும் ஒரு monospaced எழுத்துருவைப் பயன்படுத்துவதைக் கருத்தில் கொள்ளுங்கள், ஏனெனில் நிலையான அகலமுள்ள எழுத்துக்கள் கர்சர் கணக்கீட்டை மிகவும் எளிதாக்கும்.

நிகழ்நேர Markdown ரெண்டரிங். இது சற்று சிக்கலானது. நீங்கள் **bold** என்று டைப் செய்தால், உங்களுக்கு இரண்டு விருப்பங்கள் உள்ளன: நட்சத்திரக் குறிகளை அப்படியே காட்டுவது அல்லது அவற்றை உடனுக்குடன் போல்ட் (bold) ஸ்டைலாக மாற்றுவது. நீங்கள் இரண்டாவதைத் தேர்ந்தெடுத்தால், இடையில் textContent-லிருந்து innerHTML-க்கு மாறுவது உங்கள் உரை நோட் எல்லைகளை (text node boundaries) மாற்றும். HTML டேக்குகள் உங்களுக்குக் கீழே உள்ள DOM மரத்தை மாற்றுவதால், கர்சர் நிலையை நிர்வகிப்பது ஒரு பெரிய தலைவலியாக மாறும். ஒரு பாதுகாப்பான அணுகுமுறை என்னவென்றால், மூல Markdown தொடரைச் சாதாரணமாகத் தட்டச்சு செய்துவிட்டு, முழுத் தொடரும் திரையில் வந்தவுடன் ஒரு ரெண்டர் பாஸைத் (render pass) தூண்டுவதாகும். உங்களுக்கு நேரடி ஃபார்மேட்டிங் (live formatting) உண்மையிலேயே தேவைப்பட்டால், இரண்டு அடுக்குகளைப் பராமரிக்கவும்: ஒரு மறைக்கப்பட்ட டைப் செய்யப்பட்ட பஃபர் (hidden typed buffer) மற்றும் ஒரு பகுப்பாய்வு செய்யப்பட்ட விஷுவல் ஓவர்லே (parsed visual overlay).

தலைகீழ் விளைவுகள். உரையை நீக்குவது என்பது ஒவ்வொரு எழுத்தாக backspace செய்வதைக் குறிக்க வேண்டிய அவசியமில்லை. அடுத்த தொடர் தட்டச்சு செய்யப்படுவதற்கு முன்பு, புலத்தை உடனடியாகத் துடைக்கும் "அனைத்தையும் தேர்ந்தெடுத்து, பின் நீக்கு" (select all, then delete) போன்ற ஒரு செயல்பாட்டை நீங்கள் செய்ய முடியும். இது இயந்திரத்தனமாகத் தோன்றும். மாற்றாக, ஒரு எழுத்துக்கு 30 மில்லி விநாடிகள் என்ற வேகத்தில் மெதுவாக backspace செய்வது ஒருவித எதிர்பார்ப்பை (tension) உருவாக்கும். இரண்டையும் கலந்து பயன்படுத்தவும்: ஒரு எழுத்துப் பிழையை விரைவாக backspace செய்துவிட்டு, சிறிது இடைவெளி விட்டு, பின்னர் சாதாரண வேகத்தில் நீக்கத் தொடங்குங்கள். இந்த மாறுபாடுகள் அந்த விளைவின் இயல்பானத் தன்மையை (humanity) வெளிப்படுத்தும்.

உண்மையான கருத்து

டைப்ரைட்டர் விளைவு என்பது மேலோட்டமாக எளிதாகத் தோன்றும், ஆனால் நீங்கள் அதை உருவாக்கிய பின்னரே அதன் சிக்கல்களை உணர முடியும். Start with