Skip to content

Commit 4010cab

Browse files
authored
feat: Support Social emote (#144)
* chore: Update @dcl/schemas package * feat: Parse socialEmote param from url * feat: Add logic to handle emoteDataADR287 property * feat: Duplicate avatar when Armature_Other is present in the socialEmote prop * feat: Use loop and animations specified in socialEmote prop * feat: Load selectedSound when specified * docs: Update README * chore: Update @dcl/schemas package * feat: Define getSocialEmoteanimations methods in the controller * feat: Apply color to Avatar Other * fix: Top level async * chore: Update @dcl/schemas package * fix: Use types from @dcl/schemas * chore: Upgrade @dcl/schemas package * chore: Upgrade package @dcl/schemas * feat: Use types from @dcl/schemas * docs: Update README * chore: Upgrade @dcl/schemas package * refactor: Use options from schemas * refactor: Improve conditions readability
1 parent a647260 commit 4010cab

13 files changed

Lines changed: 386 additions & 76 deletions

File tree

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ This webapp renders an interactive 3D preview of a wearable or an avatar. It can
1414
- `eyes`: a color to be used by the eyes tint, it must be in hex.
1515
- `bodyShape`: which body shape to use, possible values are `urn:decentraland:off-chain:base-avatars:BaseMale` or `urn:decentraland:off-chain:base-avatars:BaseFemale`.
1616
- `emote`: the emote that the avatar will play. Default value is `idle`, other possible values are: `clap`, `dab`, `dance`, `fashion`, `fashion-2`, `fashion-3`,`fashion-4`, `love`, `money`, `fist-pump` and `head-explode`.
17+
- `socialEmote`: when specified, duplicates the avatar and plays different animations on each avatar to create a social interaction scenario. The structure should be a JSON object with the following properties:
18+
- `title` (required): a string describing the social emote (e.g., `"High Five"`)
19+
- `loop` (required): a boolean indicating if the animation should loop (e.g., `true`)
20+
- `audio` (optional): a string URL for audio to play with the animation
21+
- `Armature` (optional): animation for the main avatar (e.g., `{"animation": "HighFive_Start"}`)
22+
- `Armature_Prop` (optional): animation for props/objects (e.g., `{"animation": "HighFive_Prop_Start"}`)
23+
- `Armature_Other` (optional): animation for the duplicated avatar using AvatarOther\_ nodes (e.g., `{"animation": "HighFive_Other_Start"}`)
24+
- Example: `{"title": "High Five", "loop": true, "Armature": {"animation": "HighFive_Start"}, "Armature_Other": {"animation": "HighFive_Other_Start"}}`
1725
- `zoom`: the level of zoom, it must be a number between 1 and 100.
1826
- `zoomScale`: a multiplier for the zoom level. By default is `1` but it can be increased to get extra zoom.
1927
- `camera`: which camera type to use, either `interactive` or `static`. By default it uses the `interactive` one.
@@ -146,7 +154,7 @@ const promises = new Map<string, IFuture<any>>()
146154
function sendRequest<T>(
147155
namespace: 'scene' | 'emote',
148156
method: 'getScreenshot' | 'getMetrics' | 'getLength' | 'isPlaying' | 'goTo' | 'play' | 'pause' | 'stop',
149-
params: any[]
157+
params: any[],
150158
) {
151159
// create promise
152160
const promise = future<T>()

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"@babylonjs/inspector": "^4.2.2",
1010
"@babylonjs/loaders": "^4.2.2",
1111
"@babylonjs/materials": "^4.2.2",
12-
"@dcl/schemas": "^18.1.0",
12+
"@dcl/schemas": "^20.1.1",
1313
"@dcl/ui-env": "^1.5.1",
1414
"classnames": "^2.3.1",
1515
"decentraland-ui": "^6.17.1",

src/config/env/dev.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"NFT_SERVER_URL": "https://nft-api.decentraland.zone",
3-
"PEER_URL": "https://peer.decentraland.zone",
3+
"PEER_URL": "https://peer-ap1.decentraland.zone",
44
"NETWORK": "amoy"
55
}

src/hooks/useOptions.ts

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { useMemo, useRef, useEffect, useState } from 'react'
2-
import { BodyShape, PreviewCamera, PreviewEmote, PreviewOptions, PreviewProjection, PreviewType } from '@dcl/schemas'
2+
import {
3+
BodyShape,
4+
PreviewCamera,
5+
PreviewEmote,
6+
PreviewOptions,
7+
PreviewProjection,
8+
PreviewType,
9+
PreviewUnityMode,
10+
} from '@dcl/schemas'
11+
import { SocialEmoteAnimation } from '@dcl/schemas/dist/dapps/preview/social-emote-animation'
312
import { parseZoom } from '../lib/zoom'
413
import { useOverrides } from './useOverrides'
514

6-
export enum UnityPreviewMode {
7-
PROFILE = 'profile',
8-
MARKETPLACE = 'marketplace',
9-
AUTHENTICATION = 'authentication',
10-
BUILDER = 'builder',
11-
CONFIGURATOR = 'configurator',
12-
}
13-
1415
export interface OptionsWithSource {
15-
options: PreviewOptions & { mode: UnityPreviewMode | null; disableLoader: boolean }
16+
options: PreviewOptions
1617
overrideSources: Record<string, boolean>
1718
}
1819

@@ -29,7 +30,7 @@ export const useOptions = (): OptionsWithSource => {
2930
}
3031
})
3132

