{"_id":"ccapture.js","_rev":"20-1cbeb29b02ce75bf344cd9453e68ea60","name":"ccapture.js","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"ccapture.js","version":"1.0.0","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.0","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"8dd8681da51c24203b8e0920a2d2087f45cb5dab","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.0.tgz","integrity":"sha512-blFc86rSfdTnoY/RVQshDAJrvLGpM1VyUFWpvJG/8LVAjKVCMglMQQQ3syqLxg9XaAyn3AfZONry7DwNDVAcnA==","signatures":[{"sig":"MEUCIQDV/j8u+Mm5OlQnlWV6+nrNjlnV6+dIt3HpSCqad0sTuAIgSH8djRqbYPJ8/P7h9/+vxeiu1txyw6jQ6vxGP1LGygQ=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"index.js","_from":".","_shasum":"8dd8681da51c24203b8e0920a2d2087f45cb5dab","gitHead":"43ef5537c247b674e3854370755c8f925d39f1fa","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.7.3","description":"A library to capture canvas-based animations at a fixed framerate","directories":{"example":"examples"},"_nodeVersion":"5.6.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.0.tgz_1460978062851_0.5010527693666518","host":"packages-16-east.internal.npmjs.com"}},"1.0.2":{"name":"ccapture.js","version":"1.0.2","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.2","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"0616303bcee861dcd8452954a7b97de83cb079fe","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.2.tgz","integrity":"sha512-6oZ9DhujkL1s6JQjcsEY+EL2pM7rDR91dt1X+KIU8igoyDZI5Lt0mPVKtbERPQF1v4hUd8PFxsT7R/FbQ+vIUw==","signatures":[{"sig":"MEUCIBcySTB/b7TYZJDKxYPnmx9Jjn3dsOTl56MT6aEAPk1PAiEA72QADySdkzq1swQ/572KNYvIEUbflMqSDPHxQ+o0Rts=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","_from":".","_shasum":"0616303bcee861dcd8452954a7b97de83cb079fe","gitHead":"b4ca036ee64e218e7692dc5de01af2b386a383ad","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.7.3","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"5.6.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.2.tgz_1460979749110_0.8393860873766243","host":"packages-16-east.internal.npmjs.com"}},"1.0.3":{"name":"ccapture.js","version":"1.0.3","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.3","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"ad497bbdbe96f50ca2c362f14de294a118654d17","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.3.tgz","integrity":"sha512-BxCzn6GzmarHZdOGHEhBUj01AitVFSXZfcELkx8/OY9qAH73y8FsCDlf8zjnarsoti5jaJiQ5Q5as5Ab5daYzw==","signatures":[{"sig":"MEUCIQC7kUYQR5xa/nPSX7WD3zcdWSsxG1SNnJcWEnGAPqlRHgIgbh6xghoxyAF8Xo3GrcgH6x60RFy2sQkt2CdLOr1xCSk=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","_from":".","_shasum":"ad497bbdbe96f50ca2c362f14de294a118654d17","gitHead":"fc2ebc6877673f6a6697582c33f574da4c89067c","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.7.3","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"5.6.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.3.tgz_1460986586645_0.44872202491387725","host":"packages-16-east.internal.npmjs.com"}},"1.0.4":{"name":"ccapture.js","version":"1.0.4","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.4","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"addb546ce721711937f7560da1d9d13e24de5d54","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.4.tgz","integrity":"sha512-re6uFhHLMrMFUt8C3B926ic2JF4fYL+iHHq1FLnKkznrS461eElZlNDD9BUefvjQfkgghxRHJlkzjrlRVpd4CA==","signatures":[{"sig":"MEYCIQD8s1Uf1bvX42twE/93ZUuMTo2D8UeZ/e01hjDemhR/1wIhAPkYSTlD3BPnVSzyi7sWT01FfbuyTt5dbCnhMdHnCwi/","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","_from":".","_shasum":"addb546ce721711937f7560da1d9d13e24de5d54","gitHead":"d69a1e4857df0ccd1870d7d6bf5fa4d7d2abe846","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.8.6","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"6.0.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.4.tgz_1480888053308_0.7931148142088205","host":"packages-12-west.internal.npmjs.com"}},"1.0.5":{"name":"ccapture.js","version":"1.0.5","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.5","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"68f9b4a42bb837c9ae779690329a529be804b663","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.5.tgz","integrity":"sha512-3TITtZNLT0O4rSwEoq0H6+sMxchHMDf7VNmgtpwljtex5AgFKV8H3a83u0WiHmpHSlQMaxOzXa2weF5RgvLDqg==","signatures":[{"sig":"MEUCIQDFHww44mMniB+i6oNQVL44hl/IAg02ortA18ItEnC4qAIgSQxKyztgynxDH492K5oxiJJux5XoO0iTTJR/o9W02Ok=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","_from":".","_shasum":"68f9b4a42bb837c9ae779690329a529be804b663","gitHead":"5fdb8d53c7d228436820162eda4bd0de6d4ae38f","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.8.6","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"6.0.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.5.tgz_1480896520009_0.02105705114081502","host":"packages-18-east.internal.npmjs.com"}},"1.0.6":{"name":"ccapture.js","version":"1.0.6","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.6","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"9d9d591579ae9745c6ef3745210686c946db7fed","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.6.tgz","integrity":"sha512-IkkxiURBUnQGRiTl4q+GqZNwx9XzxvDNYXJ2FcsdUEn4oGmTkVvAsIWae8Q7HuuBj1hKjuXXOUQThidJhV/znA==","signatures":[{"sig":"MEUCIQDlSs2H+awATTbTvlHjFRYlDlul7A6Ujz2alo1VSg9h2AIgU6PYafWkH5P4xCG3MT/XlG8OizPyYuhT+ejuyMxwe4A=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","_from":".","_shasum":"9d9d591579ae9745c6ef3745210686c946db7fed","gitHead":"0027e5eab10fac12577156962d995fb534a1a0ed","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"3.8.6","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"6.0.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.6.tgz_1481101423143_0.9678336842916906","host":"packages-18-east.internal.npmjs.com"}},"1.0.7":{"name":"ccapture.js","version":"1.0.7","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.7","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"8437eb14545925f2896a693b6d22cda1876a8d36","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.7.tgz","integrity":"sha512-RuIOv/DDUR9PF9QU/NdkxjYQ/0zXi8jHfPc6ua6ljVZgq281iale5LBUNvv/5SDc5mW7i4KEIH5qTRmhKnPZjw==","signatures":[{"sig":"MEUCIQDYxaifWjyS6TA9FE9MGLNHKBaOPkA0zWgI+DU8UUBkRAIgdBSBsQ+thPiNR3qvB1+hxdCOPKqbfaFd90FPQRSeGdI=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}]},"main":"build/CCapture.all.min.js","gitHead":"bccbcb673abdf4c63f4d1fa06761f0b5ebed5583","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"5.0.0","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"7.4.0","_npmOperationalInternal":{"tmp":"tmp/ccapture.js-1.0.7.tgz_1500322228933_0.13333175680600107","host":"s3://npm-registry-packages"}},"1.0.8":{"name":"ccapture.js","version":"1.0.8","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.8","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"8b8218fe52d964e1b29546781b7023b1e5e4d59b","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.8.tgz","fileCount":2507,"integrity":"sha512-dlW2mXvKENwCieI9CGwokL+PsCTw485TRShuTYwFeVi1eCizeXU7tByX757RrjhBsvrHP1XBCntPC+FP60fVNg==","signatures":[{"sig":"MEUCIQDS2VOxjV95XuxM9lTNn8uOf0iyiw06qFve9iM/LyT2cwIgLPhNXSLjlG+k4PV25b1MZar6f+TjAthvVmMADveaVts=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":18100204},"main":"build/CCapture.all.min.js","gitHead":"660bab376ccc6ca049b7cf3df62a0aa669a51e02","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"5.7.1","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"9.7.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ccapture.js_1.0.8_1521627209900_0.6342926975909438","host":"s3://npm-registry-packages"}},"1.0.9":{"name":"ccapture.js","version":"1.0.9","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.0.9","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"91e291e9a9eaff29843add622d9fb78f04deb498","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.0.9.tgz","fileCount":13,"integrity":"sha512-kHCilD/T0PrFjJ/0fs79R2GPZ7F9PBno3vYp45YttI/UxEfeXia1Tdo0gGDvb34wYkcNX5iJJt9X55k2Ohn2xw==","signatures":[{"sig":"MEUCIQDRLWnAJSsytIbbj3IPpTZnnFnKUSo9ivRb+x0TAPWtTAIgU7qo/bWEl4eJiU7w9UsTFvUyfjhMoSZJxd7IN/m8fbs=","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":170763},"main":"build/CCapture.all.min.js","gitHead":"e66f7bd12c0cfd2c27ce844fcfa8d0dad15ff188","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"5.7.1","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"9.7.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ccapture.js_1.0.9_1521661437297_0.9107401687602452","host":"s3://npm-registry-packages"}},"1.1.0":{"name":"ccapture.js","version":"1.1.0","keywords":["capture","canvas","webgl","animation"],"author":{"url":"https://www.clicktorelease.com","name":"Jaume Sanchez","email":"the.spite@gmail.com"},"license":"MIT","_id":"ccapture.js@1.1.0","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"homepage":"https://github.com/spite/ccapture.js#readme","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"dist":{"shasum":"ac4030e8b43847e305242d784abf284d2313beff","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-1.1.0.tgz","fileCount":13,"integrity":"sha512-28kiHJzFsZ6b0OTfKpWpEwK2n/LTAgytK1uzB+413dzjHltdh2hP5Yg2qR0+9Xw3XoBMz5UkGCh8Ektr2rVlmw==","signatures":[{"sig":"MEYCIQCJAHsi2FSUOPuQWaXwxShiz13gi3lsiI3VRIdZm2mHmwIhANEBvFexAomE4tIl+2N6TGZcYO2A9b8NGcIGpBEiKysf","keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"}],"unpackedSize":172490,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJa1TSYCRA9TVsSAnZWagAAc4UP/2LwoqDFcHCoYcLwTTdj\ncIWQ3gaifiV77L2Tpy5VwoZnenCvw3kLts7h62xV1bGrm+Vybf47Zgk0I+KS\nm2zMmFFcD7LiKBpc7tUZpVM8zswjJqQ2PUJkJ1P/+CrGch8TApcTUg+BknpQ\nShkpqGq/a35fGB4XlxelHSD1F8WpzIIOlpWrv6QLI32ZgY9n7MeXBxM1ZgCv\nximOkTDdrArC8zvmup0Ve+qnYRe8nee9UYp4u5jKM5F/iP+hAeS6CULJpdk4\nrhHX9JzKvr96jtQhTSNwWHSMXLWwqJu1bvJzAYMImg/kGcVu0t8rQKtlJyVj\nR8u5CzVLFh3Esnl4JgjZWC3TUCaf6SvPVYJTiXrL04FtPBRzRz5MWG9YBKu9\nRyJSZKi7GxDrn/AJ9Bxgrn7KuBWA6snbXH8mqH9dSTqWY0a7ngnLh+kPW3sl\nJ/UFs89ZSSX/zbXXDZxhLT1t9bQhmwVULxlD8xoDV4Fu4WgjCWeJRUK55mft\nA/0muV3nHNZt2oUMHQpolcrviDmfsSDCp2COX5pw1TvH/T4wZlvS326dcw8P\nLEf/JnC1dUNrgZhKsnLv+S6+0scE1UG+Vvo8c2WNwT67W6s7AxTKNPbw6wh6\nTS57GVRF0h/Q34UoM2wpzgPcnaUX5wGw521srH1BdMIPDEqfEKbcRUBXS1R1\ngIQ9\r\n=lTDF\r\n-----END PGP SIGNATURE-----\r\n"},"main":"build/CCapture.all.min.js","gitHead":"158611dee46d905643b6b40d4e26f668feea98c0","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"repository":{"url":"git+https://github.com/spite/ccapture.js.git","type":"git"},"_npmVersion":"5.8.0","description":"A library to capture canvas-based animations at a fixed framerate","directories":{},"_nodeVersion":"9.7.1","_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/ccapture.js_1.1.0_1523922070765_0.8147228756030624","host":"s3://npm-registry-packages"}},"2.0.0":{"name":"ccapture.js","version":"2.0.0","description":"Capture canvas-based animations at a fixed framerate, with motion blur and modern encoders (WebCodecs).","type":"module","main":"src/index.js","module":"src/index.js","types":"./src/index.d.ts","unpkg":"build/ccapture.umd.min.js","jsdelivr":"build/ccapture.umd.min.js","exports":{".":{"types":"./src/index.d.ts","import":"./src/index.js"},"./CCapture":{"types":"./src/CCapture.d.ts","import":"./src/CCapture.js"},"./TimeWarp":{"types":"./src/TimeWarp.d.ts","import":"./src/TimeWarp.js"},"./FrameWrap":{"types":"./src/FrameWrap.d.ts","import":"./src/FrameWrap.js"},"./umd":"./build/ccapture.umd.min.js"},"scripts":{"build":"esbuild src/umd.js --bundle --format=iife --target=es2020 --outfile=build/ccapture.umd.js && esbuild src/umd.js --bundle --format=iife --target=es2020 --minify --outfile=build/ccapture.umd.min.js","test":"node test/TimeWarp.test.js && node test/FrameWrap.test.js && node test/CCapture.test.js && node test/WebCodecsEncoder.test.js && node test/MotionBlur.test.js && node test/Modular.test.js","test:browser":"node test/browser/run.mjs","test:types":"tsc -p test/types/tsconfig.json","serve":"node test/browser/serve.mjs","prepublishOnly":"npm run build"},"devDependencies":{"esbuild":"0.24.0","playwright-core":"1.48.0","typescript":"5.6.3"},"keywords":["capture","canvas","webgl","webgpu","webcodecs","animation","motion-blur","video","gif"],"repository":{"type":"git","url":"git+https://github.com/spite/ccapture.js.git"},"author":{"name":"Jaume Sanchez","email":"the.spite@gmail.com","url":"https://www.clicktorelease.com"},"license":"MIT","homepage":"https://github.com/spite/ccapture.js#readme","gitHead":"123df0a31801859118a0f09da6fdc01ffc9cd166","bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"_id":"ccapture.js@2.0.0","_nodeVersion":"18.19.1","_npmVersion":"9.2.0","dist":{"integrity":"sha512-6cKIIcK8TIX6uKffk6ItOwsmOnvp5Wx6YXKK6QYWUJFts2OTcLm66feEP6tOclosUE3MicjHz/cG4GbuUWgK2w==","shasum":"2f497a82d5e9bfda7715c9e1cf4f076163041f73","tarball":"https://registry.npmjs.org/ccapture.js/-/ccapture.js-2.0.0.tgz","fileCount":36,"unpackedSize":670579,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQC/hT+i7fpDw7PXxzTeF2GL0C35KlqgmxuYlxiUDpnXZAIhANf7c2//1HcSNKRpu3R5TsBGGUVbeJ/yI4Ed+FkShQ4v"}]},"_npmUser":{"name":"spite","email":"the.spite@gmail.com"},"directories":{},"maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ccapture.js_2.0.0_1785178770317_0.2743376901994503"},"_hasShrinkwrap":false}},"time":{"created":"2016-04-18T11:14:24.595Z","modified":"2026-07-27T18:59:30.579Z","1.0.0":"2016-04-18T11:14:24.595Z","1.0.1":"2016-04-18T11:29:42.082Z","1.0.2":"2016-04-18T11:42:30.620Z","1.0.3":"2016-04-18T13:36:28.420Z","1.0.4":"2016-12-04T21:47:36.991Z","1.0.5":"2016-12-05T00:08:40.778Z","1.0.6":"2016-12-07T09:03:44.062Z","1.0.7":"2017-07-17T20:10:30.080Z","1.0.8":"2018-03-21T10:13:30.209Z","1.0.9":"2018-03-21T19:43:57.424Z","1.1.0":"2018-04-16T23:41:10.816Z","2.0.0":"2026-07-27T18:59:30.448Z"},"bugs":{"url":"https://github.com/spite/ccapture.js/issues"},"author":{"name":"Jaume Sanchez","email":"the.spite@gmail.com","url":"https://www.clicktorelease.com"},"license":"MIT","homepage":"https://github.com/spite/ccapture.js#readme","keywords":["capture","canvas","webgl","webgpu","webcodecs","animation","motion-blur","video","gif"],"repository":{"type":"git","url":"git+https://github.com/spite/ccapture.js.git"},"description":"Capture canvas-based animations at a fixed framerate, with motion blur and modern encoders (WebCodecs).","maintainers":[{"name":"spite","email":"the.spite@gmail.com"}],"readme":"# CCapture\n\nCapture canvas-based animations at a **fixed framerate**, with motion blur and\nmodern encoders — a ground-up rewrite of [CCapture.js](https://github.com/spite/ccapture.js)\n(ES modules, WebCodecs, GPU motion blur, `async`/`await`).\n\nYour animation renders as fast (or as slowly) as it needs to; CCapture lies to\nit about what time it is, so the exported video is perfectly smooth at exactly\nthe framerate you asked for — 30, 60, 240, whatever. Record a 4K frame that takes\ntwo seconds to draw and still get a flawless 60fps file.\n\n```js\nimport CCapture from \"ccapture.js\";\n\nconst capturer = new CCapture({ format: \"mp4\", framerate: 60, timeLimit: 5 });\ncapturer.start();\n\nfunction render() {\n  requestAnimationFrame(render);      // your normal loop\n  drawMyScene();                      // draws using performance.now() / rAF time\n  capturer.capture(canvas);           // ← the only line you add\n}\nrender();\n```\n\nThat's it. After 5 seconds an `.mp4` downloads. No `await`, no restructuring.\n\n`CCapture` is the unified, plug-and-play recorder. It's composed of two pieces\nyou can also use on their own: **`FrameWrap`** (canvas capture — motion blur +\nencoding) and **`TimeWarp`** (the virtual clock).\n\n---\n\n## Table of contents\n\n- [How it works](#how-it-works)\n- [Install](#install)\n- [The least-intrusive API](#the-least-intrusive-api)\n- [Adding it to an existing sketch](#adding-it-to-an-existing-sketch)\n- [Options](#options)\n- [Formats & encoders](#formats--encoders)\n- [Custom encoders](#custom-encoders)\n- [Motion blur](#motion-blur)\n- [Methods & events](#methods--events)\n- [Recipes](#recipes)\n- [Using TimeWarp on its own](#using-timewarp-on-its-own)\n- [Using FrameWrap on its own](#using-framewrap-on-its-own)\n- [The `hookDate` trade-off](#the-hookdate-trade-off)\n- [Migrating from CCapture 1.x](#migrating-from-ccapture-1x)\n- [Browser support & caveats](#browser-support--caveats)\n- [Examples](#examples)\n- [License](#license)\n\n---\n\n## How it works\n\nThe idea (à la [ryg's kkapture](http://www.farb-rausch.de/~fg/kkapture/)) is to\nreplace the browser's notion of time with a **virtual clock** that only advances\none fixed step per captured frame. Anything that derives motion from elapsed\ntime then steps deterministically, decoupled from wall-clock.\n\nThe library is three composable pieces:\n\n- **`TimeWarp`** — owns time. Hooks `performance.now`, `requestAnimationFrame`,\n  `setTimeout`/`setInterval`, `Date`, and media `currentTime`, and advances a\n  virtual clock on demand. Knows nothing about canvases.\n- **`FrameWrap`** — owns capture. Takes already-drawn canvas frames, applies\n  motion blur, enforces frame/time limits, and feeds a pluggable encoder. Knows\n  nothing about time.\n- **`CCapture`** — composes the two and drives them: the plug-and-play recorder.\n\nBecause `requestAnimationFrame` is hooked during capture, your render loop only\nadvances when `CCapture.capture()` flushes it — so it paces the whole thing, as\nfast as your machine can draw and encode, with no wall-clock throttle.\n\nUse `CCapture` for the normal \"record a live animation\" case; reach for the\nhalves directly when you only need one (timing without capture, or encoding\nframes you produce yourself without touching the browser clock).\n\n---\n\n## Install\n\n```bash\nnpm install ccapture.js\n```\n\n```js\nimport CCapture from \"ccapture.js\";\n// or: import { CCapture, FrameWrap, TimeWarp } from \"ccapture.js\";\n```\n\nOr use it straight from source as native ES modules (no build step) — point at\n`src/index.js` and serve over HTTP.\n\nShips with **TypeScript declarations** (`.d.ts`) — full autocomplete and\ntype-checking out of the box, no `@types` package needed.\n\n### Script tag (no build, no bundler)\n\nA UMD/IIFE global build is included for classic `<script>` use — the whole API\nhangs off `window.CCapture`:\n\n```html\n<script src=\"https://cdn.jsdelivr.net/npm/ccapture.js@2/build/ccapture.umd.min.js\"></script>\n<script>\n  const capturer = new CCapture({ format: \"mp4\", framerate: 60, timeLimit: 5 });\n  // CCapture.FrameWrap, CCapture.TimeWarp, CCapture.createMotionBlur, … also here\n</script>\n```\n\nBuild it yourself with `npm run build` (outputs `build/ccapture.umd[.min].js`).\n\n---\n\n## The least-intrusive API\n\nThe common case is a single `capture(canvas)` call inside your existing loop:\n\n```js\nconst capturer = new CCapture({ format: \"mp4\", framerate: 60, timeLimit: 5 });\ncapturer.start();\n\nfunction render() {\n  requestAnimationFrame(render);\n  // draw using performance.now() (warped) or the rAF timestamp\n  capturer.capture(canvas);\n}\nrender();\n```\n\nNotes:\n- Set a `timeLimit` or `frameLimit` and it stops and saves itself. Otherwise call\n  `capturer.stop()` then `capturer.save()` when you're done.\n- Kick your loop once (`render()`), or make sure it's already running, right after\n  `start()` — after that, `capture()` drives it.\n- The frame you pass to `capture()` should already be drawn. `capture()` is\n  `async` but you don't need to `await` it.\n\n---\n\n## Adding it to an existing sketch\n\nThree steps, whatever you're using: **(1)** make a `CCapture`, **(2)** `start()`\nit, **(3)** call `capture(yourCanvas)` once per frame in your loop. Drive motion\nfrom `performance.now()` / the rAF timestamp / `millis()` (all warped during\ncapture) rather than fixed per-frame increments.\n\n**three.js** — pass the renderer's canvas:\n```js\nfunction animate() {\n  requestAnimationFrame(animate);\n  renderer.render(scene, camera);\n  capturer.capture(renderer.domElement);\n}\n```\n\n**p5.js** — p5 owns the loop, so drive it with `redraw()` while capturing (see\nthe [p5 example](examples/p5/)):\n```js\ncapturer.on(\"stop\", () => loop());        // resume live preview when done\nawait capturer.start();\nnoLoop();\n(function tick() {\n  if (!capturer.capturing) return;\n  requestAnimationFrame(tick);\n  redraw();                                // your draw() on the warped clock\n  capturer.capture(document.querySelector(\"canvas\"));\n})();\n```\nGlobal-mode p5 users can drop in the UMD build (`window.CCapture`) with two\n`<script>` tags instead of importing.\n\n**Plain canvas / WebGL / WebGPU** — same as the top example; pass your\n`<canvas>`. WebGPU canvases capture fine (WebCodecs reads them directly); GPU\nmotion blur currently needs WebGL2, so a WebGPU source uses the CPU blur backend.\n\n---\n\n## Options\n\nAll options are passed to the `CCapture` constructor (capture options go to its\n`FrameWrap`, timing options to its `TimeWarp`). Defaults shown.\n\n| Option | Default | Description |\n|---|---|---|\n| `format` | `\"mp4\"` | `mp4`, `webm`, `webm-legacy`, `png`, `jpg`, `webp`. |\n| `framerate` | `60` | Target framerate of the output. |\n| `quality` | `90` | 0–100. Drives video bitrate and JPEG/WebP quality (PNG ignores it). |\n| `name` | *(guid)* | Base filename for the download. |\n| `gifColors` | `256` | GIF palette size (2–256). |\n| `codec` | *(per container)* | `avc` / `vp9` / `av1` / `vp8`. Default `avc` for mp4, `vp9` for webm. |\n| `bitrate` | `0` | Bits/sec for video. `0` derives it from resolution × quality. |\n| `audio` | `null` | An `AudioBuffer` to encode + mux as an audio track (mp4/webm). |\n| `audioBitrate` | `128000` | Audio bits/sec. |\n| `maxQueueSize` | `8` | WebCodecs encoder-queue high-water mark (backpressure). |\n| `motionBlurFrames` | `1` | Sub-frames averaged per output frame. `1` = no blur. |\n| `motionBlur` | `\"auto\"` | Blur backend: `auto` / `gpu` / `cpu`. |\n| `timeLimit` | `0` | Seconds; auto-stops & saves at this mark. `0` = unlimited. |\n| `frameLimit` | `0` | Output frames; auto-stops & saves at this count. `0` = unlimited. |\n| `autoSaveTime` | `0` | Seconds; if `>0`, downloads the capture in parts periodically. |\n| `startTime` | `0` | Seconds to skip into the animation before the first frame. |\n| `media` | `null` | A `<video>`/`<audio>` element (or array) to frame-step. See [capturing video](#capturing-a-video-or-audio-element). |\n| `hookMedia` | `true` | Hook `HTMLMediaElement` (`currentTime`/`play`) to frame-step media. |\n| `hookDate` | `true` | Warp `Date.now` + `Date.prototype.getTime`. See [the trade-off](#the-hookdate-trade-off). |\n| `hookValueOf` | `false` | Also warp `Date.prototype.valueOf`, so `+new Date()` is warped (needs `hookDate`). |\n| `display` | `false` | Show a small on-page capture-status widget. |\n| `verbose` | `false` | Log internal steps to the console. |\n| `timewarp` | *(created)* | Inject a shared `TimeWarp` instance instead of creating one. |\n\n---\n\n## Formats & encoders\n\n| Format | Output | Encoder |\n|---|---|---|\n| `mp4` | `.mp4` (H.264/AV1) | **WebCodecs** `VideoEncoder` + mp4 muxer |\n| `webm` | `.webm` (VP9/VP8/AV1) | **WebCodecs**; falls back to the legacy writer if unavailable |\n| `webm-legacy` | `.webm` | webm-writer-js (WebP frames; Chromium-only) |\n| `gif` | `.gif` | [gifenc](https://github.com/mattdesl/gifenc) (256-color, CPU) |\n| `png` / `jpg` / `webp` | `.tar` of images | `canvas.toBlob` packed into a TAR |\n\nGIF is 256-color and palette-quantized (tune with `gifColors`), so it needs a\nCPU readback per frame and its timing is coarse (delays are whole centiseconds,\nso 60fps plays back at ~50fps). Prefer a video format unless you specifically\nneed a GIF. Need your own format? See [Custom encoders](#custom-encoders).\n\n**WebCodecs is the default and preferred path** — it's hardware-accelerated and\nback-pressured, so you can run flat-out with bounded memory. Codec strings are\nnegotiated at runtime via `VideoEncoder.isConfigSupported`, and odd/resized\nframes are automatically fitted to a valid even-dimension coded size.\n\nIf a browser lacks WebCodecs, `webm` transparently falls back to the legacy\nwriter; `mp4` throws a clear error (switch to `webm`).\n\n---\n\n## Custom encoders\n\nAn encoder is just an object with a small interface, so you can wrap anything — a\nWASM codec, a server upload, APNG, whatever. There are two base classes for the\ntwo kinds of encoder.\n\n### Frame-by-frame encoders — `FrameEncoder`\n\nFor codecs that take one frame at a time (WebCodecs, image sequences, GIF via\ngifenc). Extend `FrameEncoder` for free filename, multipart-autosave, and event\nhandling:\n\n```js\nimport { FrameEncoder } from \"ccapture.js\";\n\nclass MyEncoder extends FrameEncoder {\n  constructor(params) {\n    super(params);\n    this.extension = \"bin\";              // download filename extension\n    this.mimeType = \"application/octet-stream\";\n  }\n  async start() { await super.start(); /* init */ }\n  async add(canvas) { /* consume this frame */ await super.add(); }\n  async save() { return new Blob([/* … */], { type: this.mimeType }); } // or null\n  async dispose() { /* free resources */ }\n  // optional: async backpressure() {}   // FrameWrap awaits this before each frame\n  // (this.emit(\"progress\", 0..1) bubbles up as the \"progress\" event)\n}\n```\n\n### Batch encoders — `BatchEncoder`\n\nFor libraries that need *all* frames at once (e.g. gifski). `BatchEncoder` does\nthe buffering for you — frames are stored compressed during capture\n(`bufferMode: \"webp\" | \"png\" | \"raw\"`) to keep memory bounded, then handed back\nat save time. You implement one method:\n\n```js\nimport { BatchEncoder } from \"ccapture.js\";\n\nclass MyBatchEncoder extends BatchEncoder {\n  constructor(params) {\n    super(params);\n    this.extension = \"gif\";\n    this.mimeType = \"image/gif\";\n  }\n  async encodeAll({ frameCount, width, height, framerate, getFrame }) {\n    const frames = [];\n    for (let i = 0; i < frameCount; i++) {\n      frames.push(await getFrame(i));            // decoded ImageData, on demand\n      this.emit(\"progress\", (i + 1) / frameCount);\n    }\n    const bytes = await myBatchLib.encode({ frames, width, height, fps: framerate });\n    return new Blob([bytes], { type: this.mimeType });\n  }\n}\n```\n\n### Registering / using either kind\n\n```js\n// Pass directly (class or ready instance) — overrides `format`:\nnew CCapture({ encoder: MyEncoder });\nnew CCapture({ encoder: new MyEncoder(params) });\n\n// Or register a named format (great for plugins):\nCCapture.registerEncoder(\"mine\", MyEncoder); // also on FrameWrap\nnew CCapture({ format: \"mine\" });\n\nCCapture.formats; // → all registered format names\n```\n\nThe built-in `GIFEncoder` (frame-by-frame) and `GifskiEncoder` (batch) are\nreal-world examples of each base.\n\n### High-quality GIF via gifski\n\n`GifskiEncoder` wraps [gifski-wasm](https://github.com/jamsinclair/gifski-wasm)\n(libimagequant + dithering) — much better quality than the default `gif`, at the\ncost of buffering frames (batch) and pulling in gifski. It's **not registered by\ndefault**; opt in:\n\n```js\nimport { CCapture, GifskiEncoder } from \"ccapture.js\";\n\nCCapture.registerEncoder(\"gif-hq\", GifskiEncoder);\nnew CCapture({ format: \"gif-hq\", quality: 90, frameLimit: 120 });\n```\n\ngifski needs every frame as raw RGBA in one buffer, so GIFs must stay small.\n`GifskiEncoder` **downscales** frames to `gifMaxSize` (longest side, default\n`640`) — set `gifMaxSize`, or explicit `gifWidth`/`gifHeight`, to change it. It\nthrows early with guidance if the batch would still be too large; keep clips\nshort (and remember GIF playback is coarse, ~≤50fps).\n\ngifski loads lazily from a CDN by default. To vendor it or use the multithreaded\nbuild (needs `Cross-Origin-Opener-Policy`/`Cross-Origin-Embedder-Policy`\nheaders), pass your own: `{ encoder: new GifskiEncoder({ gifski: encodeFn }) }`\nor `{ gifskiUrl: \"/vendor/gifski/encode.js\" }`. Best for short, quality-critical\nGIFs — for long captures the streaming `gif` keeps memory bounded.\n\n## Motion blur\n\nSet `motionBlurFrames` to the number of sub-frames to average per output frame.\nEach sub-frame is rendered at a fractional time step, then blended — the same\nblur a real camera shutter produces.\n\n```js\nnew CCapture({ format: \"mp4\", motionBlurFrames: 16 });\n```\n\nYou don't change your loop: internally `capture()` runs N sub-renders per output\nframe. The backend is chosen automatically (`motionBlur: \"auto\"`):\n\n- **GPU** (WebGL2) when the source is a WebGL canvas and `motionBlurFrames > 2` —\n  accumulation stays on the GPU, no per-sub-frame readback.\n- **CPU** otherwise — a `Float32` accumulator (no overflow, alpha included).\n\nForce it with `motionBlur: \"gpu\"` or `\"cpu\"`.\n\n---\n\n## Methods & events\n\n### Methods\n\n- **`start()`** → `Promise` — install hooks, start the encoder, begin capturing.\n- **`capture(canvas)`** → `Promise` — capture the just-drawn frame (auto-drives\n  the loop; see above).\n- **`stop()`** → `Promise` — stop capturing and restore the real clock.\n- **`save(callback?)`** → `Promise<Blob|null>` — finalize. With no callback it\n  downloads the file; with a callback it hands you the `Blob` instead. Safe to\n  call while still capturing to grab everything so far.\n- **`step()`** — advance the virtual clock by one (sub-)frame manually. Only\n  needed for the manual driving mode.\n- **`record(canvas, render)`** → `Promise<boolean>` — headless convenience: give\n  it a `render(frame)` function and it owns a flat capture loop (needs a\n  `frameLimit`/`timeLimit`). Use when you *don't* have an existing rAF loop.\n- **`dispose()`** → `Promise` — release the encoder and any GPU blur context.\n  Call it if you create a new `FrameWrap` per recording.\n- **`on(event, handler)`** — subscribe to an event (one handler per event).\n\n### Events\n\n| Event | Payload | Fired when |\n|---|---|---|\n| `start` | — | capture begins |\n| `frame` | `frameCount` | an output frame is encoded |\n| `progress` | `0..1` | encoder reports progress (where supported) |\n| `save` | `Blob` | the file is finalized |\n| `stop` | — | capture stops (auto or manual) |\n| `error` | `Error` | a capture/encode error occurred |\n\n---\n\n## Recipes\n\n**Stop manually and get a Blob instead of downloading**\n\n```js\ncapturer.start();\n// … your loop calling capture(canvas) …\nawait capturer.stop();\nawait capturer.save((blob) => {\n  const url = URL.createObjectURL(blob);\n  video.src = url;\n});\n```\n\n**Headless / no existing loop**\n\n```js\nconst capturer = new CCapture({ format: \"mp4\", framerate: 60, frameLimit: 300 });\nawait capturer.record(canvas, (frame) => {\n  const t = frame / 60;          // seconds\n  drawMyScene(t);\n});\n```\n\n**Long captures without blowing memory** — download in parts:\n\n```js\nnew CCapture({ format: \"mp4\", autoSaveTime: 20 }); // a file every 20s\n```\n\n**Skip into the animation**\n\n```js\nnew CCapture({ format: \"mp4\", startTime: 3, timeLimit: 5 }); // seconds 3→8\n```\n\n**Capturing a `<video>` or `<audio>` element**\n\nRegister the element with `media` and CCapture frame-steps it in lockstep: each\nframe it seeks the element to the exact time and waits for `seeked` before your\n`render` draws, so a video drawn to canvas is frame-accurate (not the usual\nbest-effort realtime grab).\n\n```js\nconst capturer = new CCapture({ format: \"mp4\", framerate: 60, timeLimit: 8, media: video });\ncapturer.start();\nfunction render() {\n  requestAnimationFrame(render);\n  ctx.drawImage(video, 0, 0);   // shows the frame for this exact moment\n  capturer.capture(canvas);\n}\nrender();\n```\n\n- Register the element even if you only `drawImage` it — `drawImage` never reads\n  `currentTime`, so it wouldn't otherwise be discovered. (Code that *does* read\n  `video.currentTime` is auto-registered.)\n- The element must be **same-origin**; a cross-origin video taints the canvas and\n  encoding will throw.\n- `play()` is suppressed during capture (CCapture drives time by seeking).\n- Audio-reactive visuals that use the **Web Audio API** can't be frame-stepped\n  (see caveats).\n\n**Frame-accurate audio-reactive visuals**\n\nA realtime `AnalyserNode` reads audio at wall-clock time, so it desyncs during a\nslow capture. `renderAudioFrames()` renders the audio *offline* and samples it at\neach frame's exact time, so the visuals line up with the soundtrack\nframe-for-frame (add the audio back in an editor afterwards):\n\n```js\nimport { CCapture, renderAudioFrames } from \"ccapture.js\";\n\nconst framerate = 60, frames = 300;\n\n// Decode once, then use the buffer for both the analysis and the muxed track.\nconst arrayBuffer = await (await fetch(\"track.mp3\")).arrayBuffer();\nconst buffer = await new OfflineAudioContext(1, 1, 44100).decodeAudioData(arrayBuffer);\n\nconst audio = await renderAudioFrames({ buffer, framerate, frames, fftSize: 1024 });\n\nconst capturer = new CCapture({ format: \"mp4\", framerate, frameLimit: frames, audio: buffer });\nawait capturer.record(canvas, (i) => {\n  const { frequency, waveform } = audio[i]; // this frame's spectrum / waveform (Uint8Array)\n  drawBars(frequency);\n});\n// → an mp4 with frame-accurate visuals AND the audio track muxed in.\n```\n\n**Share one clock across two recorders** (e.g. two canvases in lockstep):\n\n```js\nimport { CCapture, TimeWarp } from \"ccapture.js\";\nconst timewarp = new TimeWarp({ framerate: 60 });\nconst a = new CCapture({ format: \"mp4\", timewarp });\nconst b = new CCapture({ format: \"mp4\", timewarp });\n```\n\n---\n\n## Using TimeWarp on its own\n\n`TimeWarp` is fully standalone — useful for deterministic testing or your own\ncapture pipeline.\n\n```js\nimport { TimeWarp } from \"ccapture.js\";\n\nconst tw = new TimeWarp({ framerate: 60 });\ntw.start();                 // performance.now/rAF/timers now virtual\n// … drive your animation …\ntw.step();                  // advance exactly one frame (1000/60 ms)\ntw.step(8);                 // or advance a custom dt in ms\ntw.stop();                  // restore the real clock\n```\n\nProperties: `time` (virtual `performance.now`), `frameStep` (ms/frame),\n`enabled`. Methods: `start`/`stop`/`enable`/`disable`/`step(dt?)`.\n\n## Using FrameWrap on its own\n\nIf you already produce frames deterministically (a server render, your own fixed\nloop) and don't want the browser clock touched, use `FrameWrap` directly — it's\npure capture (motion blur + encoding + limits + save), no timing:\n\n```js\nimport { FrameWrap } from \"ccapture.js\";\n\nconst fw = new FrameWrap({ format: \"mp4\", framerate: 60 });\nawait fw.start();\nfor (const frameCanvas of myFrames) await fw.capture(frameCanvas);\nawait fw.stop();\nawait fw.save();\n```\n\n---\n\n## The `hookDate` trade-off\n\nWith `hookDate: true` (default), TimeWarp overrides **both** `Date.now` and\n`Date.prototype.getTime` to return the virtual clock — so animations that time\nthemselves with `Date.now()` or `new Date().getTime()` work.\n\nThe catch: overriding `Date.prototype.getTime` affects **every** `Date` object,\nnot just \"now\". While capturing, real date math breaks:\n\n```js\nnew Date(\"2020-01-01\").getTime();          // returns the virtual clock, not 2020\nlaterDate.getTime() - earlierDate.getTime(); // garbage — both are \"now\"\n```\n\nSet **`hookDate: false`** if your animation uses `performance.now()` / the rAF\ntimestamp anyway (three.js, GSAP, most modern code) *and* something on the page\ndoes real date math during capture. `performance.now`, rAF, and timers stay\nhooked either way.\n\n`+new Date()` and `.valueOf()` are **not** warped by `hookDate` alone (they go\nthrough `Date.prototype.valueOf`, a separate function). If your code times off\n`+new Date()`, add **`hookValueOf: true`** — off by default because it changes\nthe numeric value of every `Date`, not just \"now\".\n\n---\n\n## Migrating from CCapture 1.x\n\nThe concepts are identical; the surface is modernized.\n\n| CCapture 1.x | CCapture 2.x |\n|---|---|\n| `new CCapture({ format: 'webm' })` | `new CCapture({ format: 'mp4' })` (or `webm`) |\n| global `<script>` + `window.CCapture` | ESM `import`, **or** the UMD build (`window.CCapture` still works) |\n| `capturer.save(cb)` (callback only) | `await capturer.save()` (downloads) or `save(cb)` for the Blob |\n| `format: 'ffmpegserver'` / `'webm-mediarecorder'` | removed (server-based / realtime) |\n| `workersPath` (gif worker) | n/a — `gif` uses gifenc, no worker script |\n| `motionBlurFrames` doubled internally | `motionBlurFrames` = exact sample count |\n| CPU-only motion blur | CPU **and** GPU (auto) |\n| WebM via WebP frames (Chromium) | WebCodecs MP4/WebM (all modern browsers) |\n\n`new CCapture({...})` keeps working and the `.start()` / `.capture()` /\n`.stop()` / `.save()` flow is unchanged — but `CCapture` is now its own class\n(composing `FrameWrap` + `TimeWarp`) rather than the whole library. If you were\nrelying on `CCapture` being the capture engine itself, that role is now\n`FrameWrap`.\n\n---\n\n## Browser support & caveats\n\n- **WebCodecs** (`mp4`, `webm`): recent Chrome, Edge, Safari, and Firefox.\n  Without it, `webm` falls back to the legacy writer; `mp4` errors.\n- **GPU motion blur** needs WebGL2 + `EXT_color_buffer_float` (widely available);\n  otherwise it falls back to CPU.\n- Capturing a **cross-origin** canvas taints it and encoding will throw — a\n  browser security rule, not something the library can bypass.\n- Odd or mid-capture-resized canvases are fitted to an even coded size\n  automatically (H.264 requires even dimensions).\n\n**What TimeWarp does and doesn't warp.**\n\n*Always hooked* (they're how capture is driven): `performance.now`,\n`requestAnimationFrame`/`cancelAnimationFrame`, `setTimeout`/`setInterval`.\n\n*Hooked but opt-out-able:*\n- `Date.now` + `Date.prototype.getTime` — `hookDate` (default on);\n- `Date.prototype.valueOf` (so `+new Date()`) — `hookValueOf` (default **off**);\n- `<video>`/`<audio>` `currentTime` + `play` — `hookMedia` (default on).\n\n*Partly covered:*\n- **Web Audio** — a realtime `AudioContext` can't be stepped, but for\n  audio-reactive visuals `renderAudioFrames()` renders the audio *offline* and\n  samples an `AnalyserNode` at each frame time, giving frame-accurate spectrum /\n  waveform data. See [Frame-accurate audio](#recipes). You can also **mux an\n  `AudioBuffer` into the output** via the `audio` option (AAC/Opus for mp4, Opus\n  for webm — where the browser's `AudioEncoder` supports it; falls back to\n  video-only otherwise).\n\n*Not covered* — these run on clocks the library can't step, so they'll drift\nduring a capture:\n- the **Web Animations API** (`element.animate`) and **CSS animations/transitions**,\n  which run on the compositor/document timeline.\n\n> Note on `+new Date()`: by default it reads the real construction time (only\n> `Date.now()`/`getTime()` are warped). Set `hookValueOf: true` to warp it too —\n> it's off by default because it's the most invasive Date hook (it changes the\n> numeric value of *every* Date, not just \"now\").\n\n---\n\n## Examples\n\nServe the repo over HTTP (ES modules require it) and open `/examples/`:\n\n```bash\npython3 -m http.server\n# → http://localhost:8000/examples/\n```\n\n- **basic** — 2D canvas, all formats, motion-blur toggle.\n- **three** — Three.js (WebGL); shows the auto-selected GPU motion blur.\n- **gsap** — a GSAP timeline scrubbed by the warped clock.\n- **video** — a `<video>` frame-stepped in lockstep with capture.\n- **demo** — the smallest possible inline capture loop.\n\nAll examples share `examples/CaptureUI.js`, a drop-in control panel (format,\nframerate, motion blur, duration, start/stop, progress, frame count).\n\n---\n\n## License\n\nMIT © Jaume Sanchez Elias — https://www.clicktorelease.com\n","readmeFilename":"README.md","users":{"andrej":true,"rexpan":true,"scottyfillups":true}}