Skip to content

Commit

Permalink
feat: added position controls for height and depth
Browse files Browse the repository at this point in the history
  • Loading branch information
andrepat0 committed Nov 7, 2024
1 parent 43dd930 commit c324473
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.memori--position-controls{
position: fixed;
z-index: 1000;
top: 60px;
left: 15px;
display: flex;
flex-direction: column;
gap: 0.5rem;
min-width: 400px;
height: auto !important;
text-align: left;
max-width: 400px;
padding: calc(var(--memori-inner-content-pad) / 4) calc(var(--memori-inner-content-pad) / 2);
border-radius: 10px;
margin-left: auto;
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
background-color: var(--memori-inner-bg, #fff);
}

.memori--position-controls-helper-text{
font-size: 0.875rem;
color: #3b3e46;
}

.memori--slider-container {
display: flex;
flex-direction: column;
gap: 0.5rem;
}

.memori--preset-button{
border: 1px solid #ccc;
padding: 0.5rem;
}

.memori--preset-button:hover{
background-color: #f0f0f0;
}

.memori--preset-buttons{
display: flex;
gap: 0.5rem;
}

.memori--slider-label{
font-size: 0.875rem;
color: #3b3e46;
margin: 0px;
}

.memori--position-controls-close{
position: absolute;
top: 0;
right: 0;
}

.memori--position-controls-close-button{
padding: 0.5rem;
}

.memori--position-controls-close-button:hover, .memori--position-controls-close-button:active, .memori--position-controls-close-button:focus {
border: none !important;
box-shadow: none !important;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import { useEffect, useRef } from 'react';
import { setLocalConfig } from '../../../../../helpers/configuration';
import { useTranslation } from 'react-i18next';
import Slider from '../../../../../components/ui/Slider';
import './positionControls.css';
import Button from '../../../../ui/Button';
import Close from '../../../../icons/Close';

interface PositionControlsProps {
avatarHeight: number;
avatarDepth: number;
setAvatarHeight: (value: number) => void;
setAvatarDepth: (value: number) => void;
isZoomed?: boolean;
setEnablePositionControls: (value: boolean) => void;
}

// eslint-disable-next-line no-undef
const PositionControls: React.FC<PositionControlsProps> = ({
avatarHeight,
avatarDepth,
setAvatarHeight,
setAvatarDepth,
isZoomed = false,
setEnablePositionControls,
}: PositionControlsProps) => {
const { t } = useTranslation();
const settingsRef = useRef<Record<string, any>>({
height: avatarHeight,
depth: avatarDepth,
zoomed: false,
normal: false,
far: false,
});

// Update settings when values change externally
// useEffect(() => {
// settingsRef.current.height = avatarHeight;
// settingsRef.current.depth = avatarDepth;
// }, [avatarHeight, avatarDepth]);

// Keyboard controls for depth
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === '-' || event.key === '_') {
const newValue = Math.min(settingsRef.current.depth + 10, 100);
setAvatarDepth(newValue);
setLocalConfig('avatarDepth', newValue);
} else if (event.key === '+' || event.key === '=') {
const newValue = Math.max(settingsRef.current.depth - 10, -100);
setAvatarDepth(newValue);
setLocalConfig('avatarDepth', newValue);
}
};

window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [setAvatarDepth]);

useEffect(() => {
const handleArrowUp = (event: KeyboardEvent) => {
if (event.key === 'ArrowUp') {
const newValue = settingsRef.current.height + 5;
setAvatarHeight(newValue);
setLocalConfig('avatarHeight', newValue);
}
};

const handleArrowDown = (event: KeyboardEvent) => {
if (event.key === 'ArrowDown') {
const newValue = settingsRef.current.height - 5;
setAvatarHeight(newValue);
setLocalConfig('avatarHeight', newValue);
}
};

window.addEventListener('keydown', handleArrowUp);
window.addEventListener('keydown', handleArrowDown);

return () => {
window.removeEventListener('keydown', handleArrowUp);
window.removeEventListener('keydown', handleArrowDown);
};
}, [setAvatarHeight]);