32-
const options = useMemo<PreviewOptions & { mode: UnityPreviewMode | null; disableLoader: boolean }>(() => {
33+
const options = useMemo<PreviewOptions>(() => {
3334
const autoRotateSpeedParam = searchParams.get('autoRotateSpeed') as string | null
3435
const offsetXParam = searchParams.get('offsetX') as string | null
3536
const offsetYParam = searchParams.get('offsetY') as string | null
@@ -55,7 +56,7 @@ export const useOptions = (): OptionsWithSource => {
5556
}
5657
const centerBoundingBox = searchParams.get('centerBoundingBox') !== 'false'
5758

58-
const options: PreviewOptions & { mode: UnityPreviewMode | null; disableLoader: boolean } = {
59+
const options: PreviewOptions = {
5960
contractAddress: searchParams.get('contract')!,
6061
tokenId: searchParams.get('token'),
6162
itemId: searchParams.get('item'),
@@ -104,9 +105,18 @@ export const useOptions = (): OptionsWithSource => {
104105
lockAlpha: lockAlpha === 'true',
105106
lockBeta: lockBeta === 'true',
106107
lockRadius: lockRadius === 'true',
107-
mode: searchParams.get('mode') as UnityPreviewMode | null,
108+
unityMode: searchParams.get('mode') as PreviewUnityMode | null,
108109
disableLoader: searchParams.has('disableLoader'),
109110
username: searchParams.get('username'),
111+
socialEmote: (() => {
112+
const socialEmoteParam = searchParams.get('socialEmote')
113+
if (!socialEmoteParam) return null
114+
try {
115+
return JSON.parse(socialEmoteParam) as SocialEmoteAnimation
116+
} catch {
117+
return null
118+
}
119+
})(),
110120
}
111121

112122
return options

src/hooks/useUnityConfig.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,20 @@ import {
99
EmoteDefinition,
1010
PreviewType,
1111
Avatar,
12+
PreviewUnityMode,
1213
} from '@dcl/schemas'
1314
import { config } from '../config'
1415
import { colorToHex, formatHex } from '../lib/color'
1516
import { fetchItemFromContract, fetchProfile, fetchProfileEntity, sanitizeProfile } from '../lib/config'
16-
import { UnityPreviewMode, useOptions } from './useOptions'
17+
import { useOptions } from './useOptions'
1718
import { isWearable } from '../lib/wearable'
1819
import { isTexture } from '../lib/representation'
1920
import { getWearableRepresentationOrDefault } from '../lib/representation'
2021
import { getRandomDefaultProfile } from '../lib/profile'
2122

2223
export interface UnityPreviewConfig {
2324
background: Background
24-
mode: UnityPreviewMode | null
25+
mode: PreviewUnityMode | null
2526
type: PreviewType
2627
base64: string | null
2728
bodyShape: BodyShape | null
@@ -59,7 +60,7 @@ type QueryParams = {
5960
eyeColor: string
6061
hairColor: string
6162
skinColor: string
62-
mode: UnityPreviewMode | string
63+
mode: PreviewUnityMode | string
6364
camera: PreviewCamera
6465
projection: PreviewProjection
6566
emote: string
@@ -198,7 +199,7 @@ export function useUnityConfig(): [UnityPreviewConfig | null, boolean, string |
198199
})
199200

200201
// Get camera settings
201-
const mode = options.mode || null
202+
const mode = options.unityMode || null
202203
const camera =
203204
options.camera && Object.values(PreviewCamera).includes(options.camera as PreviewCamera)
204205
? (options.camera as PreviewCamera)
@@ -248,7 +249,7 @@ export function useUnityConfig(): [UnityPreviewConfig | null, boolean, string |
248249
const base64s = toQueryArray(options.base64s)
249250

250251
// For configurator mode, only add mode parameter
251-
if (mode === 'configurator') {
252+
if (mode === PreviewUnityMode.CONFIG) {
252253
const queryParams: Partial<QueryParams> = {
253254
mode: toQueryValue(mode || ''),
254255
}

0 commit comments

Comments
 (0)