@oxy.so/bloom 7.1.2 → 7.1.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/assets/character-runtime/README.md +114 -19
- package/assets/character-runtime/authored-parts.mjs +754 -0
- package/assets/character-runtime/catalog-parts.mjs +362 -0
- package/assets/character-runtime/character-recipe.mjs +247 -0
- package/assets/character-runtime/clippo-geometry.mjs +679 -0
- package/assets/character-runtime/controller-mode.mjs +208 -0
- package/assets/character-runtime/cyclops-geometry.mjs +180 -0
- package/assets/character-runtime/legacy-engine.mjs +406 -54
- package/assets/character-runtime/legacy-geometry.mjs +242 -85
- package/assets/character-runtime/legacy-worker.mjs +82 -23
- package/assets/character-runtime/managed-avatar.mjs +12 -17
- package/assets/character-runtime/migrated-contours.mjs +2067 -0
- package/assets/character-runtime/migrated-faces.mjs +59 -0
- package/assets/character-runtime/pose-transition.mjs +523 -0
- package/assets/character-runtime/preparation-cache.mjs +60 -0
- package/assets/character-runtime/render-budget.mjs +5 -3
- package/assets/character-runtime/render-errors.mjs +180 -0
- package/assets/character-runtime/resolution.mjs +10 -0
- package/assets/character-runtime/runtime.mjs +744 -295
- package/assets/character-runtime/sha256.mjs +44 -0
- package/assets/character-runtime/shared-programs.mjs +534 -0
- package/assets/character-runtime/shared-surface.mjs +490 -0
- package/assets/character-runtime/shared-textures.mjs +420 -0
- package/assets/character-runtime/thumbnails/eyes/todd.png +0 -0
- package/docs/agent-avatar.mdx +45 -8
- package/docs/agent-creator.mdx +13 -3
- package/lib/commonjs/agent-avatar/AgentAvatar.js +1 -1
- package/lib/commonjs/agent-avatar/AgentAvatar.js.map +1 -1
- package/lib/commonjs/agent-avatar/CharacterAvatar.js +2 -1
- package/lib/commonjs/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/commonjs/agent-avatar/character-colors.js +19 -0
- package/lib/commonjs/agent-avatar/character-colors.js.map +1 -0
- package/lib/commonjs/agent-avatar/character-shapes.js +106 -0
- package/lib/commonjs/agent-avatar/character-shapes.js.map +1 -0
- package/lib/commonjs/agent-avatar/config-character.js +4 -0
- package/lib/commonjs/agent-avatar/config-character.js.map +1 -1
- package/lib/commonjs/agent-avatar/legacy-recipe.js +19 -6
- package/lib/commonjs/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/commonjs/agent-creator/AgentCreatorBase.js +67 -107
- package/lib/commonjs/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/commonjs/agent-creator/CharacterControls.js +23 -5
- package/lib/commonjs/agent-creator/CharacterControls.js.map +1 -1
- package/lib/commonjs/agent-creator/ClippoArtwork.js +63 -0
- package/lib/commonjs/agent-creator/ClippoArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/CyclopsArtwork.js +45 -0
- package/lib/commonjs/agent-creator/CyclopsArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/EmotionPicker.js +8 -1
- package/lib/commonjs/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/commonjs/agent-creator/ShapeSilhouette.js +8 -1
- package/lib/commonjs/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/commonjs/agent-creator/ToddArtwork.js +29 -0
- package/lib/commonjs/agent-creator/ToddArtwork.js.map +1 -0
- package/lib/commonjs/agent-creator/constants.js +16 -17
- package/lib/commonjs/agent-creator/constants.js.map +1 -1
- package/lib/commonjs/agent-creator/messages.js +1 -1
- package/lib/commonjs/agent-creator/messages.js.map +1 -1
- package/lib/commonjs/locale/translations/ar.js +1 -1
- package/lib/commonjs/locale/translations/ar.js.map +1 -1
- package/lib/commonjs/locale/translations/bn.js +1 -1
- package/lib/commonjs/locale/translations/bn.js.map +1 -1
- package/lib/commonjs/locale/translations/ca.js +1 -1
- package/lib/commonjs/locale/translations/ca.js.map +1 -1
- package/lib/commonjs/locale/translations/de.js +1 -1
- package/lib/commonjs/locale/translations/de.js.map +1 -1
- package/lib/commonjs/locale/translations/es.js +1 -1
- package/lib/commonjs/locale/translations/es.js.map +1 -1
- package/lib/commonjs/locale/translations/fr.js +1 -1
- package/lib/commonjs/locale/translations/fr.js.map +1 -1
- package/lib/commonjs/locale/translations/hi.js +1 -1
- package/lib/commonjs/locale/translations/hi.js.map +1 -1
- package/lib/commonjs/locale/translations/id.js +1 -1
- package/lib/commonjs/locale/translations/id.js.map +1 -1
- package/lib/commonjs/locale/translations/it.js +1 -1
- package/lib/commonjs/locale/translations/it.js.map +1 -1
- package/lib/commonjs/locale/translations/ja.js +1 -1
- package/lib/commonjs/locale/translations/ja.js.map +1 -1
- package/lib/commonjs/locale/translations/pt.js +1 -1
- package/lib/commonjs/locale/translations/pt.js.map +1 -1
- package/lib/commonjs/locale/translations/ru.js +1 -1
- package/lib/commonjs/locale/translations/ru.js.map +1 -1
- package/lib/commonjs/locale/translations/tr.js +1 -1
- package/lib/commonjs/locale/translations/tr.js.map +1 -1
- package/lib/commonjs/locale/translations/zh.js +1 -1
- package/lib/commonjs/locale/translations/zh.js.map +1 -1
- package/lib/module/agent-avatar/AgentAvatar.js +1 -1
- package/lib/module/agent-avatar/AgentAvatar.js.map +1 -1
- package/lib/module/agent-avatar/CharacterAvatar.js +2 -1
- package/lib/module/agent-avatar/CharacterAvatar.js.map +1 -1
- package/lib/module/agent-avatar/character-colors.js +15 -0
- package/lib/module/agent-avatar/character-colors.js.map +1 -0
- package/lib/module/agent-avatar/character-shapes.js +97 -0
- package/lib/module/agent-avatar/character-shapes.js.map +1 -0
- package/lib/module/agent-avatar/config-character.js +4 -0
- package/lib/module/agent-avatar/config-character.js.map +1 -1
- package/lib/module/agent-avatar/legacy-recipe.js +19 -6
- package/lib/module/agent-avatar/legacy-recipe.js.map +1 -1
- package/lib/module/agent-creator/AgentCreatorBase.js +69 -109
- package/lib/module/agent-creator/AgentCreatorBase.js.map +1 -1
- package/lib/module/agent-creator/CharacterControls.js +24 -6
- package/lib/module/agent-creator/CharacterControls.js.map +1 -1
- package/lib/module/agent-creator/ClippoArtwork.js +59 -0
- package/lib/module/agent-creator/ClippoArtwork.js.map +1 -0
- package/lib/module/agent-creator/CyclopsArtwork.js +41 -0
- package/lib/module/agent-creator/CyclopsArtwork.js.map +1 -0
- package/lib/module/agent-creator/EmotionPicker.js +8 -1
- package/lib/module/agent-creator/EmotionPicker.js.map +1 -1
- package/lib/module/agent-creator/ShapeSilhouette.js +8 -1
- package/lib/module/agent-creator/ShapeSilhouette.js.map +1 -1
- package/lib/module/agent-creator/ToddArtwork.js +25 -0
- package/lib/module/agent-creator/ToddArtwork.js.map +1 -0
- package/lib/module/agent-creator/constants.js +8 -16
- package/lib/module/agent-creator/constants.js.map +1 -1
- package/lib/module/agent-creator/messages.js +1 -1
- package/lib/module/agent-creator/messages.js.map +1 -1
- package/lib/module/locale/translations/ar.js +1 -1
- package/lib/module/locale/translations/ar.js.map +1 -1
- package/lib/module/locale/translations/bn.js +1 -1
- package/lib/module/locale/translations/bn.js.map +1 -1
- package/lib/module/locale/translations/ca.js +1 -1
- package/lib/module/locale/translations/ca.js.map +1 -1
- package/lib/module/locale/translations/de.js +1 -1
- package/lib/module/locale/translations/de.js.map +1 -1
- package/lib/module/locale/translations/es.js +1 -1
- package/lib/module/locale/translations/es.js.map +1 -1
- package/lib/module/locale/translations/fr.js +1 -1
- package/lib/module/locale/translations/fr.js.map +1 -1
- package/lib/module/locale/translations/hi.js +1 -1
- package/lib/module/locale/translations/hi.js.map +1 -1
- package/lib/module/locale/translations/id.js +1 -1
- package/lib/module/locale/translations/id.js.map +1 -1
- package/lib/module/locale/translations/it.js +1 -1
- package/lib/module/locale/translations/it.js.map +1 -1
- package/lib/module/locale/translations/ja.js +1 -1
- package/lib/module/locale/translations/ja.js.map +1 -1
- package/lib/module/locale/translations/pt.js +1 -1
- package/lib/module/locale/translations/pt.js.map +1 -1
- package/lib/module/locale/translations/ru.js +1 -1
- package/lib/module/locale/translations/ru.js.map +1 -1
- package/lib/module/locale/translations/tr.js +1 -1
- package/lib/module/locale/translations/tr.js.map +1 -1
- package/lib/module/locale/translations/zh.js +1 -1
- package/lib/module/locale/translations/zh.js.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts +13 -0
- package/lib/typescript/commonjs/agent-avatar/character-colors.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts +19 -0
- package/lib/typescript/commonjs/agent-avatar/character-shapes.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts +4 -0
- package/lib/typescript/commonjs/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts +2 -10
- package/lib/typescript/commonjs/agent-avatar/legacy-recipe.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/AgentCreatorBase.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts +2 -1
- package/lib/typescript/commonjs/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts +6 -0
- package/lib/typescript/commonjs/agent-creator/ClippoArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts +5 -0
- package/lib/typescript/commonjs/agent-creator/CyclopsArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts +1 -0
- package/lib/typescript/commonjs/agent-creator/EmotionPicker.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ShapeSilhouette.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts +6 -0
- package/lib/typescript/commonjs/agent-creator/ToddArtwork.d.ts.map +1 -0
- package/lib/typescript/commonjs/agent-creator/constants.d.ts +7 -15
- package/lib/typescript/commonjs/agent-creator/constants.d.ts.map +1 -1
- package/lib/typescript/commonjs/agent-creator/messages.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/CharacterAvatar.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/character-colors.d.ts +13 -0
- package/lib/typescript/module/agent-avatar/character-colors.d.ts.map +1 -0
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts +19 -0
- package/lib/typescript/module/agent-avatar/character-shapes.d.ts.map +1 -0
- package/lib/typescript/module/agent-avatar/config-character.d.ts +4 -0
- package/lib/typescript/module/agent-avatar/config-character.d.ts.map +1 -1
- package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts +2 -10
- package/lib/typescript/module/agent-avatar/legacy-recipe.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/AgentCreatorBase.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/CharacterControls.d.ts +2 -1
- package/lib/typescript/module/agent-creator/CharacterControls.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts +6 -0
- package/lib/typescript/module/agent-creator/ClippoArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts +5 -0
- package/lib/typescript/module/agent-creator/CyclopsArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/EmotionPicker.d.ts +1 -0
- package/lib/typescript/module/agent-creator/EmotionPicker.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ShapeSilhouette.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts +6 -0
- package/lib/typescript/module/agent-creator/ToddArtwork.d.ts.map +1 -0
- package/lib/typescript/module/agent-creator/constants.d.ts +7 -15
- package/lib/typescript/module/agent-creator/constants.d.ts.map +1 -1
- package/lib/typescript/module/agent-creator/messages.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/agent-avatar/AgentAvatar.tsx +1 -1
- package/src/agent-avatar/CharacterAvatar.tsx +4 -1
- package/src/agent-avatar/character-colors.ts +12 -0
- package/src/agent-avatar/character-shapes.ts +122 -0
- package/src/agent-avatar/config-character.ts +39 -6
- package/src/agent-avatar/legacy-recipe.ts +34 -6
- package/src/agent-creator/AgentCreatorBase.tsx +121 -152
- package/src/agent-creator/CharacterControls.tsx +39 -14
- package/src/agent-creator/ClippoArtwork.tsx +49 -0
- package/src/agent-creator/CyclopsArtwork.tsx +27 -0
- package/src/agent-creator/EmotionPicker.tsx +55 -16
- package/src/agent-creator/ShapeSilhouette.tsx +16 -1
- package/src/agent-creator/ToddArtwork.tsx +24 -0
- package/src/agent-creator/constants.ts +47 -14
- package/src/agent-creator/messages.ts +2 -1
- package/src/locale/translations/ar.ts +1 -1
- package/src/locale/translations/bn.ts +1 -1
- package/src/locale/translations/ca.ts +1 -1
- package/src/locale/translations/de.ts +1 -1
- package/src/locale/translations/es.ts +1 -1
- package/src/locale/translations/fr.ts +1 -1
- package/src/locale/translations/hi.ts +1 -1
- package/src/locale/translations/id.ts +1 -1
- package/src/locale/translations/it.ts +1 -1
- package/src/locale/translations/ja.ts +1 -1
- package/src/locale/translations/pt.ts +1 -1
- package/src/locale/translations/ru.ts +1 -1
- package/src/locale/translations/tr.ts +1 -1
- package/src/locale/translations/zh.ts +1 -1
- package/src/__tests__/support/adoption-matrix.ts +0 -683
- package/src/__tests__/support/card-surface.ts +0 -25
- package/src/__tests__/support/collision-fixture-barrel.ts +0 -20
- package/src/__tests__/support/commerce-harness.tsx +0 -97
- package/src/__tests__/support/composite.ts +0 -68
- package/src/__tests__/support/constructed-style-sheets.ts +0 -68
- package/src/__tests__/support/messages-in.ts +0 -10
- package/src/__tests__/support/press-host.ts +0 -30
- package/src/__tests__/support/rendered-style.ts +0 -99
- package/src/__tests__/support/unread-hook-fixture.ts +0 -33
- package/src/__tests__/support/worklet-capture-fixture.tsx +0 -28
- package/src/agent-avatar/__tests__/artwork-golden.json +0 -774
- package/src/agent-creator/__tests__/support/character-runtime-fixture.tsx +0 -26
- package/src/theme/__tests__/__fixtures__/golden-resolved-tokens.json +0 -9346
- package/src/theme/__tests__/__fixtures__/tonal-glass-primary-failures.json +0 -69
- package/src/theme/__tests__/fixtures/color-engine-golden.json +0 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { avatarHex } from './avatar-color';
|
|
2
|
+
import type { AvatarCharacterConfig } from './config-character';
|
|
3
|
+
import type { AvatarConfig } from './model';
|
|
4
|
+
|
|
5
|
+
export const NATIVE_CHARACTER_SHAPES = [
|
|
6
|
+
['clippo', 'Clippo'],
|
|
7
|
+
['todd', 'Todd'],
|
|
8
|
+
['circle', 'Circle'],
|
|
9
|
+
['rounded_triangle', 'Rounded triangle'],
|
|
10
|
+
['capsule', 'Capsule'],
|
|
11
|
+
['rounded_head_two_ears', 'Rounded head with two ears'],
|
|
12
|
+
['six_lobed_flower', 'Six lobed flower'],
|
|
13
|
+
['heart', 'Heart'],
|
|
14
|
+
['four_lobed_butterfly', 'Four lobed butterfly'],
|
|
15
|
+
['circle_two_ears', 'Circle with two ears'],
|
|
16
|
+
['twelve_scalloped_rosette', 'Twelve scalloped rosette'],
|
|
17
|
+
['rounded_cube', 'Hexagon'],
|
|
18
|
+
['rounded_diamond', 'Rounded diamond'],
|
|
19
|
+
] as const;
|
|
20
|
+
export const MIGRATED_CHARACTER_SHAPES = [
|
|
21
|
+
['slender', 'Slender'],
|
|
22
|
+
['pocket', 'Pocket'],
|
|
23
|
+
['petal', 'Petal'],
|
|
24
|
+
['star', 'Star'],
|
|
25
|
+
['cloud', 'Cloud'],
|
|
26
|
+
['shield', 'Shield'],
|
|
27
|
+
['pebble', 'Pebble'],
|
|
28
|
+
['squircle', 'Squircle'],
|
|
29
|
+
] as const;
|
|
30
|
+
export const CHARACTER_SHAPES = [
|
|
31
|
+
...NATIVE_CHARACTER_SHAPES,
|
|
32
|
+
...MIGRATED_CHARACTER_SHAPES,
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
export function isMigratedCharacterShape(id: string | undefined): boolean {
|
|
36
|
+
return MIGRATED_CHARACTER_SHAPES.some(([shape]) => shape === id);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** The saved paper/blob fields remain readable; canonical shape IDs own new edits. */
|
|
40
|
+
export function currentCharacterShape(config: AvatarConfig): string {
|
|
41
|
+
if (config.character?.selections?.shape)
|
|
42
|
+
return config.character.selections.shape;
|
|
43
|
+
const shape = config.family === 'fold' ? config.foldShape : config.shape;
|
|
44
|
+
const equivalent: Partial<Record<string, string>> = {
|
|
45
|
+
triangle: 'rounded_triangle',
|
|
46
|
+
flower: 'six_lobed_flower',
|
|
47
|
+
diamond: 'rounded_diamond',
|
|
48
|
+
};
|
|
49
|
+
return equivalent[shape] ?? shape;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Geometry-only view of one of the eight migrated contours. */
|
|
53
|
+
export function characterShapeGeometry(config: AvatarConfig): AvatarConfig {
|
|
54
|
+
const shape = config.character?.selections?.shape;
|
|
55
|
+
if (!isMigratedCharacterShape(shape)) return config;
|
|
56
|
+
return shape === 'pebble' || shape === 'squircle'
|
|
57
|
+
? { ...config, family: 'blob', shape }
|
|
58
|
+
: {
|
|
59
|
+
...config,
|
|
60
|
+
family: 'fold',
|
|
61
|
+
foldShape: shape as AvatarConfig['foldShape'],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** Retain effective authored parts while preparing the next body. An old recipe
|
|
66
|
+
* is promoted once, with its actual paint and contour rather than Felipe defaults.
|
|
67
|
+
*/
|
|
68
|
+
export function materializeCharacter(
|
|
69
|
+
config: AvatarConfig,
|
|
70
|
+
selected: Readonly<Record<string, string>> = {},
|
|
71
|
+
): AvatarCharacterConfig {
|
|
72
|
+
const saved = config.character;
|
|
73
|
+
if (!saved || saved.preset === 'bloom')
|
|
74
|
+
return {
|
|
75
|
+
...saved,
|
|
76
|
+
preset: 'legacy',
|
|
77
|
+
...(saved?.bodyColor
|
|
78
|
+
? { bodyColor: saved.bodyColor }
|
|
79
|
+
: !saved?.selections?.color
|
|
80
|
+
? { bodyColor: avatarHex(config) }
|
|
81
|
+
: {}),
|
|
82
|
+
selections: {
|
|
83
|
+
shape: currentCharacterShape(config),
|
|
84
|
+
eyes: 'oval',
|
|
85
|
+
eyewear: 'none',
|
|
86
|
+
accessory: 'none',
|
|
87
|
+
...saved?.selections,
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
const defaults: NonNullable<AvatarCharacterConfig['selections']> = {};
|
|
91
|
+
for (const part of ['eyes', 'eyewear', 'accessory'] as const)
|
|
92
|
+
if (selected[part]) defaults[part] = selected[part];
|
|
93
|
+
// These virtual parts are absent from the backing native catalog.
|
|
94
|
+
if (!defaults.eyes && saved.preset === 'clippo') defaults.eyes = 'clippo';
|
|
95
|
+
if (!defaults.eyes && saved.preset === 'lime_frog') defaults.eyes = 'todd';
|
|
96
|
+
if (!defaults.accessory && saved.preset === 'blue_beret')
|
|
97
|
+
defaults.accessory = 'felipe_beret';
|
|
98
|
+
return { ...saved, selections: { ...defaults, ...saved.selections } };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** All 21 bodies change the same character recipe. Named paint and explicit RGB
|
|
102
|
+
* keep their precedence; a body never supplies a replacement color or face.
|
|
103
|
+
*/
|
|
104
|
+
export function createConfigForShape(
|
|
105
|
+
config: AvatarConfig,
|
|
106
|
+
shape: string,
|
|
107
|
+
selected: Readonly<Record<string, string>> = {},
|
|
108
|
+
): AvatarConfig {
|
|
109
|
+
if (!CHARACTER_SHAPES.some(([id]) => id === shape))
|
|
110
|
+
throw new Error('Unknown character shape.');
|
|
111
|
+
const character = materializeCharacter(config, selected);
|
|
112
|
+
if (!character.bodyColor && !character.selections?.color) {
|
|
113
|
+
if (character.preset === 'clippo') character.bodyColor = '#999b9d';
|
|
114
|
+
else if (selected.color)
|
|
115
|
+
character.selections = { ...character.selections, color: selected.color };
|
|
116
|
+
else if (selected.bodyColor) character.bodyColor = selected.bodyColor;
|
|
117
|
+
}
|
|
118
|
+
return characterShapeGeometry({
|
|
119
|
+
...config,
|
|
120
|
+
character: { ...character, selections: { ...character.selections, shape } },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
/** Catalog parts extend the existing avatar recipe without discarding its shape or expression fields. */
|
|
2
|
-
export type AvatarCharacterCategory =
|
|
2
|
+
export type AvatarCharacterCategory =
|
|
3
|
+
'shape' | 'color' | 'eyes' | 'eyewear' | 'accessory';
|
|
3
4
|
|
|
4
5
|
export type AvatarCharacterConfig = {
|
|
6
|
+
/** Named catalog preset, including Clippo (`clippo`), or a saved renderer ID. */
|
|
5
7
|
preset: string;
|
|
8
|
+
/** Clippo's open wire body and ring eyes are independently selectable with ID `clippo`. */
|
|
6
9
|
selections?: Partial<Record<AvatarCharacterCategory, string>>;
|
|
7
10
|
/** Custom body RGB accepted by the original renderer, stored as lowercase #RRGGBB. */
|
|
8
11
|
bodyColor?: string;
|
|
12
|
+
/** @deprecated Retained when reading saved recipes; ignored by the renderer. Each shape owns its eye layout. */
|
|
13
|
+
eyeSpacing?: number;
|
|
9
14
|
};
|
|
10
15
|
|
|
11
|
-
const categories: readonly AvatarCharacterCategory[] = [
|
|
16
|
+
const categories: readonly AvatarCharacterCategory[] = [
|
|
17
|
+
'shape',
|
|
18
|
+
'color',
|
|
19
|
+
'eyes',
|
|
20
|
+
'eyewear',
|
|
21
|
+
'accessory',
|
|
22
|
+
];
|
|
12
23
|
const validId = (value: unknown): value is string =>
|
|
13
24
|
typeof value === 'string' && value.length > 0 && value.length <= 63;
|
|
14
25
|
|
|
@@ -19,22 +30,44 @@ export function parseCharacterConfig(value: unknown): AvatarCharacterConfig {
|
|
|
19
30
|
const candidate = value as Record<string, unknown>;
|
|
20
31
|
if (!validId(candidate.preset)) throw new Error('Invalid character preset.');
|
|
21
32
|
const result: AvatarCharacterConfig = { preset: candidate.preset };
|
|
33
|
+
if (candidate.eyeSpacing !== undefined) {
|
|
34
|
+
if (
|
|
35
|
+
typeof candidate.eyeSpacing !== 'number' ||
|
|
36
|
+
!Number.isFinite(candidate.eyeSpacing) ||
|
|
37
|
+
candidate.eyeSpacing < 0.5 ||
|
|
38
|
+
candidate.eyeSpacing > 1.5
|
|
39
|
+
)
|
|
40
|
+
throw new Error('Invalid character eye spacing.');
|
|
41
|
+
result.eyeSpacing = candidate.eyeSpacing;
|
|
42
|
+
}
|
|
22
43
|
if (candidate.bodyColor !== undefined) {
|
|
23
|
-
if (
|
|
44
|
+
if (
|
|
45
|
+
typeof candidate.bodyColor !== 'string' ||
|
|
46
|
+
candidate.bodyColor.length !== 7 ||
|
|
47
|
+
!/^#[0-9a-f]{6}$/i.test(candidate.bodyColor)
|
|
48
|
+
)
|
|
24
49
|
throw new Error('Invalid character body color.');
|
|
25
50
|
result.bodyColor = candidate.bodyColor.toLowerCase();
|
|
26
51
|
}
|
|
27
52
|
if (candidate.selections !== undefined) {
|
|
28
|
-
if (
|
|
53
|
+
if (
|
|
54
|
+
!candidate.selections ||
|
|
55
|
+
typeof candidate.selections !== 'object' ||
|
|
56
|
+
Array.isArray(candidate.selections)
|
|
57
|
+
)
|
|
29
58
|
throw new Error('Invalid character selections.');
|
|
30
59
|
const selections: NonNullable<AvatarCharacterConfig['selections']> = {};
|
|
31
60
|
for (const [category, id] of Object.entries(candidate.selections)) {
|
|
32
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
!categories.includes(category as AvatarCharacterCategory) ||
|
|
63
|
+
!validId(id)
|
|
64
|
+
)
|
|
33
65
|
throw new Error('Invalid character selection.');
|
|
34
66
|
selections[category as AvatarCharacterCategory] = id;
|
|
35
67
|
}
|
|
36
68
|
result.selections = selections;
|
|
37
69
|
}
|
|
38
|
-
if ('state' in candidate)
|
|
70
|
+
if ('state' in candidate)
|
|
71
|
+
throw new Error('Opaque character state is not supported.');
|
|
39
72
|
return result;
|
|
40
73
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { CHARACTER_COLORS } from './character-colors';
|
|
2
|
+
import {
|
|
3
|
+
characterShapeGeometry,
|
|
4
|
+
isMigratedCharacterShape,
|
|
5
|
+
} from './character-shapes';
|
|
1
6
|
import { avatarHex } from './avatar-color';
|
|
2
7
|
import { legacyContours } from './legacy-contours';
|
|
3
8
|
import type { AvatarConfig } from './model';
|
|
@@ -9,6 +14,7 @@ export type LegacyRecipe = {
|
|
|
9
14
|
points?: Point[];
|
|
10
15
|
shape?: string;
|
|
11
16
|
eyes: string;
|
|
17
|
+
eyeSpacing?: number;
|
|
12
18
|
selections?: Pick<
|
|
13
19
|
NonNullable<AvatarCharacterConfig['selections']>,
|
|
14
20
|
'eyewear' | 'accessory'
|
|
@@ -18,6 +24,8 @@ export type LegacyRecipe = {
|
|
|
18
24
|
|
|
19
25
|
/** Saved unsupported artwork stays readable without pretending it was migrated. */
|
|
20
26
|
export function legacyRecipeUnsupported(config: AvatarConfig): boolean {
|
|
27
|
+
if (isMigratedCharacterShape(config.character?.selections?.shape))
|
|
28
|
+
return false;
|
|
21
29
|
return (
|
|
22
30
|
config.family === 'alien' || config.family === 'mascot' || !config.face
|
|
23
31
|
);
|
|
@@ -74,6 +82,8 @@ export function radialContour(polygons: Point[][], samples = 256): Point[] {
|
|
|
74
82
|
|
|
75
83
|
/** Shared capability identity for the editor and the legacy engine adapter. */
|
|
76
84
|
export function legacyCharacterRecipe(config: AvatarConfig) {
|
|
85
|
+
if (config.character && config.character.preset !== 'bloom')
|
|
86
|
+
return config.character;
|
|
77
87
|
const customization =
|
|
78
88
|
config.character?.preset === 'bloom' ? config.character : undefined;
|
|
79
89
|
return {
|
|
@@ -88,7 +98,15 @@ export function legacyCharacterRecipe(config: AvatarConfig) {
|
|
|
88
98
|
? { accessory: customization.selections.accessory }
|
|
89
99
|
: {}),
|
|
90
100
|
},
|
|
91
|
-
bodyColor:
|
|
101
|
+
bodyColor:
|
|
102
|
+
customization?.bodyColor ??
|
|
103
|
+
CHARACTER_COLORS[
|
|
104
|
+
customization?.selections?.color as keyof typeof CHARACTER_COLORS
|
|
105
|
+
] ??
|
|
106
|
+
avatarHex(config),
|
|
107
|
+
...(customization?.eyeSpacing !== undefined
|
|
108
|
+
? { eyeSpacing: customization.eyeSpacing }
|
|
109
|
+
: {}),
|
|
92
110
|
};
|
|
93
111
|
}
|
|
94
112
|
|
|
@@ -102,14 +120,24 @@ export function legacyRecipe(
|
|
|
102
120
|
): LegacyRecipe {
|
|
103
121
|
if (legacyRecipeUnsupported(config))
|
|
104
122
|
throw new Error('Unsupported legacy 3D recipe');
|
|
105
|
-
const
|
|
123
|
+
const geometry = characterShapeGeometry(config);
|
|
124
|
+
const canonical = config.character && config.character.preset !== 'bloom';
|
|
125
|
+
const selectedShape = canonical
|
|
126
|
+
? config.character?.selections?.shape
|
|
127
|
+
: undefined;
|
|
128
|
+
const shape = isMigratedCharacterShape(selectedShape)
|
|
129
|
+
? undefined
|
|
130
|
+
: (selectedShape ?? legacyNativeShape(geometry));
|
|
106
131
|
const recipe = legacyCharacterRecipe(config);
|
|
107
|
-
const { eyewear, accessory } = recipe.selections;
|
|
132
|
+
const { eyewear, accessory } = recipe.selections ?? {};
|
|
108
133
|
return {
|
|
109
134
|
...(shape
|
|
110
135
|
? { shape }
|
|
111
|
-
: { points: radialContour(legacyContours(
|
|
112
|
-
eyes: recipe.selections
|
|
136
|
+
: { points: radialContour(legacyContours(geometry), samples) }),
|
|
137
|
+
eyes: recipe.selections?.eyes ?? 'oval',
|
|
138
|
+
...(recipe.eyeSpacing !== undefined
|
|
139
|
+
? { eyeSpacing: recipe.eyeSpacing }
|
|
140
|
+
: {}),
|
|
113
141
|
...(eyewear || accessory
|
|
114
142
|
? {
|
|
115
143
|
selections: {
|
|
@@ -118,6 +146,6 @@ export function legacyRecipe(
|
|
|
118
146
|
},
|
|
119
147
|
}
|
|
120
148
|
: {}),
|
|
121
|
-
patch: { bodyColor: recipe.bodyColor },
|
|
149
|
+
patch: { bodyColor: recipe.bodyColor ?? avatarHex(config) },
|
|
122
150
|
};
|
|
123
151
|
}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
import { useContext, useMemo, useState } from 'react';
|
|
1
|
+
import { useContext, useMemo, useRef, useState } from 'react';
|
|
2
2
|
import { Platform } from 'react-native';
|
|
3
3
|
import { AgentAvatar, type AvatarConfig } from '../agent-avatar';
|
|
4
|
+
import {
|
|
5
|
+
CHARACTER_SHAPES,
|
|
6
|
+
NATIVE_CHARACTER_SHAPES,
|
|
7
|
+
createConfigForShape,
|
|
8
|
+
currentCharacterShape,
|
|
9
|
+
materializeCharacter,
|
|
10
|
+
} from '../agent-avatar/character-shapes';
|
|
4
11
|
import type { AvatarCharacterCategory } from '../agent-avatar/config-character';
|
|
5
12
|
import {
|
|
6
13
|
CharacterRuntimeContext,
|
|
7
14
|
CharacterCapabilitiesContext,
|
|
8
15
|
} from '../agent-avatar/context';
|
|
9
|
-
import {
|
|
10
|
-
legacyCharacterRecipe,
|
|
11
|
-
legacyNativeShape,
|
|
12
|
-
} from '../agent-avatar/legacy-recipe';
|
|
16
|
+
import { legacyCharacterRecipe } from '../agent-avatar/legacy-recipe';
|
|
13
17
|
import { Button } from '../button/Button';
|
|
14
18
|
import { CloseButton } from '../button/CloseButton';
|
|
15
19
|
import { useDirectionProps } from '../hooks/use-is-rtl';
|
|
@@ -56,58 +60,86 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
56
60
|
);
|
|
57
61
|
const { runtimeUrl } = runtime;
|
|
58
62
|
const beta = Boolean(c.character && c.character.preset !== 'bloom');
|
|
59
|
-
const nativeShape = legacyNativeShape(c);
|
|
60
63
|
const key = JSON.stringify(beta ? c.character : legacyCharacterRecipe(c));
|
|
61
|
-
const
|
|
64
|
+
const currentCapabilities =
|
|
62
65
|
catalog.capabilitiesByKey?.get(key) ??
|
|
63
66
|
(catalog.capabilities?.key === key ? catalog.capabilities : undefined);
|
|
67
|
+
const retained = useRef<{ owner: string; selected: Record<string, string> }>({
|
|
68
|
+
owner: '',
|
|
69
|
+
selected: {},
|
|
70
|
+
});
|
|
71
|
+
const owner = JSON.stringify([agent.id, c.character?.preset ?? 'bloom']);
|
|
72
|
+
if (retained.current.owner !== owner)
|
|
73
|
+
retained.current = { owner, selected: {} };
|
|
74
|
+
if (currentCapabilities)
|
|
75
|
+
retained.current.selected = currentCapabilities.selected;
|
|
76
|
+
const capabilities = currentCapabilities ?? {
|
|
77
|
+
selected: retained.current.selected,
|
|
78
|
+
available: {},
|
|
79
|
+
};
|
|
64
80
|
const betaColor =
|
|
65
|
-
|
|
81
|
+
c.character?.selections?.color ?? capabilities?.selected.color;
|
|
82
|
+
const betaBodyColor =
|
|
83
|
+
c.character?.bodyColor ??
|
|
84
|
+
(c.character?.preset === 'clippo' && !c.character.selections?.color
|
|
85
|
+
? '#999b9d'
|
|
86
|
+
: undefined) ??
|
|
87
|
+
(!betaColor ? capabilities?.selected.bodyColor : undefined);
|
|
66
88
|
const customColorValue = beta
|
|
67
|
-
? (
|
|
89
|
+
? (betaBodyColor ??
|
|
90
|
+
(c.character?.selections?.color
|
|
91
|
+
? CHARACTER_COLORS[
|
|
92
|
+
c.character.selections.color as keyof typeof CHARACTER_COLORS
|
|
93
|
+
]
|
|
94
|
+
: undefined) ??
|
|
95
|
+
capabilities?.selected.bodyColor ??
|
|
68
96
|
CHARACTER_COLORS[betaColor as keyof typeof CHARACTER_COLORS] ??
|
|
69
97
|
avatarHex(c))
|
|
70
|
-
: (c.character?.bodyColor ??
|
|
98
|
+
: (c.character?.bodyColor ??
|
|
99
|
+
CHARACTER_COLORS[
|
|
100
|
+
c.character?.selections?.color as keyof typeof CHARACTER_COLORS
|
|
101
|
+
] ??
|
|
102
|
+
avatarHex(c));
|
|
71
103
|
const selectedEyes =
|
|
72
|
-
|
|
104
|
+
c.character?.selections?.eyes ??
|
|
105
|
+
capabilities?.selected.eyes ??
|
|
106
|
+
(c.character?.preset === 'clippo'
|
|
107
|
+
? 'clippo'
|
|
108
|
+
: c.character?.preset === 'lime_frog'
|
|
109
|
+
? 'todd'
|
|
110
|
+
: 'oval');
|
|
111
|
+
const selectedEyewear =
|
|
112
|
+
c.character?.selections?.eyewear ?? capabilities?.selected.eyewear;
|
|
113
|
+
const selectedAccessory =
|
|
114
|
+
c.character?.selections?.accessory ?? capabilities?.selected.accessory;
|
|
115
|
+
const selectedParts = {
|
|
116
|
+
...(c.character?.selections?.eyes ||
|
|
117
|
+
capabilities.selected.eyes ||
|
|
118
|
+
c.character?.preset === 'clippo' ||
|
|
119
|
+
c.character?.preset === 'lime_frog'
|
|
120
|
+
? { eyes: selectedEyes }
|
|
121
|
+
: {}),
|
|
122
|
+
...(selectedEyewear ? { eyewear: selectedEyewear } : {}),
|
|
123
|
+
...(selectedAccessory ? { accessory: selectedAccessory } : {}),
|
|
124
|
+
};
|
|
73
125
|
const characterConfig = (
|
|
74
126
|
category: AvatarCharacterCategory,
|
|
75
127
|
id: string,
|
|
76
128
|
): AvatarConfig => {
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
const character = beta
|
|
92
|
-
? c.character!
|
|
93
|
-
: {
|
|
94
|
-
preset: 'blue_beret',
|
|
95
|
-
bodyColor: customColorValue,
|
|
96
|
-
selections: {
|
|
97
|
-
eyewear:
|
|
98
|
-
c.character?.selections?.eyewear ??
|
|
99
|
-
capabilities?.selected.eyewear ??
|
|
100
|
-
'none',
|
|
101
|
-
accessory:
|
|
102
|
-
c.character?.selections?.accessory ??
|
|
103
|
-
capabilities?.selected.accessory ??
|
|
104
|
-
'none',
|
|
105
|
-
eyes: selectedEyes,
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
const selections = { ...character.selections, [category]: id };
|
|
109
|
-
if (category === 'shape') delete selections.eyes;
|
|
110
|
-
const next = { ...character, selections };
|
|
129
|
+
if (category === 'shape')
|
|
130
|
+
return createConfigForShape(c, id, capabilities.selected);
|
|
131
|
+
const character = materializeCharacter(c, capabilities.selected);
|
|
132
|
+
// Choosing a body retains the edited face and the preset's effective parts.
|
|
133
|
+
// Presets supply defaults; their catalog restrictions do not own edits.
|
|
134
|
+
const selections = {
|
|
135
|
+
...selectedParts,
|
|
136
|
+
...character.selections,
|
|
137
|
+
[category]: id,
|
|
138
|
+
};
|
|
139
|
+
const next = {
|
|
140
|
+
...character,
|
|
141
|
+
selections,
|
|
142
|
+
};
|
|
111
143
|
if (category === 'color') delete next.bodyColor;
|
|
112
144
|
return { ...c, character: next };
|
|
113
145
|
};
|
|
@@ -117,103 +149,37 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
117
149
|
? runtimeUrl.slice(0, runtimeUrl.lastIndexOf('/') + 1)
|
|
118
150
|
: '';
|
|
119
151
|
const eyeBackground = customColorValue;
|
|
120
|
-
const migratedShapes = [
|
|
121
|
-
...(['slender', 'pocket', 'petal', 'star', 'cloud', 'shield'] as const).map(
|
|
122
|
-
(shape) => ({
|
|
123
|
-
family: 'fold' as const,
|
|
124
|
-
shape,
|
|
125
|
-
title: messages.shapes[shape],
|
|
126
|
-
}),
|
|
127
|
-
),
|
|
128
|
-
...(
|
|
129
|
-
[
|
|
130
|
-
['pebble', 'Pebble'],
|
|
131
|
-
['squircle', 'Squircle'],
|
|
132
|
-
] as const
|
|
133
|
-
).map(([shape, title]) => ({
|
|
134
|
-
family: 'blob' as const,
|
|
135
|
-
shape,
|
|
136
|
-
title: messages.characterOption('shape', shape, title),
|
|
137
|
-
})),
|
|
138
|
-
];
|
|
139
|
-
const migratedConfig = (
|
|
140
|
-
family: 'fold' | 'blob',
|
|
141
|
-
shape: string,
|
|
142
|
-
): AvatarConfig => {
|
|
143
|
-
const { character: _character, ...existing } = c;
|
|
144
|
-
const color = hexAppearance(customColorValue);
|
|
145
|
-
return {
|
|
146
|
-
...existing,
|
|
147
|
-
...color,
|
|
148
|
-
lightEyes: beta ? false : c.lightEyes,
|
|
149
|
-
family,
|
|
150
|
-
...(family === 'fold'
|
|
151
|
-
? { foldShape: shape as AvatarConfig['foldShape'] }
|
|
152
|
-
: { shape: shape as AvatarConfig['shape'] }),
|
|
153
|
-
...(runtimeUrl
|
|
154
|
-
? {
|
|
155
|
-
character: {
|
|
156
|
-
preset: 'bloom',
|
|
157
|
-
selections: {
|
|
158
|
-
eyes: selectedEyes,
|
|
159
|
-
...((capabilities?.selected.eyewear ??
|
|
160
|
-
c.character?.selections?.eyewear)
|
|
161
|
-
? {
|
|
162
|
-
eyewear:
|
|
163
|
-
capabilities?.selected.eyewear ??
|
|
164
|
-
c.character?.selections?.eyewear,
|
|
165
|
-
}
|
|
166
|
-
: {}),
|
|
167
|
-
...((capabilities?.selected.accessory ??
|
|
168
|
-
c.character?.selections?.accessory)
|
|
169
|
-
? {
|
|
170
|
-
accessory:
|
|
171
|
-
capabilities?.selected.accessory ??
|
|
172
|
-
c.character?.selections?.accessory,
|
|
173
|
-
}
|
|
174
|
-
: {}),
|
|
175
|
-
},
|
|
176
|
-
},
|
|
177
|
-
}
|
|
178
|
-
: {}),
|
|
179
|
-
};
|
|
180
|
-
};
|
|
181
152
|
const shapeChoices = runtimeUrl
|
|
182
|
-
? [
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
...
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
153
|
+
? CHARACTER_SHAPES.map(([id, title]) => ({
|
|
154
|
+
id,
|
|
155
|
+
label:
|
|
156
|
+
id in messages.shapes
|
|
157
|
+
? messages.shapes[id as keyof typeof messages.shapes]
|
|
158
|
+
: messages.characterOption('shape', id, title),
|
|
159
|
+
config: createConfigForShape(c, id, capabilities.selected),
|
|
160
|
+
...(NATIVE_CHARACTER_SHAPES.some(([shape]) => shape === id) &&
|
|
161
|
+
id !== 'clippo' &&
|
|
162
|
+
id !== 'todd'
|
|
163
|
+
? { thumbnail: `${thumbnailBase}thumbnails/shapes/${id}.png` }
|
|
164
|
+
: {}),
|
|
165
|
+
}))
|
|
195
166
|
: undefined;
|
|
196
|
-
const shapeValue =
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
onChange({
|
|
204
|
-
...agent,
|
|
205
|
-
avatar: migratedConfig(family as 'fold' | 'blob', shape!),
|
|
206
|
-
});
|
|
207
|
-
} else selectCharacter('shape', id);
|
|
208
|
-
};
|
|
167
|
+
const shapeValue =
|
|
168
|
+
c.character?.selections?.shape ??
|
|
169
|
+
(beta
|
|
170
|
+
? (capabilities.selected.shape ??
|
|
171
|
+
(c.character?.preset === 'clippo' ? 'clippo' : undefined))
|
|
172
|
+
: currentCharacterShape(c));
|
|
173
|
+
const selectShape = (id: string) => selectCharacter('shape', id);
|
|
209
174
|
const eyeChoices = runtimeUrl
|
|
210
175
|
? CHARACTER_OPTIONS.eyes.map(([id, title]) => ({
|
|
211
176
|
id,
|
|
212
177
|
label: messages.characterOption('eyes', id, title),
|
|
213
178
|
config: characterConfig('eyes', id),
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
179
|
+
...(id === 'clippo' || id === 'cyclops'
|
|
180
|
+
? { artwork: id }
|
|
181
|
+
: { thumbnail: `${thumbnailBase}thumbnails/eyes/${id}.png` }),
|
|
182
|
+
disabled: false,
|
|
217
183
|
}))
|
|
218
184
|
: undefined;
|
|
219
185
|
const appearance = (patch: Partial<AvatarConfig>) => {
|
|
@@ -367,8 +333,15 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
367
333
|
</StyledView>
|
|
368
334
|
)}
|
|
369
335
|
<CharacterControls
|
|
370
|
-
character={
|
|
336
|
+
character={
|
|
337
|
+
runtimeUrl
|
|
338
|
+
? beta
|
|
339
|
+
? c.character
|
|
340
|
+
: materializeCharacter(c, capabilities.selected)
|
|
341
|
+
: c.character
|
|
342
|
+
}
|
|
371
343
|
capabilitiesKey={key}
|
|
344
|
+
selected={capabilities.selected}
|
|
372
345
|
onChange={(character) => {
|
|
373
346
|
if (character)
|
|
374
347
|
onChange({ ...agent, avatar: { ...c, character } });
|
|
@@ -386,7 +359,7 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
386
359
|
boxShadow: '0 1px 2px rgba(0,0,0,.05)',
|
|
387
360
|
}}
|
|
388
361
|
>
|
|
389
|
-
{!
|
|
362
|
+
{!runtimeUrl &&
|
|
390
363
|
AVATAR_COLORS.map(([hue, saturation, name, center, edge]) => {
|
|
391
364
|
const active =
|
|
392
365
|
c.hue === hue &&
|
|
@@ -415,15 +388,11 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
415
388
|
</StyledPressable>
|
|
416
389
|
);
|
|
417
390
|
})}
|
|
418
|
-
{
|
|
391
|
+
{runtimeUrl &&
|
|
419
392
|
CHARACTER_OPTIONS.color.map(([id, title]) => {
|
|
420
|
-
const active =
|
|
421
|
-
!c.character?.bodyColor &&
|
|
422
|
-
capabilities?.selected.color === id;
|
|
393
|
+
const active = !betaBodyColor && betaColor === id;
|
|
423
394
|
const hex = CHARACTER_COLORS[id];
|
|
424
|
-
const disabled =
|
|
425
|
-
!capabilities ||
|
|
426
|
-
capabilities.available[`color:${id}`] === false;
|
|
395
|
+
const disabled = false;
|
|
427
396
|
return (
|
|
428
397
|
<StyledPressable
|
|
429
398
|
key={id}
|
|
@@ -446,18 +415,18 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
446
415
|
<PopoverTrigger asChild label={messages.customColor}>
|
|
447
416
|
<StyledPressable
|
|
448
417
|
aria-pressed={
|
|
449
|
-
|
|
418
|
+
runtimeUrl ? Boolean(betaBodyColor) : undefined
|
|
450
419
|
}
|
|
451
420
|
accessibilityState={{
|
|
452
|
-
selected:
|
|
421
|
+
selected: Boolean(runtimeUrl) && Boolean(betaBodyColor),
|
|
453
422
|
}}
|
|
454
423
|
className="relative size-[26px] shrink-0 overflow-hidden rounded-full"
|
|
455
424
|
>
|
|
456
425
|
<GlossArt
|
|
457
|
-
rainbow={!
|
|
458
|
-
center={
|
|
459
|
-
edge={
|
|
460
|
-
active={
|
|
426
|
+
rainbow={!runtimeUrl || !betaBodyColor}
|
|
427
|
+
center={runtimeUrl ? betaBodyColor : undefined}
|
|
428
|
+
edge={runtimeUrl ? betaBodyColor : undefined}
|
|
429
|
+
active={Boolean(runtimeUrl) && Boolean(betaBodyColor)}
|
|
461
430
|
/>
|
|
462
431
|
</StyledPressable>
|
|
463
432
|
</PopoverTrigger>
|
|
@@ -473,14 +442,14 @@ export function AgentCreatorBase(props: AgentCreatorProps) {
|
|
|
473
442
|
onChange={(hex) => {
|
|
474
443
|
const next = hexAppearance(hex);
|
|
475
444
|
if (!next) return;
|
|
476
|
-
if (
|
|
445
|
+
if (runtimeUrl)
|
|
477
446
|
onChange({
|
|
478
447
|
...agent,
|
|
479
448
|
avatar: {
|
|
480
449
|
...c,
|
|
481
450
|
...next,
|
|
482
451
|
character: {
|
|
483
|
-
...c.
|
|
452
|
+
...materializeCharacter(c, capabilities.selected),
|
|
484
453
|
bodyColor: hex.toLowerCase(),
|
|
485
454
|
},
|
|
486
455
|
},
|