{"_id":"@basementuniverse/animation","_rev":"10-e67fd48b0e93b23f73dc471a74ce5c73","name":"@basementuniverse/animation","dist-tags":{"latest":"1.5.1"},"versions":{"1.0.0":{"name":"@basementuniverse/animation","version":"1.0.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.0.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"3debbcf93d9b0f0bd0c14516350e936ab3dc5561","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.0.0.tgz","fileCount":5,"integrity":"sha512-InMmwArU1y7eOO+Wyl7iYp9VgXc59D+DhRJ+3Hd18AQGungfhHxMbI2NtKke+oKEHKMLMvOmJKXoxuau72ncbg==","signatures":[{"sig":"MEQCIFzAQ3V52RyO9rmzByc7HBjaEleliLOnBlPMZOUkFg2wAiAxeK/j/l81nhE82J0O8o6Xm094wWD5a4cLPqM59fC+XA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":78494},"main":"build/index.js","types":"build/index.d.ts","gitHead":"f672dcb261754c86ecb0c5675f8e65e842868001","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.0.0_1757520381603_0.778920014873449","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@basementuniverse/animation","version":"1.1.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.1.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"51da5544f5b646ad6befcabcc9126edb4cc21bcf","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.1.0.tgz","fileCount":5,"integrity":"sha512-kIvunMn/kmygpjDbYc2vbVfXYQebWdBavTQKf8laf9pdfUJXhM2PZ0D4EzMcd+CNQTv9HDoISq0B7/ZtIC2mUQ==","signatures":[{"sig":"MEUCIBjQ1y3IvyR+koJdWge6Y1ps04Vg17hv/BVFvMc3S8h3AiEAvhfPr57ecS4sgrMchnAgmF/JL2H/9Q/kgmki0eY3ZR0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82446},"main":"build/index.js","types":"build/index.d.ts","gitHead":"0b6758113e29640a60b6f1d6fe004b832244974c","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.1.0_1757617012640_0.9213511779084049","host":"s3://npm-registry-packages-npm-production"}},"1.2.0":{"name":"@basementuniverse/animation","version":"1.2.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.2.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"1e913d1f65d50babeab8fb1588dd9ce3d62fff7c","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.2.0.tgz","fileCount":5,"integrity":"sha512-b5MnsnvEWs3V4jQjWG6/uiYo2RL4n0yZuOVqCVgH+QljEi0rWNlomX09vNggOxm0QVGysJCKrEncLwSFaAMFlg==","signatures":[{"sig":"MEQCICzRF0ZKP686HDgDybhtAXmAmRDTbvTFXEz3daNpOhqgAiBdL/2aBlJhYiY2EIGRVlHcDDCPwdEeG8M8vmW3RhOh8w==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82526},"main":"build/index.js","types":"build/index.d.ts","gitHead":"d352144bae575b242a86b46aedd20fadd4184ccf","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.2.0_1757618106937_0.40360944286111256","host":"s3://npm-registry-packages-npm-production"}},"1.2.1":{"name":"@basementuniverse/animation","version":"1.2.1","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.2.1","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"c41e8e01a3783e902fb07f7adadd9f8f1279e077","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.2.1.tgz","fileCount":5,"integrity":"sha512-g/mh0qdLdSwlF9Wevht4ZeGYzmv8OknKm3yV0V4+TVXp/jA4/PQNVrBMMk11yWZbx4HTs+yfinzAllK220lgvA==","signatures":[{"sig":"MEYCIQCcbkEhMT2gSbyOrCDlUNd9TfdAVv8CLHf5B0cQzCLhMwIhAJafxjhGCE6ufSz4bkM0dFQ6zCNt1WnVHZDfFRTQPzaH","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":82612},"main":"build/index.js","types":"build/index.d.ts","gitHead":"e6e5056ce633754187ddb48b9cf7f2e10b967ed3","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.2.1_1757655949588_0.039968470938630984","host":"s3://npm-registry-packages-npm-production"}},"1.2.2":{"name":"@basementuniverse/animation","version":"1.2.2","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.2.2","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"9b7760a4546bf85e009bc4294908725a4c5c5bd7","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.2.2.tgz","fileCount":5,"integrity":"sha512-SDPwpXs5KUAWz15bbPiwC0d/mB0wEqJa89PzdPxIdho4fPZg9eyYZfwfaQbL+x3zmEqVmGCR3VNdVr3wd0bhRg==","signatures":[{"sig":"MEQCIE8zSFw1cy19cOFgIONRLrqR9WnBFtCoahI93+03tp8GAiBQUt9tJp8XsKb3gIeKxltrcjRAcrn6XTGLBPF/vDSXFQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83041},"main":"build/index.js","types":"build/index.d.ts","gitHead":"adde7a4e04fc14f78c48fc29eb37857f9903dccf","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.2.2_1758346758784_0.3057357768079312","host":"s3://npm-registry-packages-npm-production"}},"1.2.3":{"name":"@basementuniverse/animation","version":"1.2.3","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.2.3","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"916e4060e29d046e3bb828eaa3120d562f3671da","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.2.3.tgz","fileCount":5,"integrity":"sha512-Yh7h+pInVI0hdvlGBMteL/7sm4jUjeHNsCwFQh/fA7ywJH4JDX50szwEH6vhhKQYfzeVXunHBkxkNKSNaHVkqg==","signatures":[{"sig":"MEYCIQCSkEsx0uLVQVbsY2AEB53+EhvV3khlKcauU90pgtDnEAIhAPJsLSdvdzRzZQR598LgX8aO7TOrq2RyTpm2/Z6SpzqC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":83339},"main":"build/index.js","types":"build/index.d.ts","gitHead":"2e9080c4153e50a4fc75e978553d5a21f12f548d","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.5.1","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.5.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.2.3_1761608879368_0.5865080727277632","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"@basementuniverse/animation","version":"1.3.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.3.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"329dede4058f00304dbb524da2a711720b2a7bc5","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.3.0.tgz","fileCount":5,"integrity":"sha512-SE9Plk4khbT3YyQP/pmlTCT3tAlM04DLN9XJOclqyxYwOuBOMwJgFNc4xKVWor4IZ/oQh3PUq2Fs5YSuouZrLg==","signatures":[{"sig":"MEQCIF5d+EkUScobGKitHrLhiwhrAl+gNwGXU37XGXjb1KN1AiADFbtG0+/sYSTGamAHQbEyrPzYS+72x94TgOXuxL14Hg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":99668},"main":"build/index.js","types":"build/index.d.ts","gitHead":"174feefa8afcfb0bb2b08ad7aa88df404ff482c9","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.6.2","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.3.0_1769894451637_0.8899639387858931","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"@basementuniverse/animation","version":"1.4.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.4.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"0a5bafdefa7100803f6cd8241282ed6bb4f41716","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.4.0.tgz","fileCount":5,"integrity":"sha512-uuJM1bpfadELg7GLIssvtcHkRO48kcerQWhiM6SIsmeMsizwhQfAU1e0aEvo9X8SxV39D8RdQ8PCGGyvC/8OZA==","signatures":[{"sig":"MEYCIQC43JK9eEhdXB6vVxfkx1rKOvZ2QhJ+BspPGMgn1xneGgIhAKOQpv1U6RONszE8Rd1hvqB8hV7UQVecUS5FqUbKqyGu","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":125246},"main":"build/index.js","types":"build/index.d.ts","gitHead":"2022d4380adb7937f921e176f9cc5c22af61c39b","scripts":{"build":"webpack","watch":"webpack --watch"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.6.2","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@basementuniverse/vec":"^2.3.5","@basementuniverse/utils":"^1.7.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.4.0_1772984504072_0.5853120817015485","host":"s3://npm-registry-packages-npm-production"}},"1.5.0":{"name":"@basementuniverse/animation","version":"1.5.0","author":{"url":"https://gordonlarrigan.com","name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com"},"license":"MIT","_id":"@basementuniverse/animation@1.5.0","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"homepage":"https://github.com/basementuniverse/animation#readme","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"dist":{"shasum":"7346bab7efa138771fbd7469d0da496f0d2b5140","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.5.0.tgz","fileCount":5,"integrity":"sha512-TOHzKKd0EZQvoLLP3uNTUWTyiQ+bHPmxQbMskRLbhh3GCV35mBD9Lp7PprPo5TXXvANrzG5N0/RrA66dlpCwVQ==","signatures":[{"sig":"MEYCIQD/O8bJHg5GNMC9lvdGmmjdAUh9aSfHl26TlVxrwIE/RAIhAPBDyu2I6o95XIjz4VkEVylZB/MBB+a1lZwNdVMpZ1Y9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":72427},"main":"build/index.js","types":"build/index.d.ts","gitHead":"62850579f62d75b5c7c8891e79a08fcc711a3f08","scripts":{"build":"webpack --mode production","watch":"webpack --watch","build:dev":"webpack --mode development"},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"repository":{"url":"git+https://github.com/basementuniverse/animation.git","type":"git"},"_npmVersion":"11.6.2","description":"A component for animating values in browser games","directories":{},"_nodeVersion":"24.12.0","dependencies":{"@basementuniverse/vec":"^2.5.1","@basementuniverse/color":"^1.6.0","@basementuniverse/utils":"^1.8.1"},"_hasShrinkwrap":false,"devDependencies":{"webpack":"^5.3.2","ts-loader":"^8.0.7","typescript":"^4.9.4","@types/node":"^18.11.12","webpack-cli":"^4.1.0","clean-webpack-plugin":"^4.0.0-alpha.0"},"_npmOperationalInternal":{"tmp":"tmp/animation_1.5.0_1786813449061_0.022198037980414753","host":"s3://npm-registry-packages-npm-production"}},"1.5.1":{"name":"@basementuniverse/animation","version":"1.5.1","description":"A component for animating values in browser games","author":{"name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com","url":"https://gordonlarrigan.com"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/basementuniverse/animation.git"},"main":"build/index.js","types":"build/index.d.ts","scripts":{"build":"webpack --mode production","build:dev":"webpack --mode development","watch":"webpack --watch"},"dependencies":{"@basementuniverse/color":"^1.6.1","@basementuniverse/utils":"^1.8.1","@basementuniverse/vec":"^2.5.1"},"devDependencies":{"@types/node":"^18.11.12","clean-webpack-plugin":"^4.0.0-alpha.0","ts-loader":"^8.0.7","typescript":"^4.9.4","webpack":"^5.3.2","webpack-cli":"^4.1.0"},"gitHead":"c9e88b6d1970d12c91705467d61a5de8ad0923df","_id":"@basementuniverse/animation@1.5.1","bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"homepage":"https://github.com/basementuniverse/animation#readme","_nodeVersion":"24.12.0","_npmVersion":"11.6.2","dist":{"integrity":"sha512-viYwmcpRgkKd8PetPGikA49IFgU24LEvpVquSS8FKjC2DDg6QTFAif9wNIMxWZDRiXh0/aZXPEujcd90sXLKSw==","shasum":"1376086624abcad26fc154d0cc4c4a7b931061b0","tarball":"https://registry.npmjs.org/@basementuniverse/animation/-/animation-1.5.1.tgz","fileCount":5,"unpackedSize":72427,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIG06+xdNbDijVViK5SCVFIclejyzI7M+cWto64BZ5Eo+AiEAlP1r2AK3fVBEYS3Yy81NPQkwCt6cY52ipKaZleh/q+w="}]},"_npmUser":{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"},"directories":{},"maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/animation_1.5.1_1786898619699_0.27158781739974436"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-10T16:06:21.402Z","modified":"2026-08-16T16:43:40.022Z","1.0.0":"2025-09-10T16:06:21.837Z","1.1.0":"2025-09-11T18:56:52.830Z","1.2.0":"2025-09-11T19:15:07.149Z","1.2.1":"2025-09-12T05:45:49.779Z","1.2.2":"2025-09-20T05:39:19.001Z","1.2.3":"2025-10-27T23:47:59.588Z","1.3.0":"2026-01-31T21:20:51.791Z","1.4.0":"2026-03-08T15:41:44.228Z","1.5.0":"2026-08-15T17:04:09.197Z","1.5.1":"2026-08-16T16:43:39.851Z"},"bugs":{"url":"https://github.com/basementuniverse/animation/issues"},"author":{"name":"Gordon Larrigan","email":"gordonlarrigan@gmail.com","url":"https://gordonlarrigan.com"},"license":"MIT","homepage":"https://github.com/basementuniverse/animation#readme","repository":{"type":"git","url":"git+https://github.com/basementuniverse/animation.git"},"description":"A component for animating values in browser games","maintainers":[{"name":"basementuniverse","email":"gordonlarrigan@gmail.com"}],"readme":"# Game Component: Animation\n\nA component for creating keyframe animations or interpolated animations for scalar values, vectors, and colors.\n\n## Installation\n\n```bash\nnpm install @basementuniverse/animation\n```\n\nFor direct browser usage, include the UMD build with a script tag:\n\n```html\n<script src=\"build/index.js\"></script>\n```\n\nThe build exposes its exports through the `BasementUniverseAnimation` browser\nnamespace. It does not add each export directly to `window`.\n\n## How to use\n\nSee `/demos` for some examples.\n\n```ts\nimport {\n  AnimationMode,\n  RepeatMode,\n  Animation,\n  type AnimationOptions,\n  MultiAnimation,\n  EasingFunctions,\n} from '@basementuniverse/animation';\n```\n\nWhen using the library directly from a browser script, prefix exports with\n`BasementUniverseAnimation`:\n\n```html\n<script src=\"build/index.js\"></script>\n<script>\n  const animation = new BasementUniverseAnimation.Animation({\n    initialValue: 100,\n    targetValue: 500,\n    duration: 3,\n  });\n\n  animation.update(1 / 60);\n  console.log(animation.current);\n</script>\n```\n\n### `Animation`\n\nCreate an animation:\n\n```ts\nconst animation = new Animation({\n  initialValue: 100,\n  targetValue: 500,\n  mode: AnimationMode.Auto,\n  repeat: RepeatMode.Once,\n  repeats: 0,\n  duration: 3,\n  delay: 0,\n  clamp: false,\n  round: false,\n  easeAmount: 0,\n  stops: [],\n  interpolationFunction: 'linear',\n  interpolationFunctionParameters: [],\n});\n```\n\nUpdate the animation every frame:\n\n```ts\nfunction update(dt) {\n  animation.update(dt);\n}\n```\n\nUse the animated value:\n\n```ts\nconst value = animation.current;\n```\n\nControl the animation:\n\n```ts\nanimation.start();\nanimation.stop();\nanimation.reset();\n```\n\nThe animated value can be `number`, `vec2`, `vec3`, or `Color`.\n\n```ts\ntype vec2 = {\n  x: number;\n  y: number;\n};\n\ntype vec3 = {\n  x: number;\n  y: number;\n  z: number;\n};\n\ntype Color = {\n  r: number;\n  g: number;\n  b: number;\n  a?: number;\n};\n```\n\nPublic properties:\n\n- `progress`: Current normalised progress of the animation (0 to 1)\n- `running`: Whether the animation is currently running\n- `holding`: Whether the animation is currently being held (for `Hold` mode)\n- `direction`: Direction of the animation (1 = forward, -1 = backward)\n- `repeatCount`: Number of completed repeats\n- `finished`: Whether the animation has finished (for `Once` repeat mode)\n\n### `MultiAnimation`\n\n```ts\nconst multiAnimation = new MultiAnimation({\n  // The _default animation will be used as a base for all other animations\n  _default: {\n    mode: AnimationMode.Auto,\n    repeat: RepeatMode.PingPong,\n    duration: 2,\n    interpolationFunction: 'ease-in-out-cubic',\n  },\n  scale: {\n    initialValue: 1,\n    targetValue: 2,\n    duration: 1,\n  },\n  rotation: {\n    initialValue: 0,\n    targetValue: Math.PI * 2,\n    repeat: RepeatMode.Loop,\n    duration: 3,\n  },\n  // etc.\n});\n```\n\n### Spline Interpolation\n\nThe library includes built-in support for animating along Bezier and Catmull-Rom splines:\n\n```ts\nimport { bezierPath, catmullRomPath } from '@basementuniverse/animation';\n\n// Cubic Bezier path with control points in normalized space\nconst bezierAnimation = new Animation({\n  initialValue: { x: 0, y: 0 },\n  targetValue: { x: 100, y: 100 },\n  duration: 2,\n  interpolationFunction: bezierPath({\n    points: [\n      { x: 0.25, y: 0.8 },  // Control point 1\n      { x: 0.75, y: 0.2 }   // Control point 2\n    ],\n    order: 3,              // Cubic Bezier (1=linear, 2=quadratic, 3=cubic)\n    relative: 'start-end', // Points in normalized 0-1 space\n    useAnimationEndpoints: true  // Use initialValue/targetValue as endpoints\n  })\n});\n\n// Catmull-Rom spline through multiple waypoints\nconst splineAnimation = new Animation({\n  initialValue: { x: 0, y: 0 },\n  targetValue: { x: 300, y: 300 },\n  duration: 3,\n  interpolationFunction: catmullRomPath({\n    points: [\n      { x: 50, y: 200 },   // Waypoint 1\n      { x: 150, y: 50 },   // Waypoint 2\n      { x: 250, y: 250 }   // Waypoint 3\n    ],\n    tension: 0.5,          // Controls curve tightness (0-1)\n    relative: 'none'       // Absolute coordinates\n  })\n});\n```\n\n#### Relative positioning modes\n\nBoth `bezierPath` and `catmullRomPath` support three positioning modes:\n\n- `'none'`: Points are absolute coordinates\n- `'start'`: Points are offsets from `initialValue`\n- `'start-end'`: Points are in normalized 0-1 space, scaled between `initialValue` and `targetValue`\n\n```ts\n// Example: Start-relative positioning\nconst animation = new Animation({\n  initialValue: { x: 100, y: 100 },\n  targetValue: { x: 400, y: 400 },\n  interpolationFunction: bezierPath({\n    points: [\n      { x: 50, y: -50 },   // 50 units right, 50 units up from start\n      { x: 250, y: 150 }   // 250 units right, 150 units down from start\n    ],\n    order: 3,\n    relative: 'start'\n  })\n});\n```\n\nSee `./demos/spline-animation.html` for interactive examples.\n\n### Markers\n\nMarkers allow you to trigger events at specific points during an animation. They can be defined using either absolute time (in seconds) or normalized progress (0-1).\n\n```ts\nimport { MarkerDirection } from '@basementuniverse/animation';\n\nconst animation = new Animation({\n  initialValue: 0,\n  targetValue: 100,\n  duration: 5,\n  markers: [\n    {\n      progress: 0.25,  // Fire at 25% through the animation\n      name: 'quarter',\n      callback: (marker) => {\n        console.log(`Reached ${marker.name}`);\n      }\n    },\n    {\n      time: 3,  // Fire at 3 seconds (time takes precedence over progress)\n      name: 'three-seconds',\n      direction: MarkerDirection.Forward,  // Only fire when playing forward\n      once: true,  // Only fire once per loop\n      callback: (marker) => {\n        console.log('3 seconds elapsed');\n      }\n    },\n    {\n      progress: 0.75,\n      global: true,  // Only fire once in the animation's lifetime\n      callback: () => {\n        console.log('Passed 75% mark for the first time');\n      }\n    }\n  ],\n  onMarkerReached: (marker) => {\n    // Global callback for all markers\n    console.log('Any marker reached:', marker.name);\n  }\n});\n```\n\nMarker options:\n\n- `time?: number` - Time in seconds (takes precedence over `progress`)\n- `progress?: number` - Normalized progress (0-1)\n- `name?: string` - Optional name for the marker\n- `direction?: MarkerDirection` - When to fire: `Forward`, `Backward`, or `Both` (default)\n- `once?: boolean` - If true, only fires once per loop (resets on repeat boundaries)\n- `global?: boolean` - If true, only fires once in the animation's lifetime\n- `callback: (marker) => void` - Function to call when marker is reached\n\n### AnimationTimeline\n\n`AnimationTimeline` allows you to coordinate multiple animations with precise timing control, creating complex sequences and choreographies.\n\n```ts\nimport { AnimationTimeline, AnimationTimelineMode } from '@basementuniverse/animation';\n\nconst timeline = new AnimationTimeline({\n  mode: AnimationTimelineMode.Auto,\n  durationMode: 'relative',  // or 'absolute'\n  duration: 10,  // Total timeline duration (required for relative mode)\n  onFinished: () => console.log('Timeline complete'),\n  onTrackStart: (track) => console.log('Track started:', track.label),\n  onTrackEnd: (track) => console.log('Track ended:', track.label),\n  onMarkerReached: (marker, track) => {\n    console.log('Marker reached in track:', track.label, marker.name);\n  }\n});\n\n// Add animations with relative timing (0-1 progress)\nconst anim1 = new Animation({\n  initialValue: 0,\n  targetValue: 100,\n  duration: 2\n});\ntimeline.addAnimation(anim1, 0, 0.2, 'fadeIn');  // start=0%, end=20%\n\n// Add animations with relative timing (0-1 progress)\n// When durationMode is 'relative', times are normalized to timeline duration\nconst anim2 = new Animation({\n  initialValue: { x: 0, y: 0 },\n  targetValue: { x: 100, y: 100 },\n  duration: 3\n});\ntimeline.addAnimation(anim2, 0.2, 0.5, 'move');  // starts at 20%, ends at 50%\n\n// Add multi-animations\nconst multiAnim = new MultiAnimation({\n  scale: { initialValue: 1, targetValue: 2 },\n  rotation: { initialValue: 0, targetValue: Math.PI }\n});\ntimeline.addMultiAnimation(multiAnim, 0.5, 1, 'scaleAndRotate');\n\n// Control the timeline\ntimeline.start();\ntimeline.stop();\ntimeline.reset();\n\n// Seek to specific time or progress\ntimeline.seek(3.5);  // Seek to 3.5 seconds\ntimeline.seekToProgress(0.5);  // Seek to 50%\n\n// Update in game loop\nfunction update(dt) {\n  timeline.update(dt);\n\n  // Get current values from active tracks\n  const current = timeline.current;\n  // current = { fadeIn: 50, move: { x: 50, y: 50 }, ... }\n}\n```\n\nTimeline options:\n\n- `mode?: AnimationTimelineMode` - `Auto` (starts immediately), `Trigger` (manual start), or `Manual` (controlled by progress/time)\n- `durationMode?: 'absolute' | 'relative'` - How track times are interpreted\n  - `'absolute'`: Track times are in seconds\n  - `'relative'`: Track times are normalized 0-1 values, scaled to timeline duration\n- `duration?: number` - Total timeline duration (required for relative mode)\n- Callbacks: `onFinished`, `onTrackStart`, `onTrackEnd`, `onMarkerReached`\n\nPublic properties:\n\n- `globalTime: number` - Current time in seconds\n- `duration: number` - Total duration of the timeline\n- `progress: number` - Normalized progress (0-1), can be set for scrubbing\n- `running: boolean` - Whether timeline is playing\n- `finished: boolean` - Whether timeline has finished\n- `current: object` - Object containing current values from all labeled tracks\n\nSee `./demos/timeline-animation.html` for interactive examples.\n\n## Animation options\n\n```ts\nexport enum AnimationMode {\n  /**\n   * Animation starts automatically when created\n   */\n  Auto = 'auto',\n\n  /**\n   * Animation starts when triggered manually by calling the `start` method\n   */\n  Trigger = 'trigger',\n\n  /**\n   * Animation plays while triggered, and reverses when not triggered\n   */\n  Hold = 'hold',\n\n  /**\n   * Animation is controlled manually by setting the progress\n   */\n  Manual = 'manual',\n}\n\nexport enum RepeatMode {\n  /**\n   * Animation will play once and then stop\n   */\n  Once = 'once',\n\n  /**\n   * Animation will loop indefinitely\n   */\n  Loop = 'loop',\n\n  /**\n   * Animation will play forward and then reverse, repeating indefinitely\n   */\n  PingPong = 'pingpong',\n}\n\nexport type AnimationOptions<T extends AnimatableValue> = {\n  /**\n   * The initial value for this animation\n   */\n  initialValue: T;\n\n  /**\n   * The target value for this animation\n   */\n  targetValue: T;\n\n  /**\n   * The mode of this animation:\n   *\n   * - Auto: Animation starts automatically when created\n   * - Trigger: Animation starts when triggered manually by calling the `start`\n   *   method\n   * - Hold: Animation plays while triggered, and reverses when not triggered\n   * - Manual: Animation is controlled manually by setting the progress\n   *\n   * Default is Auto\n   */\n  mode: AnimationMode;\n\n  /**\n   * The repeat mode of this animation:\n   *\n   * - Once: Animation will play once and then stop\n   * - Loop: Animation will loop indefinitely or a specific number of times\n   * - PingPong: Animation will play forward and then reverse, repeating\n   *   indefinitely or a specific number of times\n   *\n   * Default is Once\n   */\n  repeat: RepeatMode;\n\n  /**\n   * If repeat mode is Loop or PingPong, the number of times to repeat the\n   * animation\n   *\n   * Default is 0 (repeat indefinitely)\n   */\n  repeats: number;\n\n  /**\n   * The duration of this animation in seconds\n   */\n  duration: number;\n\n  /**\n   * Optional delay before the animation starts, in seconds\n   */\n  delay?: number;\n\n  /**\n   * If true, the progress value will be clamped between 0 and 1\n   *\n   * When this is false, we can have \"overshoot\" values less than 0 or greater\n   * than 1\n   */\n  clamp?: boolean;\n\n  /**\n   * If true, the value will be rounded to the nearest integer\n   *\n   * Alternatively, we can provide a custom rounding function which takes the\n   * value and returns the rounded value\n   */\n  round?: boolean | ((value: T) => T);\n\n  /**\n   * Optionally ease the value towards the target value over time (exponential\n   * easing)\n   *\n   * A higher value means more easing:\n   * - 0 to disable easing (value will change immediately)\n   * - 1 to enable full easing (value will never change)\n   */\n  easeAmount?: number;\n\n  /**\n   * An array of stops for keyframe animations. Each stop should have a progress\n   * value between 0 and 1, and a corresponding value for the animation at that\n   * progress point\n   *\n   * If a stop with progress 0 or 1 is provided, these will take precendence\n   * over the initialValue and targetValue options, otherwise the initialValue\n   * and targetValue will be used as the first and last stops respectively\n   *\n   * Stops should be provided in ascending order of progress (from 0 to 1)\n   */\n  stops?: {\n    progress: number;\n    value: T;\n  }[];\n\n  /**\n   * How to interpolate between initial and target values, or between keyframes\n   *\n   * Default interpolation function is 'linear'\n   *\n   * See `EasingFunctions` for a list of built-in easing functions\n   */\n  interpolationFunction?:\n    | keyof typeof EasingFunctions\n    | ((a: T, b: T, i: number, ...params: any[]) => T);\n\n  /**\n   * Optional parameters to pass to the interpolation function\n   */\n  interpolationFunctionParameters?: any[];\n\n  /**\n   * Optional callback when the animation reaches the end\n   *\n   * This will be called every time the animation progress reaches 1\n   */\n  onFinished?: () => void;\n\n  /**\n   * Optional callback each time the animation repeats (only for Loop and\n   * PingPong repeat modes)\n   *\n   * The callback receives the current repeat count (starting from 1)\n   */\n  onRepeat?: (count: number) => void;\n\n  /**\n   * Optional callback each time the animation reaches a stop/keyframe\n   *\n   * The callback receives the index of the stop reached (starting from 0)\n   */\n  onStopReached?: (index: number) => void;\n};\n```\n\n## Built-in easing functions\n\nSee `./demos/easing-functions.html` for a demo of all built-in easing functions.\n","readmeFilename":"README.md"}