@dofy/native-emoji-motion 0.6.0 → 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/src/presets.js +38 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.4 — 2026-11-14
|
|
4
|
+
|
|
5
|
+
- Add ripple, splash and wake effects for water.
|
|
6
|
+
- Add families for swimmers, surfers, water polo players and rowers, covering their gender and skin tone variants.
|
|
7
|
+
- Boats, the ring buoy, the water wave, the dolphin and the diving mask now use water effects.
|
|
8
|
+
|
|
3
9
|
## 0.6.0 — 2026-11-14
|
|
4
10
|
|
|
5
11
|
- Add motion families for vegetables, land animals, clothing, tools, books, hand gestures, boats and sweet treats.
|
package/README.md
CHANGED
|
@@ -24,13 +24,13 @@ Bring 👋, ❤️, 📡 and more to life in React, Vue, Svelte or plain HTML. E
|
|
|
24
24
|
|
|
25
25
|
## 📊 Collection at a glance
|
|
26
26
|
|
|
27
|
-
| In version 0.6.
|
|
27
|
+
| In version 0.6.4 | Count | What it covers |
|
|
28
28
|
| --- | ---: | --- |
|
|
29
29
|
| Handcrafted presets | 177 | Individually configured base emoji |
|
|
30
|
-
| Reviewed motion families |
|
|
30
|
+
| Reviewed motion families | 31 | 212 additional base emoji sharing reviewed motions |
|
|
31
31
|
| Categories | 10 | Groups used to organize the collection |
|
|
32
32
|
| Reusable motions | 53 | Motions shared by presets and families |
|
|
33
|
-
| Emoji with optional SVG effects |
|
|
33
|
+
| Emoji with optional SVG effects | 96 | Base emoji with decorative effects |
|
|
34
34
|
| Recognized Unicode sequences | 5,235 | Unicode Emoji 18.0 sequences, including skin tones and other variants |
|
|
35
35
|
|
|
36
36
|
Skin tones and other variants count as additional Unicode sequences. Similar emoji may share a motion. Recognized emoji without a preset or reviewed family receive a category-based fallback.
|
package/package.json
CHANGED
package/src/presets.js
CHANGED
|
@@ -101,11 +101,14 @@ const rolePeople = ['🧑', '👨', '👩'];
|
|
|
101
101
|
const roleSuffixes = ['⚕️', '🎓', '🏫', '🌾', '🔧', '🔬', '🚒', '⚖️', '✈️', '🎤'];
|
|
102
102
|
const roleMembers = roleSuffixes.flatMap(suffix => rolePeople.map(person => `${person}${suffix}`));
|
|
103
103
|
const roleAliases = Object.fromEntries(roleSuffixes.flatMap(suffix => rolePeople.flatMap(person => Object.values(skinTones(person)).map(variant => [`${variant}${suffix}`, `${person}${suffix}`]))));
|
|
104
|
-
|
|
105
|
-
const
|
|
104
|
+
// Gendered sequences take the modifier on the person, before the joiner.
|
|
105
|
+
const genderedToneAliases = glyphs => Object.fromEntries(glyphs.flatMap(glyph => {
|
|
106
106
|
const [person, suffix = ''] = glyph.split('');
|
|
107
107
|
return Object.values(skinTones(person)).map(variant => [suffix ? `${variant}${suffix}` : variant, glyph]);
|
|
108
108
|
}));
|
|
109
|
+
const gendered = person => [person, `${person}♂️`, `${person}♀️`];
|
|
110
|
+
const walkerMembers = ['🚶', '🚶♂️', '🚶♀️', '🏃♂️', '🏃♀️'];
|
|
111
|
+
const walkerAliases = genderedToneAliases(walkerMembers);
|
|
109
112
|
// Members are reviewed explicitly; no entire Unicode subgroup is assumed to move alike.
|
|
110
113
|
export const families = {
|
|
111
114
|
clocks: { label: 'Clocks', group: 'objects', motion: 'clockTick', members: ['⌚', '🕰️', '⏲️', '🕛', '🕧'], aliases: { '🕰': '🕰️', '⏲': '⏲️' } },
|
|
@@ -117,7 +120,7 @@ export const families = {
|
|
|
117
120
|
handTools: { label: 'Hand tools', group: 'objects', motion: 'toolWiggle', members: ['🔨', '🪓', '🪚', '🪛', '🔧', '🪠', '🔩'] },
|
|
118
121
|
books: { label: 'Books', group: 'objects', motion: 'bookPeek', members: ['📕', '📗', '📘', '📙', '📔', '📓', '📒'] },
|
|
119
122
|
handGestures: { label: 'Hand gestures', group: 'gestures', motion: 'handEmphasis', members: ['🤏', '🫳', '🫴', '🫲', '🫱', '🫷', '🫸', '🤌', '🫵'], aliases: familyToneAliases(['🤏', '🫳', '🫴', '🫲', '🫱', '🫷', '🫸', '🤌', '🫵']) },
|
|
120
|
-
vessels: { label: 'Boats', group: 'travel', motion: 'vesselRock', members: ['🚤', '🛥️', '🛳️', '⛴️', '🛶'], aliases: { '🛥': '🛥️', '🛳': '🛳️', '⛴': '⛴️' } },
|
|
123
|
+
vessels: { label: 'Boats', group: 'travel', motion: 'vesselRock', members: ['🚤', '🛥️', '🛳️', '⛴️', '🛶'], aliases: { '🛥': '🛥️', '🛳': '🛳️', '⛴': '⛴️' }, decoration: 'wake' },
|
|
121
124
|
treats: { label: 'Sweet treats', group: 'food', motion: 'treatPop', members: ['🍬', '🍭', '🍫', '🍮', '🧁', '🍨'], decoration: 'sparkle' },
|
|
122
125
|
fruit: { label: 'Fruit', group: 'food', motion: 'fruitBounce', members: ['🍊', '🍋', '🍐', '🍑', '🍇', '🫐', '🍒', '🥝', '🍍', '🥭'], decoration: 'sparkle' },
|
|
123
126
|
animalFaces: { label: 'Animal faces', group: 'nature', motion: 'curiousTilt', members: ['🐶', '🦊', '🐹', '🦝', '🐨', '🐯', '🐭', '🐻❄️'] },
|
|
@@ -131,6 +134,10 @@ export const families = {
|
|
|
131
134
|
poses: { label: 'People in poses', group: 'people', motion: 'pose', members: ['🧎', '🧍', '🙇'], aliases: familyToneAliases(['🧎', '🧍', '🙇']) },
|
|
132
135
|
professionals: { label: 'Professionals', group: 'people', motion: 'pose', members: roleMembers, aliases: roleAliases },
|
|
133
136
|
walkers: { label: 'Walking and running', group: 'people', motion: 'steps', members: walkerMembers, aliases: walkerAliases },
|
|
137
|
+
swimmers: { label: 'Swimmers', group: 'people', motion: 'bob', members: gendered('🏊'), aliases: genderedToneAliases(gendered('🏊')), decoration: 'ripple' },
|
|
138
|
+
surfers: { label: 'Surfers', group: 'people', motion: 'ride', members: gendered('🏄'), aliases: genderedToneAliases(gendered('🏄')), decoration: 'splash' },
|
|
139
|
+
waterPolo: { label: 'Water polo', group: 'people', motion: 'bob', members: gendered('🤽'), aliases: genderedToneAliases(gendered('🤽')), decoration: 'splash' },
|
|
140
|
+
rowers: { label: 'Rowers', group: 'people', motion: 'vesselRock', members: gendered('🚣'), aliases: genderedToneAliases(gendered('🚣')), decoration: 'wake' },
|
|
134
141
|
seaLife: { label: 'Sea life', group: 'nature', motion: 'underwater', members: ['🐠', '🐡', '🦈', '🐋', '🐳', '🦭'], decoration: 'bubbles' },
|
|
135
142
|
bakery: { label: 'Bakery', group: 'food', motion: 'pastryBounce', members: ['🍞', '🥐', '🥖', '🥨', '🥯', '🥞', '🧇'] },
|
|
136
143
|
rail: { label: 'Rail vehicles', group: 'travel', motion: 'railRide', members: ['🚄', '🚅', '🚆', '🚇', '🚈', '🚊', '🚝', '🚞'] },
|
|
@@ -163,9 +170,9 @@ export const emoji = {
|
|
|
163
170
|
'🔍': { group: 'objects', name: 'Magnifying glass', motion: 'search' }, '🔔': { group: 'objects', name: 'Bell', motion: 'swing', decoration: 'sound' }, '🎁': { group: 'objects', name: 'Gift', motion: 'shake' }, '📡': { group: 'objects', name: 'Satellite antenna', motion: 'wobble', decoration: 'signal' }, '⏱️': { group: 'objects', name: 'Stopwatch', motion: 'swing', variants: ['⏱'] },
|
|
164
171
|
'💡': { group: 'objects', name: 'Light bulb', motion: 'breathe', decoration: 'glow' }, '📷': { group: 'objects', name: 'Camera', motion: 'bounce', decoration: 'flash' }, '🔑': { group: 'objects', name: 'Key', motion: 'wobble' }, '📌': { group: 'objects', name: 'Pushpin', motion: 'bounce' }, '📦': { group: 'objects', name: 'Package', motion: 'shake' }, '🧭': { group: 'objects', name: 'Compass', motion: 'wobble' },
|
|
165
172
|
'🌸': { group: 'nature', name: 'Blossom', decoration: 'petals' }, '🍃': { group: 'nature', name: 'Leaves' }, '☀️': { group: 'nature', name: 'Sun', motion: 'spin', decoration: 'glow', variants: ['☀'] },
|
|
166
|
-
'🌻': { group: 'nature', name: 'Sunflower', motion: 'leafSway' }, '🌈': { group: 'nature', name: 'Rainbow', motion: 'float' }, '🌙': { group: 'nature', name: 'Crescent moon', motion: 'float' }, '⭐': { group: 'nature', name: 'Star', motion: 'pulse', decoration: 'sparkle' }, '🔥': { group: 'nature', name: 'Fire', motion: 'wobble', decoration: 'flicker' }, '🌊': { group: 'nature', name: 'Water wave', motion: 'float' },
|
|
173
|
+
'🌻': { group: 'nature', name: 'Sunflower', motion: 'leafSway' }, '🌈': { group: 'nature', name: 'Rainbow', motion: 'float' }, '🌙': { group: 'nature', name: 'Crescent moon', motion: 'float' }, '⭐': { group: 'nature', name: 'Star', motion: 'pulse', decoration: 'sparkle' }, '🔥': { group: 'nature', name: 'Fire', motion: 'wobble', decoration: 'flicker' }, '🌊': { group: 'nature', name: 'Water wave', motion: 'float', decoration: 'splash' },
|
|
167
174
|
'🚀': { group: 'travel', name: 'Rocket' }, '✈️': { group: 'travel', name: 'Airplane', motion: 'glide', variants: ['✈'] }, '🚲': { group: 'travel', name: 'Bicycle', motion: 'ride' },
|
|
168
|
-
'🚗': { group: 'travel', name: 'Car', motion: 'ride' }, '🚂': { group: 'travel', name: 'Locomotive', motion: 'ride' }, '🛸': { group: 'travel', name: 'Flying saucer', motion: 'float' }, '🚢': { group: 'travel', name: 'Ship', motion: '
|
|
175
|
+
'🚗': { group: 'travel', name: 'Car', motion: 'ride' }, '🚂': { group: 'travel', name: 'Locomotive', motion: 'ride' }, '🛸': { group: 'travel', name: 'Flying saucer', motion: 'float' }, '🚢': { group: 'travel', name: 'Ship', motion: 'vesselRock', decoration: 'wake' },
|
|
169
176
|
'✨': { group: 'symbols', name: 'Sparkles', motion: 'pulse', decoration: 'sparkle' }, '⚙️': { group: 'symbols', name: 'Gear', variants: ['⚙'] }, '🎯': { group: 'symbols', name: 'Target', motion: 'bounce' }, '🎵': { group: 'symbols', name: 'Musical note', motion: 'swing', decoration: 'sound' }, '💤': { group: 'symbols', name: 'Sleeping symbol', motion: 'float' }, '💥': { group: 'symbols', name: 'Collision', motion: 'pulse' }, '❗': { group: 'symbols', name: 'Exclamation mark', motion: 'bounce' }, '❓': { group: 'symbols', name: 'Question mark', motion: 'wobble' }, '✅': { group: 'symbols', name: 'Check mark', motion: 'bounce' },
|
|
170
177
|
'🐰': { group: 'nature', name: 'Rabbit face', motion: 'hop' }, '🦋': { group: 'nature', name: 'Butterfly', motion: 'flutter' }, '🐝': { group: 'nature', name: 'Bee', motion: 'flutter' }, '🌱': { group: 'nature', name: 'Seedling', motion: 'sway' }, '🌧️': { group: 'nature', name: 'Cloud with rain', motion: 'float', decoration: 'rain', variants: ['🌧'] },
|
|
171
178
|
'☕': { group: 'food', name: 'Hot beverage', motion: 'sip', decoration: 'steam' }, '🍵': { group: 'food', name: 'Teacup', motion: 'sip', decoration: 'steam' }, '🍕': { group: 'food', name: 'Pizza', motion: 'bounce' }, '🍦': { group: 'food', name: 'Soft ice cream', motion: 'sway' },
|
|
@@ -184,7 +191,7 @@ export const emoji = {
|
|
|
184
191
|
'🫰': { group: 'gestures', name: 'Hand with index finger and thumb crossed', motion: 'pop', skinTones: skinTones('🫰') },
|
|
185
192
|
'🐱': { group: 'nature', name: 'Cat face', motion: 'nod' }, '🐻': { group: 'nature', name: 'Bear', motion: 'nod' }, '🐼': { group: 'nature', name: 'Panda', motion: 'sway' },
|
|
186
193
|
'🐸': { group: 'nature', name: 'Frog', motion: 'hop' }, '🐧': { group: 'nature', name: 'Penguin', motion: 'sway' }, '🐥': { group: 'nature', name: 'Front facing baby chick', motion: 'hop' },
|
|
187
|
-
'🐢': { group: 'nature', name: 'Turtle', motion: 'bob' }, '🐟': { group: 'nature', name: 'Fish', motion: 'bob' }, '🐬': { group: 'nature', name: 'Dolphin', motion: '
|
|
194
|
+
'🐢': { group: 'nature', name: 'Turtle', motion: 'bob' }, '🐟': { group: 'nature', name: 'Fish', motion: 'bob' }, '🐬': { group: 'nature', name: 'Dolphin', motion: 'hop', decoration: 'splash' },
|
|
188
195
|
'🐙': { group: 'nature', name: 'Octopus', motion: 'twirl' }, '🌵': { group: 'nature', name: 'Cactus', motion: 'sway' }, '🌲': { group: 'nature', name: 'Evergreen tree', motion: 'sway' },
|
|
189
196
|
'🌼': { group: 'nature', name: 'Blossom flower', motion: 'sway', decoration: 'petals' }, '❄️': { group: 'nature', name: 'Snowflake', motion: 'float', variants: ['❄'] }, '☁️': { group: 'nature', name: 'Cloud', motion: 'float', variants: ['☁'] },
|
|
190
197
|
'🍎': { group: 'food', name: 'Red apple', motion: 'nod' }, '🍉': { group: 'food', name: 'Watermelon', motion: 'wobble' }, '🍓': { group: 'food', name: 'Strawberry', motion: 'bounce' },
|
|
@@ -196,14 +203,13 @@ export const emoji = {
|
|
|
196
203
|
'🥁': { group: 'activities', name: 'Drum', motion: 'shake', decoration: 'sound' }, '🎮': { group: 'activities', name: 'Game controller', motion: 'wobble' }, '🪁': { group: 'activities', name: 'Kite', motion: 'flutter' },
|
|
197
204
|
'🙋': { group: 'people', name: 'Person raising hand', motion: 'wave', skinTones: skinTones('🙋') }, '🧘': { group: 'people', name: 'Person in lotus position', motion: 'breathe', skinTones: skinTones('🧘') },
|
|
198
205
|
'🏃': { group: 'people', name: 'Person running', motion: 'hop', skinTones: skinTones('🏃') }, '🤸': { group: 'people', name: 'Person cartwheeling', motion: 'twirl', skinTones: skinTones('🤸') },
|
|
199
|
-
'🏊': { group: 'people', name: 'Person swimming', motion: 'bob', skinTones: skinTones('🏊') }, '🏄': { group: 'people', name: 'Person surfing', motion: 'bob', skinTones: skinTones('🏄') },
|
|
200
206
|
'🧑🍳': { group: 'people', name: 'Cook', motion: 'nod', skinTones: personSkinTones('🍳') }, '🧑🎨': { group: 'people', name: 'Artist', motion: 'twirl', skinTones: personSkinTones('🎨') },
|
|
201
207
|
'🧑🚀': { group: 'people', name: 'Astronaut', motion: 'float', skinTones: personSkinTones('🚀') }, '🧑💻': { group: 'people', name: 'Technologist', motion: 'nod', skinTones: personSkinTones('💻') },
|
|
202
208
|
'📱': { group: 'objects', name: 'Mobile phone', motion: 'shake' }, '📚': { group: 'objects', name: 'Books', motion: 'nod' }, '✉️': { group: 'objects', name: 'Envelope', motion: 'bob', variants: ['✉'] },
|
|
203
209
|
'💌': { group: 'objects', name: 'Love letter', motion: 'bob', decoration: 'sparkle' }, '🔒': { group: 'objects', name: 'Locked', motion: 'wobble' }, '🔓': { group: 'objects', name: 'Unlocked', motion: 'pop' },
|
|
204
210
|
'🔦': { group: 'objects', name: 'Flashlight', motion: 'nod', decoration: 'flash' }, '🪄': { group: 'objects', name: 'Magic wand', motion: 'twirl', decoration: 'sparkle' }, '🎤': { group: 'objects', name: 'Microphone', motion: 'swing', decoration: 'sound' },
|
|
205
211
|
'🚌': { group: 'travel', name: 'Bus', motion: 'ride' }, '🚕': { group: 'travel', name: 'Taxi', motion: 'ride' }, '🚁': { group: 'travel', name: 'Helicopter', motion: 'bob' },
|
|
206
|
-
'🎡': { group: 'travel', name: 'Ferris wheel', motion: 'steady' }, '⛵': { group: 'travel', name: 'Sailboat', motion: '
|
|
212
|
+
'🎡': { group: 'travel', name: 'Ferris wheel', motion: 'steady' }, '⛵': { group: 'travel', name: 'Sailboat', motion: 'vesselRock', decoration: 'wake' }, '🎠': { group: 'travel', name: 'Carousel horse', motion: 'carousel' },
|
|
207
213
|
// Direction-neutral lighting for other objects that naturally emit or reflect light.
|
|
208
214
|
'📸': { group: 'objects', name: 'Camera with flash', motion: 'bounce', decoration: 'flash' },
|
|
209
215
|
'🪔': { group: 'objects', name: 'Oil lamp', motion: 'sway', decoration: 'flicker' },
|
|
@@ -219,6 +225,9 @@ export const emoji = {
|
|
|
219
225
|
'💎': { group: 'objects', name: 'Gem stone', motion: 'pulse', decoration: 'sparkle' },
|
|
220
226
|
'🪩': { group: 'objects', name: 'Mirror ball', motion: 'spin', decoration: 'sparkle' },
|
|
221
227
|
'🌠': { group: 'nature', name: 'Shooting star', motion: 'float', decoration: 'sparkle' },
|
|
228
|
+
// Water gear borrows the sea life and boat motions with matching water effects.
|
|
229
|
+
'🤿': { group: 'activities', name: 'Diving mask', motion: 'underwater', decoration: 'bubbles' },
|
|
230
|
+
'🛟': { group: 'travel', name: 'Ring buoy', motion: 'vesselRock', decoration: 'wake' },
|
|
222
231
|
'🪙': { group: 'objects', name: 'Coin', motion: 'flipHorizontal' },
|
|
223
232
|
'🎲': { group: 'activities', name: 'Game die', motion: 'spin' }
|
|
224
233
|
};
|
|
@@ -238,6 +247,21 @@ const centered = { width: '160%', height: '160%', overflow: 'visible' };
|
|
|
238
247
|
const steamShape = { viewBox: '0 0 100 100', elements: [
|
|
239
248
|
{ tag: 'path', attrs: { d: 'M38 30c-5-5 5-8 0-14M50 27c-5-5 5-8 0-14M62 30c-5-5 5-8 0-14', fill: 'none', stroke: '#a29aa5', 'stroke-width': '2.5', 'stroke-linecap': 'round' } }
|
|
240
249
|
] };
|
|
250
|
+
// Water effects sit at the waterline below the glyph and spread symmetrically.
|
|
251
|
+
// y is the waterline in viewBox units: at the body for swimmers, below the hull for boats.
|
|
252
|
+
const rippleRings = y => [0, 320].map(delay => ({
|
|
253
|
+
svg: { viewBox: '0 0 100 100', elements: [{ tag: 'ellipse', attrs: { cx: '50', cy: String(y), rx: '30', ry: '6', fill: 'none', stroke: '#7cafd0', 'stroke-width': '2.5' } }] },
|
|
254
|
+
style: { ...centered, transformOrigin: `50% ${y}%` },
|
|
255
|
+
keyframes: [{ opacity: .8, transform: 'translate(-50%, -50%) scale(.5)' }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.25)' }],
|
|
256
|
+
options: { duration: 1100, delay, easing: 'cubic-bezier(.25,.6,.4,1)', fill: 'backwards' }
|
|
257
|
+
}));
|
|
258
|
+
const splashShape = { viewBox: '0 0 100 100', elements: [
|
|
259
|
+
{ tag: 'path', attrs: { d: 'M39 70l-9-8M45 67l-3-10M61 70l9-8M55 67l3-10', fill: 'none', stroke: '#7cafd0', 'stroke-width': '2.5', 'stroke-linecap': 'round' } },
|
|
260
|
+
{ tag: 'circle', attrs: { cx: '25', cy: '56', r: '2.6', fill: '#7cafd0' } },
|
|
261
|
+
{ tag: 'circle', attrs: { cx: '39', cy: '50', r: '2', fill: '#7cafd0' } },
|
|
262
|
+
{ tag: 'circle', attrs: { cx: '75', cy: '56', r: '2.6', fill: '#7cafd0' } },
|
|
263
|
+
{ tag: 'circle', attrs: { cx: '61', cy: '50', r: '2', fill: '#7cafd0' } }
|
|
264
|
+
] };
|
|
241
265
|
const rainShape = { viewBox: '0 0 100 100', elements: [
|
|
242
266
|
{ tag: 'path', attrs: { d: 'M30 67v6M50 72v6M70 67v6', fill: 'none', stroke: '#7c9fca', 'stroke-width': '3', 'stroke-linecap': 'round' } }
|
|
243
267
|
] };
|
|
@@ -281,6 +305,12 @@ export const decorations = {
|
|
|
281
305
|
keyframes: [{ opacity: 0, transform: 'translate(-50%, -55%)' }, { opacity: .9, transform: 'translate(-50%, -50%)', offset: .3 }, { opacity: 0, transform: 'translate(-50%, -40%)' }],
|
|
282
306
|
options: { duration: 950, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
283
307
|
}] },
|
|
308
|
+
ripple: { anchor: { x: '50%', y: '50%' }, layers: rippleRings(66) },
|
|
309
|
+
wake: { anchor: { x: '50%', y: '50%' }, layers: rippleRings(75) },
|
|
310
|
+
splash: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: splashShape, style: { ...centered, transformOrigin: '50% 70%' },
|
|
311
|
+
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.55)' }, { opacity: .9, transform: 'translate(-50%, -50%) scale(1)', offset: .35 }, { opacity: 0, transform: 'translate(-50%, -54%) scale(1.15)' }],
|
|
312
|
+
options: { duration: 850, easing: curve }
|
|
313
|
+
}] },
|
|
284
314
|
signal: {
|
|
285
315
|
anchor: { x: '50%', y: '50%' },
|
|
286
316
|
layers: [0, 180, 360].map(delay => ({
|