@dofy/native-emoji-motion 0.2.0 → 0.3.0
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 +7 -0
- package/README.md +2 -2
- package/package.json +1 -1
- package/src/presets.js +49 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.0 — 2026-11-13
|
|
4
|
+
|
|
5
|
+
- Add lighting and sparkle effects for light sources, reflective objects, and celebrations.
|
|
6
|
+
- Expand the handcrafted collection to 177 emoji, including 44 with optional SVG effects.
|
|
7
|
+
- Refine motions for amusement rides, dice, compass, sunflower, candle, and hourglass.
|
|
8
|
+
- Add reusable 3D carousel and object flip motions.
|
|
9
|
+
|
|
3
10
|
## 0.2.0 — 2026-11-13
|
|
4
11
|
|
|
5
12
|
- Expand the handcrafted collection to 161 emoji and add five reviewed motion families.
|
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@ Small, expressive animations for native emoji. A framework independent library w
|
|
|
4
4
|
|
|
5
5
|
## Collection at a glance
|
|
6
6
|
|
|
7
|
-
The current repository and demo contain **
|
|
7
|
+
The current repository and demo contain **177 handcrafted emoji presets** and **5 reviewed motion families** with **24 additional base emoji**, across **10 categories**. They use **32 reusable motions**; **44 base emoji** have optional SVG effects. Skin tones and other variants are additional sequences, and similar emoji may share the same motion.
|
|
8
8
|
|
|
9
|
-
The default entry also recognizes **5,235 Unicode Emoji 18.0 sequences**, including qualified forms and variants, and applies a category based fallback when there is no handcrafted preset or reviewed family match. These collection counts describe version 0.
|
|
9
|
+
The default entry also recognizes **5,235 Unicode Emoji 18.0 sequences**, including qualified forms and variants, and applies a category based fallback when there is no handcrafted preset or reviewed family match. These collection counts describe version 0.3.0.
|
|
10
10
|
|
|
11
11
|
## Try the demo
|
|
12
12
|
|
package/package.json
CHANGED
package/src/presets.js
CHANGED
|
@@ -46,7 +46,12 @@ export const motions = {
|
|
|
46
46
|
leafSway: createSwayMotion(),
|
|
47
47
|
hoverFlight: { keyframes: [{ transform: 'translateY(0) rotate(0deg)' }, { transform: 'translateY(-15%) rotate(-6deg)', offset: .3 }, { transform: 'translateY(-9%) rotate(6deg)', offset: .6 }, { transform: 'translateY(0) rotate(0deg)' }], options: { duration: 1000, easing: 'cubic-bezier(.22,1,.36,1)' } },
|
|
48
48
|
gentleSip: { keyframes: [{ transform: 'translateY(0) rotate(0deg)' }, { transform: 'translateY(-7%) rotate(-4deg)', offset: .35 }, { transform: 'translateY(-7%) rotate(4deg)', offset: .65 }, { transform: 'translateY(0) rotate(0deg)' }], options: { duration: 1000, easing: 'cubic-bezier(.22,1,.36,1)' }, origin: '50% 85%' },
|
|
49
|
-
pose: { keyframes: [{ transform: 'scale(1) translateY(0)' }, { transform: 'scale(1.04,1.06) translateY(-3%)', offset: .45 }, { transform: 'scale(1) translateY(0)' }], options: { duration: 1100, easing: 'cubic-bezier(.22,1,.36,1)' }, origin: '50% 90%' }
|
|
49
|
+
pose: { keyframes: [{ transform: 'scale(1) translateY(0)' }, { transform: 'scale(1.04,1.06) translateY(-3%)', offset: .45 }, { transform: 'scale(1) translateY(0)' }], options: { duration: 1100, easing: 'cubic-bezier(.22,1,.36,1)' }, origin: '50% 90%' },
|
|
50
|
+
carousel: { keyframes: [{ transform: 'perspective(500px) rotateY(0deg) translateY(0)' }, { transform: 'perspective(500px) rotateY(-35deg) translateY(-8%)', offset: .3 }, { transform: 'perspective(500px) rotateY(35deg) translateY(-4%)', offset: .65 }, { transform: 'perspective(500px) rotateY(0deg) translateY(0)' }], options: { duration: 1200, easing: 'cubic-bezier(.22,1,.36,1)' }, origin: '50% 85%' },
|
|
51
|
+
flipHorizontal: { keyframes: [{ transform: 'perspective(500px) rotateY(0deg)' }, { transform: 'perspective(500px) rotateY(180deg)', offset: .5 }, { transform: 'perspective(500px) rotateY(360deg)' }], options: { duration: 1000, easing: 'cubic-bezier(.22,1,.36,1)' } },
|
|
52
|
+
flipVertical: { keyframes: [{ transform: 'perspective(500px) rotateX(0deg)' }, { transform: 'perspective(500px) rotateX(180deg)', offset: .5 }, { transform: 'perspective(500px) rotateX(360deg)' }], options: { duration: 1000, easing: 'cubic-bezier(.22,1,.36,1)' } },
|
|
53
|
+
steady: { keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(1.025)', offset: .5 }, { transform: 'scale(1)' }], options: { duration: 1100, easing: 'cubic-bezier(.22,1,.36,1)' }, origin: '50% 100%' },
|
|
54
|
+
hourglassTurn: { keyframes: [{ transform: 'rotate(0deg)' }, { transform: 'rotate(180deg)', offset: .4 }, { transform: 'rotate(180deg)', offset: .6 }, { transform: 'rotate(0deg)' }], options: { duration: 1300, easing: 'cubic-bezier(.22,1,.36,1)' } }
|
|
50
55
|
};
|
|
51
56
|
|
|
52
57
|
// Groups describe semantic families; emoji entries may override the group's motion.
|
|
@@ -103,9 +108,9 @@ export const emoji = {
|
|
|
103
108
|
'❤️': { group: 'hearts', name: 'Red heart', variants: ['❤'] }, '💛': { group: 'hearts', name: 'Yellow heart' }, '💖': { group: 'hearts', name: 'Sparkling heart' },
|
|
104
109
|
'💚': { group: 'hearts', name: 'Green heart' }, '💙': { group: 'hearts', name: 'Blue heart' }, '💜': { group: 'hearts', name: 'Purple heart' }, '💔': { group: 'hearts', name: 'Broken heart', motion: 'shake' },
|
|
105
110
|
'🔍': { 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: ['⏱'] },
|
|
106
|
-
'💡': { group: 'objects', name: 'Light bulb', motion: '
|
|
107
|
-
'🌸': { group: 'nature', name: 'Blossom', decoration: 'petals' }, '🍃': { group: 'nature', name: 'Leaves' }, '☀️': { group: 'nature', name: 'Sun', motion: 'spin', variants: ['☀'] },
|
|
108
|
-
'🌻': { group: 'nature', name: 'Sunflower', motion: '
|
|
111
|
+
'💡': { 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' },
|
|
112
|
+
'🌸': { group: 'nature', name: 'Blossom', decoration: 'petals' }, '🍃': { group: 'nature', name: 'Leaves' }, '☀️': { group: 'nature', name: 'Sun', motion: 'spin', decoration: 'glow', variants: ['☀'] },
|
|
113
|
+
'🌻': { 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' },
|
|
109
114
|
'🚀': { group: 'travel', name: 'Rocket' }, '✈️': { group: 'travel', name: 'Airplane', motion: 'glide', variants: ['✈'] }, '🚲': { group: 'travel', name: 'Bicycle', motion: 'ride' },
|
|
110
115
|
'🚗': { group: 'travel', name: 'Car', motion: 'ride' }, '🚂': { group: 'travel', name: 'Locomotive', motion: 'ride' }, '🛸': { group: 'travel', name: 'Flying saucer', motion: 'float' }, '🚢': { group: 'travel', name: 'Ship', motion: 'wobble' },
|
|
111
116
|
'✨': { 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' },
|
|
@@ -113,7 +118,7 @@ export const emoji = {
|
|
|
113
118
|
'☕': { 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' },
|
|
114
119
|
'🏀': { group: 'activities', name: 'Basketball', motion: 'hop' }, '⚽': { group: 'activities', name: 'Soccer ball', motion: 'hop' }, '🎈': { group: 'activities', name: 'Balloon', motion: 'float' }, '🎉': { group: 'activities', name: 'Party popper', motion: 'bounce', decoration: 'sparkle' },
|
|
115
120
|
'💃': { group: 'people', name: 'Woman dancing', motion: 'twirl', skinTones: skinTones('💃') }, '🕺': { group: 'people', name: 'Man dancing', motion: 'twirl', skinTones: skinTones('🕺') },
|
|
116
|
-
'⏳': { group: 'objects', name: 'Hourglass', motion: '
|
|
121
|
+
'⏳': { group: 'objects', name: 'Hourglass', motion: 'hourglassTurn' }, '⏰': { group: 'objects', name: 'Alarm clock', motion: 'shake' }, '🕯️': { group: 'objects', name: 'Candle', motion: 'steady', decoration: 'flicker', variants: ['🕯'] },
|
|
117
122
|
|
|
118
123
|
// Additional handcrafted entries share motions where their physical action fits.
|
|
119
124
|
'😀': { group: 'faces', name: 'Grinning face', motion: 'bounce' }, '🤣': { group: 'faces', name: 'Rolling on the floor laughing', motion: 'shake' },
|
|
@@ -143,9 +148,26 @@ export const emoji = {
|
|
|
143
148
|
'🧑🚀': { group: 'people', name: 'Astronaut', motion: 'float', skinTones: personSkinTones('🚀') }, '🧑💻': { group: 'people', name: 'Technologist', motion: 'nod', skinTones: personSkinTones('💻') },
|
|
144
149
|
'📱': { group: 'objects', name: 'Mobile phone', motion: 'shake' }, '📚': { group: 'objects', name: 'Books', motion: 'nod' }, '✉️': { group: 'objects', name: 'Envelope', motion: 'bob', variants: ['✉'] },
|
|
145
150
|
'💌': { group: 'objects', name: 'Love letter', motion: 'bob', decoration: 'sparkle' }, '🔒': { group: 'objects', name: 'Locked', motion: 'wobble' }, '🔓': { group: 'objects', name: 'Unlocked', motion: 'pop' },
|
|
146
|
-
'🔦': { group: 'objects', name: 'Flashlight', motion: 'nod' }, '🪄': { group: 'objects', name: 'Magic wand', motion: 'twirl', decoration: 'sparkle' }, '🎤': { group: 'objects', name: 'Microphone', motion: 'swing', decoration: 'sound' },
|
|
151
|
+
'🔦': { 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' },
|
|
147
152
|
'🚌': { group: 'travel', name: 'Bus', motion: 'ride' }, '🚕': { group: 'travel', name: 'Taxi', motion: 'ride' }, '🚁': { group: 'travel', name: 'Helicopter', motion: 'bob' },
|
|
148
|
-
'🎡': { group: 'travel', name: 'Ferris wheel', motion: '
|
|
153
|
+
'🎡': { group: 'travel', name: 'Ferris wheel', motion: 'steady' }, '⛵': { group: 'travel', name: 'Sailboat', motion: 'bob' }, '🎠': { group: 'travel', name: 'Carousel horse', motion: 'carousel' },
|
|
154
|
+
// Direction-neutral lighting for other objects that naturally emit or reflect light.
|
|
155
|
+
'📸': { group: 'objects', name: 'Camera with flash', motion: 'bounce', decoration: 'flash' },
|
|
156
|
+
'🪔': { group: 'objects', name: 'Oil lamp', motion: 'sway', decoration: 'flicker' },
|
|
157
|
+
'🚨': { group: 'objects', name: 'Police car light', motion: 'pulse', decoration: 'alertLight' },
|
|
158
|
+
'🔅': { group: 'symbols', name: 'Dim button', motion: 'breathe', decoration: 'glow' },
|
|
159
|
+
'🔆': { group: 'symbols', name: 'Bright button', motion: 'pulse', decoration: 'glow' },
|
|
160
|
+
'🌞': { group: 'nature', name: 'Sun with face', motion: 'breathe', decoration: 'glow' },
|
|
161
|
+
'🌟': { group: 'nature', name: 'Glowing star', motion: 'pulse', decoration: 'sparkle' },
|
|
162
|
+
'⚡': { group: 'nature', name: 'High voltage', motion: 'pop', decoration: 'flash' },
|
|
163
|
+
'🎆': { group: 'activities', name: 'Fireworks', motion: 'pop', decoration: 'sparkle' },
|
|
164
|
+
'🎇': { group: 'activities', name: 'Sparkler', motion: 'wobble', decoration: 'sparkle' },
|
|
165
|
+
'🔮': { group: 'objects', name: 'Crystal ball', motion: 'breathe', decoration: 'sparkle' },
|
|
166
|
+
'💎': { group: 'objects', name: 'Gem stone', motion: 'pulse', decoration: 'sparkle' },
|
|
167
|
+
'🪩': { group: 'objects', name: 'Mirror ball', motion: 'spin', decoration: 'sparkle' },
|
|
168
|
+
'🌠': { group: 'nature', name: 'Shooting star', motion: 'float', decoration: 'sparkle' },
|
|
169
|
+
'🪙': { group: 'objects', name: 'Coin', motion: 'flipHorizontal' },
|
|
170
|
+
'🎲': { group: 'activities', name: 'Game die', motion: 'spin' }
|
|
149
171
|
};
|
|
150
172
|
|
|
151
173
|
// Declarative SVG layers never alter the native glyph. Anchors are relative to
|
|
@@ -166,7 +188,27 @@ const steamShape = { viewBox: '0 0 100 100', elements: [
|
|
|
166
188
|
const rainShape = { viewBox: '0 0 100 100', elements: [
|
|
167
189
|
{ tag: 'path', attrs: { d: 'M30 67v6M50 72v6M70 67v6', fill: 'none', stroke: '#7c9fca', 'stroke-width': '3', 'stroke-linecap': 'round' } }
|
|
168
190
|
] };
|
|
191
|
+
// Symmetric rays sit around the glyph rather than assuming a bulb, lens or flame position.
|
|
192
|
+
const lightShape = color => ({ viewBox: '0 0 100 100', elements: [
|
|
193
|
+
{ tag: 'path', attrs: { d: 'M50 4v9M50 87v9M4 50h9M87 50h9M17 17l6 6M77 77l6 6M83 17l-6 6M23 77l-6 6', fill: 'none', stroke: color, 'stroke-width': '3', 'stroke-linecap': 'round' } }
|
|
194
|
+
] });
|
|
169
195
|
export const decorations = {
|
|
196
|
+
alertLight: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: lightShape('#df625e'), style: centered,
|
|
197
|
+
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.85)' }, { opacity: .9, transform: 'translate(-50%, -50%) scale(1)', offset: .3 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.12)' }],
|
|
198
|
+
options: { duration: 900, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
199
|
+
}] },
|
|
200
|
+
glow: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: lightShape('#e0a63e'), style: centered,
|
|
201
|
+
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.85)' }, { opacity: .9, transform: 'translate(-50%, -50%) scale(1)', offset: .35 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.08)' }],
|
|
202
|
+
options: { duration: 850, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
203
|
+
}] },
|
|
204
|
+
flicker: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: lightShape('#df985c'), style: centered,
|
|
205
|
+
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.9)' }, { opacity: .7, transform: 'translate(-50%, -50%) scale(1)', offset: .3 }, { opacity: .3, transform: 'translate(-50%, -50%) scale(.95)', offset: .5 }, { opacity: .75, transform: 'translate(-50%, -50%) scale(1.03)', offset: .7 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1)' }],
|
|
206
|
+
options: { duration: 1100, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
207
|
+
}] },
|
|
208
|
+
flash: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: lightShape('#a5b7df'), style: centered,
|
|
209
|
+
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.75)' }, { opacity: 1, transform: 'translate(-50%, -50%) scale(1)', offset: .18 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.2)', offset: .52 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.2)' }],
|
|
210
|
+
options: { duration: 800, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
211
|
+
}] },
|
|
170
212
|
impact: { anchor: { x: '50%', y: '50%' }, layers: [{ svg: { viewBox: '0 0 100 100', elements: [{ tag: 'path', attrs: { d: 'M28 75l-5 4M72 75l5 4M50 79v6', fill: 'none', stroke: '#d49b70', 'stroke-width': '3', 'stroke-linecap': 'round' } }] }, style: centered,
|
|
171
213
|
keyframes: [{ opacity: 0, transform: 'translate(-50%, -50%) scale(.8)' }, { opacity: 0, transform: 'translate(-50%, -50%) scale(.8)', offset: .45 }, { opacity: .85, transform: 'translate(-50%, -50%) scale(1)', offset: .65 }, { opacity: 0, transform: 'translate(-50%, -50%) scale(1.1)' }], options: { duration: 900, easing: 'cubic-bezier(.22,1,.36,1)' }
|
|
172
214
|
}] },
|