return (
<div className="memori--position-controls">
<div className="memori--position-controls-close">
<Button
ghost
icon={<Close />}
outlined
danger
shape="circle"
className="memori--position-controls-close-button"
onClick={() => {
setEnablePositionControls(false);
}}
/>
</div>
<div className="memori--position-controls-helper">
<p className="memori--position-controls-helper-text">
{t('Use the arrow keys to adjust the avatar height')}
<br />
{t('Use +/- to adjust the avatar depth')}
</p>
</div>
<div className="memori--slider-container">
<Slider
defaultValue={settingsRef.current.height}
min={0}
max={100}
label={<label className="memori--slider-label">{t('Height')}</label>}
step={1}
onChange={(value: number) => {
setAvatarHeight(value);
setLocalConfig('avatarHeight', value);
}}
/>
</div>
<div className="memori--slider-container">
<Slider
defaultValue={settingsRef.current.depth}
min={isZoomed ? -50 : -100}
max={isZoomed ? 50 : 100}
step={5}
label={<label className="memori--slider-label">{t('Depth')}</label>}
onChange={(value: number) => {
setAvatarDepth(value);
setLocalConfig('avatarDepth', value);
}}
/>
</div>
<div className="memori--preset-buttons">
<Button
outlined
// className="memori--preset-button"
onClick={() => {
const position = { height: 50, depth: -50 };
setAvatarHeight(position.height);
setAvatarDepth(position.depth);
setLocalConfig('avatarHeight', position.height);
setLocalConfig('avatarDepth', position.depth);
}}
>
{t('Zoomed')}
</Button>
<Button
outlined
// className="memori--preset-button"
onClick={() => {
const position = { height: 50, depth: 0 };
setAvatarHeight(position.height);
setAvatarDepth(position.depth);
setLocalConfig('avatarHeight', position.height);
setLocalConfig('avatarDepth', position.depth);
}}
>
{t('Normal')}
</Button>
<Button
outlined
// className="memori--preset-button"
onClick={() => {
const position = { height: 50, depth: 50 };
setAvatarHeight(position.height);
setAvatarDepth(position.depth);
setLocalConfig('avatarHeight', position.height);
setLocalConfig('avatarDepth', position.depth);
}}
>
{t('Far')}
</Button>
</div>
</div>
);
};

export default PositionControls;
30 changes: 23 additions & 7 deletions src/components/Avatar/AvatarView/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { isAndroid, isiOS } from '../../../helpers/utils';
import { AvatarView } from './AvatarComponent/avatarComponent';
import Loader from './AvatarComponent/components/loader';
import { Vector3 } from 'three';
import PositionControls from './AvatarComponent/positionControls/positionControls';
import { getLocalConfig } from '../../../helpers/configuration';
export interface Props {
url: string;
sex: 'MALE' | 'FEMALE';
Expand All @@ -28,7 +30,7 @@ export interface Props {
isZoomed?: boolean;
chatEmission?: any;
enablePositionControls?: boolean;
setEnablePositionControls?: (value: boolean) => void;
setEnablePositionControls: (value: boolean) => void;
setMeshRef?: any;
stopProcessing: () => void;
resetVisemeQueue: () => void;
Expand Down Expand Up @@ -74,6 +76,8 @@ const getLightingComponent = () =>
target: [0, 0, 0]
};
};



export default function ContainerAvatarView({
url,
Expand All @@ -98,10 +102,12 @@ const getLightingComponent = () =>
setEnablePositionControls,
}: Props) {
const [cameraZ, setCameraZ] = useState(() => getCameraSettings(halfBody).position[2]);

const [avatarHeight, setAvatarHeight] = useState(getLocalConfig('avatarHeight', 50));
const [avatarDepth, setAvatarDepth] = useState(getLocalConfig('avatarDepth', 50));
return (
<Canvas
style={style || (halfBody ? defaultStyles.halfBody : defaultStyles.fullBody)}
<>
<Canvas
style={style || defaultStyles.fullBody}
>
<PerspectiveCamera
makeDefault
Expand Down Expand Up @@ -135,11 +141,21 @@ const getLightingComponent = () =>
updateCurrentViseme={updateCurrentViseme}
stopProcessing={stopProcessing}
resetVisemeQueue={resetVisemeQueue}
enablePositionControls={enablePositionControls}
setEnablePositionControls={setEnablePositionControls}
setCameraZ={setCameraZ}
avatarHeight={avatarHeight}
avatarDepth={avatarDepth}
/>
</Suspense>
</Canvas>
</Canvas>
{enablePositionControls && (
<PositionControls
avatarHeight={avatarHeight}
avatarDepth={avatarDepth}
setAvatarHeight={setAvatarHeight}
setAvatarDepth={setAvatarDepth}
setEnablePositionControls={setEnablePositionControls}
/>
)}
</>
);
}

0 comments on commit c324473

Please sign in to comment.