This commit is contained in:
Kurtis Lew 2023-05-17 13:35:47 -04:00 committed by GitHub
commit adde23d6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
50 changed files with 2625 additions and 15 deletions

1
docs/.gitignore vendored
View file

@ -3,6 +3,7 @@
# Production # Production
/build /build
/static/animations/
# Generated files # Generated files
.docusaurus .docusaurus

View file

@ -5,6 +5,7 @@ sidebar_label: Hold-Tap
import Tabs from '@theme/Tabs'; import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem'; import TabItem from '@theme/TabItem';
import AnimationPlayer from '@site/src/components/AnimationPlayer';
## Summary ## Summary
@ -12,28 +13,75 @@ Hold-tap is the basis for other behaviors such as layer-tap and mod-tap.
Simply put, the hold-tap key will output the 'hold' behavior if it's held for a while, and output the 'tap' behavior when it's tapped quickly. Simply put, the hold-tap key will output the 'hold' behavior if it's held for a while, and output the 'tap' behavior when it's tapped quickly.
### Hold-Tap ### Flavors
The graph below shows how the hold-tap decides between a 'tap' and a 'hold'. The 'flavor' of a hold-tap determines its behavior when it is tapped, held, and when another key is pressed while the hold-tap is undecided. For example, the [mod-tap](mod-tap.md) is a 'hold-preferred' hold-tap, while the [layer-tap](layers.md/#layer-tap) is of the 'tap-preferred' variety.
![Simple behavior](../assets/hold-tap/case1_2.svg) <Tabs
defaultValue="hold-preferred"
values={[
{label: 'Hold-Preferred', value: 'hold-preferred'},
{label: 'Balanced', value: 'balanced'},
{label: 'Tap-Preferred', value: 'tap-preferred'},
{label: 'Tap-Unless-Interrupted', value: 'tap-unless-interrupted'},
]}>
<TabItem value="hold-preferred">
The simplest flavor, 'hold-preferred', triggers the hold behavior when the [`tapping-term-ms`](#tapping-term-ms) has expired or another key is pressed.
When the hold-tap key is released and the hold behavior has not been triggered, the tap behavior will trigger.
<AnimationPlayer auto small name="hold_tap_comparison" />
By default, the hold-tap is configured to also select the 'hold' functionality if another key is tapped while it's active: By default, the hold-tap is configured to also select the 'hold' functionality if another key is tapped while it's active:
![Hold preferred behavior](../assets/hold-tap/case_hold_preferred.svg) <AnimationPlayer auto small name="hold_tap_interrupted" />
We call this the 'hold-preferred' flavor of hold-taps. While this flavor may work very well for a ctrl/escape key, it's not very well suited for home-row mods or layer-taps. That's why there are two more flavors to choose from: 'tap-preferred' and 'balanced'. While this flavor may work very well for a ctrl/escape key, it's not very well suited for home-row mods or layer-taps. That's why there are more flavors to choose from: 'balanced', 'tap-preferred' and 'tap-unless-interrupted'.
#### Flavors </TabItem>
- The 'hold-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired or another key is pressed. <TabItem value="balanced">
- The 'balanced' flavor will trigger the hold behavior when the `tapping-term-ms` has expired or another key is pressed and released.
- The 'tap-preferred' flavor triggers the hold behavior when the `tapping-term-ms` has expired. Pressing another key within `tapping-term-ms` does not affect the decision.
- The 'tap-unless-interrupted' flavor triggers a hold behavior only when another key is pressed before `tapping-term-ms` has expired. It triggers the tap behavior in all other situations.
When the hold-tap key is released and the hold behavior has not been triggered, the tap behavior will trigger. The 'balanced' flavor triggers the hold behavior when the [`tapping-term-ms`](#tapping-term-ms) has expired.
![Hold-tap comparison](../assets/hold-tap/comparison.svg) <AnimationPlayer auto small name="balanced_comparison" />
Alternatively, if another key is pressed while the 'balanced' hold-tap pressed, releasing the _hold-tap_ before the interrupting keypress will invoke the tap behavior.
<AnimationPlayer auto small name="balanced_hold_tap_up" />
On the other hand, if the _interrupting key_ is released before the hold-tap, the hold behavior will be invoked.
<AnimationPlayer auto small name="balanced_other_key_up" />
</TabItem>
<TabItem value="tap-preferred">
The 'tap-preferred' flavor triggers the hold behavior when the [`tapping-term-ms`](#tapping-term-ms) has expired.
<AnimationPlayer auto small name="tap_preferred_comparison" />
As shown below, pressing another key within [`tapping-term-ms`](#tapping-term-ms) does not affect the hold-tap decision; only the press duration will decide if the 'tap-preferred' hold-tap is a 'hold' or a 'tap'.
<AnimationPlayer auto small name="tap_preferred_hold_tap_up" />
</TabItem>
<TabItem value="tap-unless-interrupted">
The press duration of the 'tap-unless-interrupted' flavor of hold-tap does not have an effect on the output: the 'tap' behavior will always be invoked.
<AnimationPlayer auto small name="tap_unless_interrupted" />
Only another key being pressed can invoke the 'hold' behavior.
<AnimationPlayer auto small name="tap_unless_interrupted_invoke_hold" />
</TabItem>
</Tabs>
### Basic usage ### Basic usage
@ -43,7 +91,7 @@ For basic usage, please see the [mod-tap](mod-tap.md) and [layer-tap](layers.md#
#### `tapping-term-ms` #### `tapping-term-ms`
Defines how long a key must be pressed to trigger Hold behavior. Defines how long a key must be pressed to trigger the 'hold' behavior.
#### `quick-tap-ms` #### `quick-tap-ms`

878
docs/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -4,7 +4,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "docusaurus start --host 0.0.0.0", "start": "docusaurus start --host 0.0.0.0",
"build": "docusaurus build", "build": "npm run build_animations && docusaurus build",
"serve": "docusaurus serve", "serve": "docusaurus serve",
"swizzle": "docusaurus swizzle", "swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy", "deploy": "docusaurus deploy",
@ -12,7 +12,8 @@
"lint": "eslint . --ext js,jsx,md,mdx", "lint": "eslint . --ext js,jsx,md,mdx",
"prettier:check": "prettier --check .", "prettier:check": "prettier --check .",
"prettier:format": "prettier --write .", "prettier:format": "prettier --write .",
"typecheck": "tsc" "typecheck": "tsc",
"build_animations": "cd src/animationhelpers && npm run build"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "^2.1.0", "@docusaurus/core": "^2.1.0",
@ -21,6 +22,11 @@
"@fortawesome/free-solid-svg-icons": "^5.15.3", "@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.18", "@fortawesome/react-fontawesome": "^0.1.18",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",
"@motion-canvas/2d": "^2.2.0",
"@motion-canvas/core": "^2.2.0",
"@motion-canvas/player": "^2.2.0",
"@motion-canvas/ui": "^2.2.0",
"@motion-canvas/vite-plugin": "^2.2.0",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"react": "^17.0.2", "react": "^17.0.2",

15
docs/src/animationhelpers/.gitignore vendored Normal file
View file

@ -0,0 +1,15 @@
# Generated files
node_modules
output
dist
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View file

@ -0,0 +1,710 @@
{
"name": "animationhelpers",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "animationhelpers",
"version": "0.0.0",
"dependencies": {
"@motion-canvas/2d": "^2.2.0",
"@motion-canvas/core": "^2.2.0"
},
"devDependencies": {
"@motion-canvas/ui": "^2.2.0",
"@motion-canvas/vite-plugin": "^2.2.0",
"typescript": "^4.9.5",
"vite": "^3.0.5"
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
"integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
"integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
"cpu": [
"loong64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/@motion-canvas/2d": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@motion-canvas/2d/-/2d-2.2.0.tgz",
"integrity": "sha512-IE/svVCBsD1EAqBoMtkuFovO8IrDG55BOqo1CgfwDLvhoKC1PnGgseBDNXT4CfCPlCsJ+M/xWWCFiYK3YIOi3Q==",
"dependencies": {
"@motion-canvas/core": "^2.2.0",
"code-fns": "^0.7.0"
}
},
"node_modules/@motion-canvas/core": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@motion-canvas/core/-/core-2.2.0.tgz",
"integrity": "sha512-iGVKp6Sl7rvmZHCM0LObnpG9KqK7ch7UBItx03l2BQFcqf/ltBANDzJulF2MZBdEXVj7vgwuRZidfAJxTyBQEA==",
"dependencies": {
"@types/chroma-js": "^2.1.4",
"chroma-js": "^2.4.2"
},
"peerDependencies": {
"vite": "^3.0.5"
}
},
"node_modules/@motion-canvas/ui": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@motion-canvas/ui/-/ui-2.2.0.tgz",
"integrity": "sha512-97r6Zee6PVUcBCtK+RtKi/f9Z+vKVtWR/FzrAVJUq3t0icduiDKRmxIEBwNyaWcHaSXAlBf9widZ1NkXrjASLA==",
"dev": true,
"dependencies": {
"@motion-canvas/core": "^2.2.0"
}
},
"node_modules/@motion-canvas/vite-plugin": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/@motion-canvas/vite-plugin/-/vite-plugin-2.2.0.tgz",
"integrity": "sha512-D9K/pl5NmSiCcAqBiGVkd1v6uuBD94jOH1yV2Dxur5ziCf6AjIV0DACKsWH8JE7KEDWuWfeJlbCoFkH+p9JbJA==",
"dev": true,
"dependencies": {
"mime-types": "^2.1.35"
},
"peerDependencies": {
"vite": "3.x"
}
},
"node_modules/@types/chroma-js": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@types/chroma-js/-/chroma-js-2.1.5.tgz",
"integrity": "sha512-LnJmElng1zoH7GOYqIo/EuL7L0/vEh5rc+fKaF4rsylJyjwOkX0pXeBemH25FQAWHifKJWqaRwR0EhC+yDod9A=="
},
"node_modules/@types/hast": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.4.tgz",
"integrity": "sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g==",
"dependencies": {
"@types/unist": "*"
}
},
"node_modules/@types/unist": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz",
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
},
"node_modules/@wooorm/starry-night": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@wooorm/starry-night/-/starry-night-1.5.0.tgz",
"integrity": "sha512-YEkNgM8IxKwzRQgTp1nyiraB5rc4LiLpnMTrJvX5+SVs7zgVqkTx6QAZgZFqrZrqq/UCWVYBzE9+zZfxpLPTYQ==",
"dependencies": {
"@types/hast": "^2.0.0",
"import-meta-resolve": "^2.0.0",
"vscode-oniguruma": "^1.0.0",
"vscode-textmate": "^7.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/chroma-js": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz",
"integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A=="
},
"node_modules/code-fns": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/code-fns/-/code-fns-0.7.1.tgz",
"integrity": "sha512-5OXF24qyo2bcW52h2mJesu2N+5hu6jk8P32SyFjjQUO2YQRgbpv3sRrF9mSmaJwvAf7B69nQBkHPTzcH35Hlmg==",
"dependencies": {
"@wooorm/starry-night": "^1.2.0"
}
},
"node_modules/esbuild": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
"hasInstallScript": true,
"bin": {
"esbuild": "bin/esbuild"
},
"engines": {
"node": ">=12"
},
"optionalDependencies": {
"@esbuild/android-arm": "0.15.18",
"@esbuild/linux-loong64": "0.15.18",
"esbuild-android-64": "0.15.18",
"esbuild-android-arm64": "0.15.18",
"esbuild-darwin-64": "0.15.18",
"esbuild-darwin-arm64": "0.15.18",
"esbuild-freebsd-64": "0.15.18",
"esbuild-freebsd-arm64": "0.15.18",
"esbuild-linux-32": "0.15.18",
"esbuild-linux-64": "0.15.18",
"esbuild-linux-arm": "0.15.18",
"esbuild-linux-arm64": "0.15.18",
"esbuild-linux-mips64le": "0.15.18",
"esbuild-linux-ppc64le": "0.15.18",
"esbuild-linux-riscv64": "0.15.18",
"esbuild-linux-s390x": "0.15.18",
"esbuild-netbsd-64": "0.15.18",
"esbuild-openbsd-64": "0.15.18",
"esbuild-sunos-64": "0.15.18",
"esbuild-windows-32": "0.15.18",
"esbuild-windows-64": "0.15.18",
"esbuild-windows-arm64": "0.15.18"
}
},
"node_modules/esbuild-android-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
"integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-android-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
"integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-darwin-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
"integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-freebsd-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
"integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"freebsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-32": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
"integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
"integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
"integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
"integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-mips64le": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
"integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
"cpu": [
"mips64el"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-ppc64le": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
"integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
"cpu": [
"ppc64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-riscv64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
"integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
"cpu": [
"riscv64"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-linux-s390x": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
"integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
"cpu": [
"s390x"
],
"optional": true,
"os": [
"linux"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-netbsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-openbsd-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
"integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"openbsd"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-sunos-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
"integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"sunos"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-32": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
"integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
"cpu": [
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
"integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/esbuild-windows-arm64": {
"version": "0.15.18",
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
"integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=12"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"hasInstallScript": true,
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
},
"node_modules/has": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
"integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
"dependencies": {
"function-bind": "^1.1.1"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/import-meta-resolve": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-2.2.1.tgz",
"integrity": "sha512-C6lLL7EJPY44kBvA80gq4uMsVFw5x3oSKfuMl1cuZ2RkI5+UJqQXgn+6hlUew0y4ig7Ypt4CObAAIzU53Nfpuw==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-core-module": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz",
"integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==",
"dependencies": {
"has": "^1.0.3"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"dev": true,
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"bin": {
"nanoid": "bin/nanoid.cjs"
},
"engines": {
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/picocolors": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
},
"node_modules/postcss": {
"version": "8.4.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/postcss/"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
}
],
"dependencies": {
"nanoid": "^3.3.4",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
"node_modules/resolve": {
"version": "1.22.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz",
"integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==",
"dependencies": {
"is-core-module": "^2.9.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/rollup": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/source-map-js": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/vite": {
"version": "3.2.5",
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.5.tgz",
"integrity": "sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==",
"dependencies": {
"esbuild": "^0.15.9",
"postcss": "^8.4.18",
"resolve": "^1.22.1",
"rollup": "^2.79.1"
},
"bin": {
"vite": "bin/vite.js"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
},
"peerDependencies": {
"@types/node": ">= 14",
"less": "*",
"sass": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
},
"peerDependenciesMeta": {
"@types/node": {
"optional": true
},
"less": {
"optional": true
},
"sass": {
"optional": true
},
"stylus": {
"optional": true
},
"sugarss": {
"optional": true
},
"terser": {
"optional": true
}
}
},
"node_modules/vscode-oniguruma": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz",
"integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA=="
},
"node_modules/vscode-textmate": {
"version": "7.0.4",
"resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-7.0.4.tgz",
"integrity": "sha512-9hJp0xL7HW1Q5OgGe03NACo7yiCTMEk3WU/rtKXUbncLtdg6rVVNJnHwD88UhbIYU2KoxY0Dih0x+kIsmUKn2A=="
}
}
}

View file

@ -0,0 +1,19 @@
{
"name": "animationhelpers",
"private": true,
"version": "0.0.0",
"scripts": {
"serve": "vite",
"build": "tsc && vite build"
},
"dependencies": {
"@motion-canvas/core": "^2.2.0",
"@motion-canvas/2d": "^2.2.0"
},
"devDependencies": {
"@motion-canvas/ui": "^2.2.0",
"@motion-canvas/vite-plugin": "^2.2.0",
"typescript": "^4.9.5",
"vite": "^3.0.5"
}
}

View file

@ -0,0 +1,82 @@
import { Rect, Text, Node } from "@motion-canvas/2d/lib/components";
import { SignalValue } from "@motion-canvas/core/lib/signals";
import { makeRef } from "@motion-canvas/core/lib/utils";
const KeySize = 200;
const KeyRadius = 10;
export const KeyBorderThickness = 10;
export const KeyTravel = 40;
export default function Key({
refs,
binding,
params,
}: {
refs: {
group: Node;
body: Node;
fill: Rect;
duration: Rect;
shadow: Rect;
binding: Text;
params: Text;
};
binding: SignalValue<string>;
params: SignalValue<string>;
}) {
return (
<Node ref={makeRef(refs, "group")} y={-KeyTravel}>
<Rect
ref={makeRef(refs, "shadow")}
width={KeySize}
height={KeySize}
y={KeyTravel}
radius={KeyRadius}
fill={"#000000"}
stroke={"#000000"}
lineWidth={KeyBorderThickness}
/>
<Node ref={makeRef(refs, "body")}>
<Rect
layout
ref={makeRef(refs, "fill")}
direction={"column-reverse"}
width={KeySize}
height={KeySize}
fill={"#FFFFFF"}
>
<Rect ref={makeRef(refs, "duration")} grow={0} fill={"#FFFFFF"} />
</Rect>
<Rect
width={KeySize}
height={KeySize}
fill={"#FFFFFF00"}
radius={KeyRadius}
stroke={"#000000"}
lineWidth={KeyBorderThickness}
/>
<Text
ref={makeRef(refs, "binding")}
text={binding}
fill={"#000000"}
width={KeySize}
padding={15}
fontWeight={600}
fontSize={32}
fontFamily={"sans-serif"}
y={-65}
/>
<Text
ref={makeRef(refs, "params")}
text={params}
fill={"#000000"}
width={KeySize}
justifyContent={"center"}
fontWeight={600}
fontSize={60}
fontFamily={"sans-serif"}
/>
</Node>
</Node>
);
}

View file

@ -0,0 +1,126 @@
import { Rect, Text } from "@motion-canvas/2d/lib/components";
import { makeRef } from "@motion-canvas/core/lib/utils";
import { KeyBorderThickness } from "./Key";
const OutputThickness = KeyBorderThickness / 2;
const OutputFontSize = 40;
const OutputFontWeight = 600;
const ModifierRadius = 10;
const ModifierFontSize = 32;
const ModifierFontWeight = 600;
const ModifierMargin = 20;
export default function Output({
refs,
}: {
refs: {
group: Rect;
output: Text;
shift: Rect;
alt: Rect;
ctrl: Rect;
gui: Rect;
};
}) {
return (
<Rect layout ref={makeRef(refs, "group")} direction={"column"}>
<Rect
layout
direction={"row"}
alignItems={"center"}
justifyContent={"center"}
radius={ModifierRadius}
stroke={"#000000"}
lineWidth={OutputThickness}
>
<Text
ref={makeRef(refs, "output")}
text={"&#8203"}
fill={"#000000"}
justifyContent={"center"}
fontWeight={OutputFontWeight}
fontSize={OutputFontSize}
fontFamily={"sans-serif"}
margin={ModifierMargin}
/>
</Rect>
<Rect layout direction={"row"} gap={20} marginTop={20}>
<Rect
layout
ref={makeRef(refs, "shift")}
radius={ModifierRadius}
stroke={"#000000"}
lineWidth={OutputThickness}
grow={1}
fill={"#D9D9D9"}
>
<Text
fill={"#000000"}
text={() => "SHIFT"}
fontWeight={ModifierFontWeight}
fontSize={ModifierFontSize}
fontFamily={"sans-serif"}
margin={ModifierMargin}
/>
</Rect>
<Rect
layout
ref={makeRef(refs, "alt")}
radius={ModifierRadius}
stroke={"#000000"}
lineWidth={OutputThickness}
grow={1}
fill={"#D9D9D9"}
>
<Text
fill={"#000000"}
text={() => "ALT"}
fontWeight={ModifierFontWeight}
fontSize={ModifierFontSize}
fontFamily={"sans-serif"}
margin={ModifierMargin}
/>
</Rect>
<Rect
layout
ref={makeRef(refs, "ctrl")}
radius={ModifierRadius}
stroke={"#000000"}
lineWidth={OutputThickness}
grow={1}
fill={"#D9D9D9"}
>
<Text
fill={"#000000"}
text={() => "CTRL"}
fontWeight={ModifierFontWeight}
fontSize={ModifierFontSize}
fontFamily={"sans-serif"}
margin={ModifierMargin}
/>
</Rect>
<Rect
layout
ref={makeRef(refs, "gui")}
radius={ModifierRadius}
stroke={"#000000"}
lineWidth={OutputThickness}
grow={1}
fill={"#D9D9D9"}
>
<Text
fill={"#000000"}
text={() => "GUI"}
fontWeight={ModifierFontWeight}
fontSize={ModifierFontSize}
fontFamily={"sans-serif"}
margin={ModifierMargin}
/>
</Rect>
</Rect>
</Rect>
);
}

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import balanced_comparison from "../../scenes/hold_tap/balanced/balanced_comparison?scene";
export default makeProject({
scenes: [balanced_comparison],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import balanced_hold_tap_up from "../../scenes/hold_tap/balanced/balanced_hold_tap_up?scene";
export default makeProject({
scenes: [balanced_hold_tap_up],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import balanced_other_key_up from "../../scenes/hold_tap/balanced/balanced_other_key_up?scene";
export default makeProject({
scenes: [balanced_other_key_up],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import hold_tap_comparison from "../scenes/hold_tap/hold_tap_comparison?scene";
export default makeProject({
scenes: [hold_tap_comparison],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import hold_tap_interrupted from "../scenes/hold_tap/hold_tap_interrupted?scene";
export default makeProject({
scenes: [hold_tap_interrupted],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import tap_preferred_comparison from "../../scenes/hold_tap/tap_preferred/tap_preferred_comparison?scene";
export default makeProject({
scenes: [tap_preferred_comparison],
background: "#FFFFFF",
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import tap_preferred_hold_tap_up from "../../scenes/hold_tap/tap_preferred/tap_preferred_hold_tap_up?scene";
export default makeProject({
scenes: [tap_preferred_hold_tap_up],
background: "#FFFFFF",
});

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import tap_unless_interrupted from "../../scenes/hold_tap/tap_unless_interrupted/tap_unless_interrupted?scene";
export default makeProject({
scenes: [tap_unless_interrupted],
background: "#FFFFFF",
});

View file

@ -0,0 +1,8 @@
import { makeProject } from "@motion-canvas/core/lib";
import tap_unless_interrupted_invoke_hold from "../../scenes/hold_tap/tap_unless_interrupted/tap_unless_interrupted_invoke_hold?scene";
export default makeProject({
scenes: [tap_unless_interrupted_invoke_hold],
background: "#FFFFFF",
});

View file

@ -0,0 +1 @@
/// <reference types="@motion-canvas/core/project" />

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,53 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const tap = makeRefs<typeof Key>();
view.add(<Key refs={tap} binding={"&ht_bl"} params={"\u21e7 F"} />);
tap.group.position.x(-400);
tap.group.position.y(-150);
tap.duration.fill("#D9D9D9");
const tap_output = makeRefs<typeof Output>();
view.add(<Output refs={tap_output} />);
tap_output.group.position(tap.group.position());
tap_output.group.position.y(tap_output.group.position.y() + 300);
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_bl"} params={"\u21e7 F"} />);
hold.group.position.x(400);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position());
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* all(
tap.body.position.y(KeyTravel, 0.15),
hold.body.position.y(KeyTravel, 0.15)
);
yield* all(
tap.duration.grow(0.5, 1, linear),
delay(1, tap.body.position.y(0, 0.15)),
hold.duration.grow(1, 2, linear)
);
yield* chain(
all(tap.group.rotation(3, 0.03), hold.group.rotation(3, 0.03)),
all(tap.group.rotation(-3, 0.06), hold.group.rotation(-3, 0.06)),
all(tap.group.rotation(0, 0.03), hold.group.rotation(0, 0.03)),
all(tap_output.output.text("f", 0), hold_output.shift.fill("#969696", 0.15))
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(
0.5,
all(tap.duration.grow(0, 0.15), hold.duration.grow(0, 0.15))
);
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,53 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { any, all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const interrupt = makeRefs<typeof Key>();
view.add(<Key refs={interrupt} binding={"&kp"} params={"J"} />);
interrupt.group.position.x(125);
interrupt.group.position.y(-150);
interrupt.duration.fill("#D9D9D9");
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_bl"} params={"\u21e7 F"} />);
hold.group.position.x(-125);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position().addX(125));
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* any(
hold.body.position.y(KeyTravel, 0.15),
hold.duration.grow(0.5, 1, linear)
);
yield* delay(
0.35,
all(
interrupt.body.position.y(KeyTravel, 0.15),
hold.duration.fill("F21D00", 0.15)
)
);
yield* delay(
0.35,
chain(
hold.body.position.y(0, 0.15),
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
hold.duration.grow(0, 0.15),
delay(0.05, hold_output.output.text("f", 0)),
delay(0.05, hold_output.output.text("fj", 0))
)
);
yield* waitFor(0.25);
yield* interrupt.body.position.y(0, 0.15);
yield* waitFor(1);
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,55 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { any, all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const interrupt = makeRefs<typeof Key>();
view.add(<Key refs={interrupt} binding={"&kp"} params={"J"} />);
interrupt.group.position.x(125);
interrupt.group.position.y(-150);
interrupt.duration.fill("#D9D9D9");
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_bl"} params={"\u21e7 F"} />);
hold.group.position.x(-125);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position().addX(125));
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* any(
hold.body.position.y(KeyTravel, 0.15),
hold.duration.grow(0.5, 1, linear)
);
yield* delay(
0.35,
all(
interrupt.body.position.y(KeyTravel, 0.15),
hold.duration.fill("F21D00", 0.15)
)
);
yield* delay(
0.35,
chain(
interrupt.body.position.y(0, 0.15),
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
hold.duration.grow(0, 0.15),
all(
delay(0.05, hold_output.output.text("J", 0)),
hold_output.shift.fill("#969696", 0.1)
)
)
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* waitFor(1);
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,80 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { Text } from "@motion-canvas/2d/lib/components";
import { createRef, makeRefs } from "@motion-canvas/core/lib/utils";
import { all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../components/Key";
import Output from "../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const tap = makeRefs<typeof Key>();
view.add(<Key refs={tap} binding={"&mt"} params={"\u21e7 F"} />);
tap.group.position.x(-400);
tap.group.position.y(-150);
tap.duration.fill("#D9D9D9");
const tap_output = makeRefs<typeof Output>();
view.add(<Output refs={tap_output} />);
tap_output.group.position(tap.group.position());
tap_output.group.position.y(tap_output.group.position.y() + 300);
const tap_label = createRef<typeof Text>();
view.add(
<Text
ref={tap_label}
position={tap.group.position().addY(-160)}
fontWeight={600}
fontSize={64}
fontFamily={"sans-serif"}
>
tap
</Text>
);
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&mt"} params={"\u21e7 F"} />);
hold.group.position.x(400);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position());
hold_output.group.position.y(hold_output.group.position.y() + 300);
const hold_tap = createRef<typeof Text>();
view.add(
<Text
ref={hold_tap}
position={hold.group.position().addY(-160)}
fontWeight={600}
fontSize={64}
fontFamily={"sans-serif"}
>
hold
</Text>
);
yield* waitFor(0.5);
yield* all(
tap.body.position.y(KeyTravel, 0.15),
hold.body.position.y(KeyTravel, 0.15)
);
yield* all(
tap.duration.grow(0.5, 1, linear),
delay(1, tap.body.position.y(0, 0.15)),
hold.duration.grow(1, 2, linear)
);
yield* chain(
all(tap.group.rotation(3, 0.03), hold.group.rotation(3, 0.03)),
all(tap.group.rotation(-3, 0.06), hold.group.rotation(-3, 0.06)),
all(tap.group.rotation(0, 0.03), hold.group.rotation(0, 0.03)),
all(tap_output.output.text("f", 0), hold_output.shift.fill("#969696", 0.15))
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(
0.5,
all(tap.duration.grow(0, 0.15), hold.duration.grow(0, 0.15))
);
});

View file

@ -0,0 +1,3 @@
{
"version": 0
}

View file

@ -0,0 +1,50 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { any, all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../components/Key";
import Output from "../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const interrupt = makeRefs<typeof Key>();
view.add(<Key refs={interrupt} binding={"&kp"} params={"J"} />);
interrupt.group.position.x(125);
interrupt.group.position.y(-150);
interrupt.duration.fill("#D9D9D9");
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&mt"} params={"\u21e7 F"} />);
hold.group.position.x(-125);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position().addX(125));
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* any(
hold.body.position.y(KeyTravel, 0.15),
hold.duration.grow(0.75, 1.5, linear)
);
yield* delay(
1.2,
all(
interrupt.body.position.y(KeyTravel, 0.15),
hold.duration.fill("F21D00", 0.15)
)
);
yield* chain(
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
all(
delay(0.15, hold_output.output.text("J", 0)),
hold_output.shift.fill("#969696", 0.15)
)
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(0.5, hold.duration.grow(0, 0.15));
});

View file

@ -0,0 +1,53 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const tap = makeRefs<typeof Key>();
view.add(<Key refs={tap} binding={"&ht_tp"} params={"\u21e7 F"} />);
tap.group.position.x(-400);
tap.group.position.y(-150);
tap.duration.fill("#D9D9D9");
const tap_output = makeRefs<typeof Output>();
view.add(<Output refs={tap_output} />);
tap_output.group.position(tap.group.position());
tap_output.group.position.y(tap_output.group.position.y() + 300);
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_tp"} params={"\u21e7 F"} />);
hold.group.position.x(400);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position());
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* all(
tap.body.position.y(KeyTravel, 0.15),
hold.body.position.y(KeyTravel, 0.15)
);
yield* all(
tap.duration.grow(0.5, 1, linear),
delay(1, tap.body.position.y(0, 0.15)),
hold.duration.grow(1, 2, linear)
);
yield* chain(
all(tap.group.rotation(3, 0.03), hold.group.rotation(3, 0.03)),
all(tap.group.rotation(-3, 0.06), hold.group.rotation(-3, 0.06)),
all(tap.group.rotation(0, 0.03), hold.group.rotation(0, 0.03)),
all(tap_output.output.text("f", 0), hold_output.shift.fill("#969696", 0.15))
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(
0.5,
all(tap.duration.grow(0, 0.15), hold.duration.grow(0, 0.15))
);
});

View file

@ -0,0 +1,47 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { any, all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const interrupt = makeRefs<typeof Key>();
view.add(<Key refs={interrupt} binding={"&kp"} params={"J"} />);
interrupt.group.position.x(125);
interrupt.group.position.y(-150);
interrupt.duration.fill("#D9D9D9");
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_tp"} params={"\u21e7 F"} />);
hold.group.position.x(-125);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position().addX(125));
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* any(
hold.body.position.y(KeyTravel, 0.15),
hold.duration.grow(0.5, 1, linear)
);
yield* delay(0.35, interrupt.body.position.y(KeyTravel, 0.15));
yield* delay(
0.35,
chain(
hold.body.position.y(0, 0.15),
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
hold.duration.grow(0, 0.15),
delay(0.05, hold_output.output.text("f", 0)),
delay(0.05, hold_output.output.text("fj", 0))
)
);
yield* waitFor(0.25);
yield* interrupt.body.position.y(0, 0.15);
yield* waitFor(1);
});

View file

@ -0,0 +1,62 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const tap = makeRefs<typeof Key>();
view.add(<Key refs={tap} binding={"&ht_tui"} params={"\u21e7 F"} />);
tap.group.position.x(-400);
tap.group.position.y(-150);
tap.duration.fill("#D9D9D9");
const tap_output = makeRefs<typeof Output>();
view.add(<Output refs={tap_output} />);
tap_output.group.position(tap.group.position());
tap_output.group.position.y(tap_output.group.position.y() + 300);
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_tui"} params={"\u21e7 F"} />);
hold.group.position.x(400);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position());
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* all(
tap.body.position.y(KeyTravel, 0.15),
hold.body.position.y(KeyTravel, 0.15)
);
yield* all(
tap.duration.grow(0.5, 1, linear),
delay(
1,
chain(
tap.body.position.y(0, 0.15),
tap.group.rotation(3, 0.03),
tap.group.rotation(-3, 0.06),
tap.group.rotation(0, 0.03),
tap_output.output.text("f", 0)
)
),
hold.duration.grow(1, 2, linear)
);
yield* chain(
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
hold_output.output.text("f", 0)
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(
0.5,
all(tap.duration.grow(0, 0.15), hold.duration.grow(0, 0.15))
);
});

View file

@ -0,0 +1,50 @@
import { makeScene2D } from "@motion-canvas/2d/lib/scenes";
import { makeRefs } from "@motion-canvas/core/lib/utils";
import { any, all, chain, delay, waitFor } from "@motion-canvas/core/lib/flow";
import Key, { KeyTravel } from "../../../components/Key";
import Output from "../../../components/Output";
import { linear } from "@motion-canvas/core/lib/tweening";
export default makeScene2D(function* (view) {
const interrupt = makeRefs<typeof Key>();
view.add(<Key refs={interrupt} binding={"&kp"} params={"J"} />);
interrupt.group.position.x(125);
interrupt.group.position.y(-150);
interrupt.duration.fill("#D9D9D9");
const hold = makeRefs<typeof Key>();
view.add(<Key refs={hold} binding={"&ht_tui"} params={"\u21e7 F"} />);
hold.group.position.x(-125);
hold.group.position.y(-150);
hold.duration.fill("#D9D9D9");
const hold_output = makeRefs<typeof Output>();
view.add(<Output refs={hold_output} />);
hold_output.group.position(hold.group.position().addX(125));
hold_output.group.position.y(hold_output.group.position.y() + 300);
yield* waitFor(0.5);
yield* any(
hold.body.position.y(KeyTravel, 0.15),
hold.duration.grow(0.75, 1.5, linear)
);
yield* delay(
1.2,
all(
interrupt.body.position.y(KeyTravel, 0.15),
hold.duration.fill("F21D00", 0.15)
)
);
yield* chain(
hold.group.rotation(3, 0.03),
hold.group.rotation(-3, 0.06),
hold.group.rotation(0, 0.03),
all(
delay(0.15, hold_output.output.text("J", 0)),
hold_output.shift.fill("#969696", 0.15)
)
);
yield* waitFor(0.25);
yield* hold.body.position.y(0, 0.15);
yield* delay(0.5, hold.duration.grow(0, 0.15));
});

View file

@ -0,0 +1,7 @@
{
"extends": "@motion-canvas/2d/tsconfig.project.json",
"compilerOptions": {
"baseUrl": "src"
},
"include": ["src"]
}

View file

@ -0,0 +1,28 @@
import { defineConfig } from "vite";
import motionCanvas from "@motion-canvas/vite-plugin";
export default defineConfig({
plugins: [
motionCanvas({
project: [
"./src/hold_tap/hold_tap_comparison.ts",
"./src/hold_tap/hold_tap_interrupted.ts",
"./src/hold_tap/balanced/balanced_comparison.ts",
"./src/hold_tap/balanced/balanced_other_key_up.ts",
"./src/hold_tap/balanced/balanced_hold_tap_up.ts",
"./src/hold_tap/tap_preferred/tap_preferred_comparison.ts",
"./src/hold_tap/tap_preferred/tap_preferred_hold_tap_up.ts",
"./src/hold_tap/tap_unless_interrupted/tap_unless_interrupted.ts",
"./src/hold_tap/tap_unless_interrupted/tap_unless_interrupted_invoke_hold.ts",
],
}),
],
build: {
rollupOptions: {
output: {
dir: "../../static/animations",
entryFileNames: "[name].js",
},
},
},
});

View file

@ -0,0 +1,39 @@
import type { MotionCanvasPlayerProps } from "@motion-canvas/player";
import React, { ComponentProps } from "react";
import styles from "./styles.module.css";
import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
import clsx from "clsx";
if (ExecutionEnvironment.canUseDOM) {
import("@motion-canvas/player");
}
declare global {
namespace JSX {
interface IntrinsicElements {
"motion-canvas-player": MotionCanvasPlayerProps & ComponentProps<"div">;
}
}
}
export interface AnimationPlayerProps {
small?: boolean;
auto?: boolean;
name: string;
}
export default function AnimationPlayer({
name,
auto,
small,
}: AnimationPlayerProps) {
return (
<div className={clsx(styles.container, small && styles.small)}>
<motion-canvas-player
class={styles.player}
src={`/animations/${name}.js`}
auto={auto}
/>
</div>
);
}

View file

@ -0,0 +1,21 @@
.container {
width: 100%;
overflow: hidden;
border-radius: var(--ifm-global-radius);
background-color: var(--ifm-background-surface-color);
position: relative;
aspect-ratio: 16 / 9;
border: 1px solid var(--ifm-color-emphasis-300);
margin-top: 20px;
margin-bottom: 20px;
}
.container.small {
max-width: 720px;
aspect-ratio: 16/9;
margin: 0 auto var(--ifm-leading);
}
.player {
aspect-ratio: 16 / 9;
}