diff --git a/src/frontend/public/assets/beret.png b/src/frontend/public/assets/beret.png
new file mode 100644
index 00000000..f9691793
Binary files /dev/null and b/src/frontend/public/assets/beret.png differ
diff --git a/src/frontend/src/features/rooms/livekit/components/blur/FaceLandmarksProcessor.ts b/src/frontend/src/features/rooms/livekit/components/blur/FaceLandmarksProcessor.ts
index 462ce624..ef4f51d3 100644
--- a/src/frontend/src/features/rooms/livekit/components/blur/FaceLandmarksProcessor.ts
+++ b/src/frontend/src/features/rooms/livekit/components/blur/FaceLandmarksProcessor.ts
@@ -49,7 +49,7 @@ export class FaceLandmarksProcessor implements BackgroundProcessorInterface {
// Effect images
glassesImage?: HTMLImageElement
mustacheImage?: HTMLImageElement
-
+ beretImage?: HTMLImageElement
constructor(opts: BackgroundOptions) {
this.name = 'face_landmarks'
this.options = opts
@@ -65,6 +65,10 @@ export class FaceLandmarksProcessor implements BackgroundProcessorInterface {
this.mustacheImage = new Image()
this.mustacheImage.src = '/assets/mustache.png'
this.mustacheImage.crossOrigin = 'anonymous'
+
+ this.beretImage = new Image()
+ this.beretImage.src = '/assets/beret.png'
+ this.beretImage.crossOrigin = 'anonymous'
}
static get isSupported() {
@@ -172,7 +176,8 @@ export class FaceLandmarksProcessor implements BackgroundProcessorInterface {
rightPoint: { x: number; y: number },
image: HTMLImageElement,
widthScale: number,
- heightScale: number
+ heightScale: number,
+ yOffset: number = 0
) {
// Calculate distance between points
const distance = Math.sqrt(
@@ -186,7 +191,7 @@ export class FaceLandmarksProcessor implements BackgroundProcessorInterface {
// Calculate center position between points
const centerX = (leftPoint.x + rightPoint.x) / 2
- const centerY = (leftPoint.y + rightPoint.y) / 2
+ const centerY = (leftPoint.y + rightPoint.y) / 2 + yOffset
// Draw image
this.outputCanvasCtx!.save()
@@ -237,21 +242,29 @@ export class FaceLandmarksProcessor implements BackgroundProcessorInterface {
this.outputCanvasCtx!.lineWidth = 2
for (const face of this.faceLandmarkerResult.faceLandmarks) {
- // Find eye landmarks (indices 33 and 263 are the left and right eye corners)
+ // Find eye landmarks
const leftEye = face[468]
const rightEye = face[473]
- // Find mouth landmarks for mustache (indices 0 and 17 are the left and right corners of the mouth)
+ // Find mouth landmarks for mustache
const leftMoustache = face[92]
const rightMoustache = face[322]
+ // Find forehead landmarks for beret
+ const leftForehead = face[103]
+ const rightForehead = face[332]
+
if (leftEye && rightEye && this.options.showGlasses) {
this.drawEffect(leftEye, rightEye, this.glassesImage!, 2.5, 0.7)
}
- if (leftMoustache && rightMoustache && this.options.showMustache) {
+ if (leftMoustache && rightMoustache && this.options.showFrench) {
this.drawEffect(leftMoustache, rightMoustache, this.mustacheImage!, 1.5, 0.5)
}
+
+ if (leftForehead && rightForehead && this.options.showFrench) {
+ this.drawEffect(leftForehead, rightForehead, this.beretImage!, 2.1, 0.7, -0.1)
+ }
}
}
diff --git a/src/frontend/src/features/rooms/livekit/components/blur/index.ts b/src/frontend/src/features/rooms/livekit/components/blur/index.ts
index e7f27414..0b345d4a 100644
--- a/src/frontend/src/features/rooms/livekit/components/blur/index.ts
+++ b/src/frontend/src/features/rooms/livekit/components/blur/index.ts
@@ -9,7 +9,7 @@ export type BackgroundOptions = {
blurRadius?: number
imagePath?: string
showGlasses?: boolean
- showMustache?: boolean
+ showFrench?: boolean
}
export interface ProcessorSerialized {
diff --git a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx
index 10e19722..4b9dd996 100644
--- a/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx
+++ b/src/frontend/src/features/rooms/livekit/components/effects/EffectsConfiguration.tsx
@@ -15,7 +15,7 @@ import { BlurOnStrong } from '@/components/icons/BlurOnStrong'
import { useTrackToggle } from '@livekit/components-react'
import { Loader } from '@/primitives/Loader'
import { useSyncAfterDelay } from '@/hooks/useSyncAfterDelay'
-import { RiProhibited2Line, RiGlassesLine, RiEmotionLine } from '@remixicon/react'
+import { RiProhibited2Line, RiGlassesLine, RiGoblet2Fill } from '@remixicon/react'
import { useHasFaceLandmarksAccess } from '../../hooks/useHasFaceLandmarksAccess'
enum BlurRadius {
@@ -142,7 +142,7 @@ export const EffectsConfiguration = ({
const tooltipLabel = (type: ProcessorType, options: BackgroundOptions) => {
if (type === ProcessorType.FACE_LANDMARKS) {
- const effect = options.showGlasses ? 'glasses' : 'mustache'
+ const effect = options.showGlasses ? 'glasses' : 'french'
return t(`faceLandmarks.${effect}.${isSelected(type, options) ? 'clear' : 'apply'}`)
}
return t(`${type}.${isSelected(type, options) ? 'clear' : 'apply'}`)
@@ -151,19 +151,19 @@ export const EffectsConfiguration = ({
const getFaceLandmarksOptions = () => {
const processor = getProcessor()
if (processor?.serialize().type === ProcessorType.FACE_LANDMARKS) {
- return processor.serialize().options as { showGlasses?: boolean; showMustache?: boolean }
+ return processor.serialize().options as { showGlasses?: boolean; showFrench?: boolean }
}
- return { showGlasses: false, showMustache: false }
+ return { showGlasses: false, showFrench: false }
}
- const toggleFaceLandmarkEffect = async (effect: 'glasses' | 'mustache') => {
+ const toggleFaceLandmarkEffect = async (effect: 'glasses' | 'french') => {
const currentOptions = getFaceLandmarksOptions()
const newOptions = {
...currentOptions,
- [effect === 'glasses' ? 'showGlasses' : 'showMustache']: !currentOptions[effect === 'glasses' ? 'showGlasses' : 'showMustache']
+ [effect === 'glasses' ? 'showGlasses' : 'showFrench']: !currentOptions[effect === 'glasses' ? 'showGlasses' : 'showFrench']
}
- if (!newOptions.showGlasses && !newOptions.showMustache) {
+ if (!newOptions.showGlasses && !newOptions.showFrench) {
// If both effects are off stop the processor
await clearEffect()
} else {
@@ -356,11 +356,11 @@ export const EffectsConfiguration = ({
variant="bigSquare"
aria-label={tooltipLabel(ProcessorType.FACE_LANDMARKS, {
showGlasses: true,
- showMustache: false,
+ showFrench: false,
})}
tooltip={tooltipLabel(ProcessorType.FACE_LANDMARKS, {
showGlasses: true,
- showMustache: false,
+ showFrench: false,
})}
isDisabled={processorPendingReveal}
onChange={async () => await toggleFaceLandmarkEffect('glasses')}
@@ -373,18 +373,18 @@ export const EffectsConfiguration = ({
variant="bigSquare"
aria-label={tooltipLabel(ProcessorType.FACE_LANDMARKS, {
showGlasses: false,
- showMustache: true,
+ showFrench: true,
})}
tooltip={tooltipLabel(ProcessorType.FACE_LANDMARKS, {
showGlasses: false,
- showMustache: true,
+ showFrench: true,
})}
isDisabled={processorPendingReveal}
- onChange={async () => await toggleFaceLandmarkEffect('mustache')}
- isSelected={getFaceLandmarksOptions().showMustache}
- data-attr="toggle-mustache"
+ onChange={async () => await toggleFaceLandmarkEffect('french')}
+ isSelected={getFaceLandmarksOptions().showFrench}
+ data-attr="toggle-french"
>
-
+
diff --git a/src/frontend/src/locales/de/rooms.json b/src/frontend/src/locales/de/rooms.json
index 2a672fd7..38aa76f0 100644
--- a/src/frontend/src/locales/de/rooms.json
+++ b/src/frontend/src/locales/de/rooms.json
@@ -156,9 +156,9 @@
"apply": "Brille hinzufügen",
"clear": "Brille entfernen"
},
- "mustache": {
- "apply": "Schnurrbart hinzufügen",
- "clear": "Schnurrbart entfernen"
+ "french": {
+ "apply": "Französische Touch hinzufügen",
+ "clear": "Französische Touch entfernen"
}
},
"experimental": "Experimentelle Funktion. Eine v2 kommt für vollständige Browserunterstützung und verbesserte Qualität."
diff --git a/src/frontend/src/locales/en/rooms.json b/src/frontend/src/locales/en/rooms.json
index 23fc147d..ca125a14 100644
--- a/src/frontend/src/locales/en/rooms.json
+++ b/src/frontend/src/locales/en/rooms.json
@@ -155,9 +155,9 @@
"apply": "Add Glasses",
"clear": "Remove Glasses"
},
- "mustache": {
- "apply": "Add Mustache",
- "clear": "Remove Mustache"
+ "french": {
+ "apply": "Add French touch",
+ "clear": "Remove French touch"
}
},
"experimental": "Experimental feature. A v2 is coming for full browser support and improved quality."
diff --git a/src/frontend/src/locales/fr/rooms.json b/src/frontend/src/locales/fr/rooms.json
index 0508179c..2ac71f08 100644
--- a/src/frontend/src/locales/fr/rooms.json
+++ b/src/frontend/src/locales/fr/rooms.json
@@ -155,9 +155,9 @@
"apply": "Ajouter des lunettes",
"clear": "Retirer les lunettes"
},
- "mustache": {
- "apply": "Ajouter une moustache",
- "clear": "Retirer la moustache"
+ "french": {
+ "apply": "Ajouter la touche française",
+ "clear": "Retirer la touche française"
}
},
"experimental": "Fonctionnalité expérimentale. Une v2 arrive pour un support complet des navigateurs et une meilleure qualité."
diff --git a/src/frontend/src/locales/nl/rooms.json b/src/frontend/src/locales/nl/rooms.json
index da56ae02..7f38350a 100644
--- a/src/frontend/src/locales/nl/rooms.json
+++ b/src/frontend/src/locales/nl/rooms.json
@@ -155,9 +155,9 @@
"apply": "Bril toevoegen",
"clear": "Bril verwijderen"
},
- "mustache": {
- "apply": "Snor toevoegen",
- "clear": "Snor verwijderen"
+ "french": {
+ "apply": "Franse stijl toevoegen",
+ "clear": "Franse stijl verwijderen"
}
},
"experimental": "Experimentele functie. Een v2 komt eraan voor volledige browserondersteuning en verbeterde kwaliteit."