@@ -40,6 +40,13 @@ const mouthArea = [
4040 { x : 0 , y : 100 } ,
4141] ;
4242
43+ const noseArea = [
44+ { x : 20 , y : 65 } ,
45+ { x : 50 , y : 25 } ,
46+ { x : 51 , y : 25 } ,
47+ { x : 80 , y : 65 } ,
48+ ] ;
49+
4350export interface FacePaths {
4451 leftEye : string ;
4552 rightEye : string ;
@@ -64,7 +71,6 @@ export function RandomfaceSVG(sha256hash: string): RandomfaceSVGData {
6471 }
6572
6673 const leftEyePoints = new Array < Point > ( ) ;
67- const rightEyePoints = new Array < Point > ( ) ;
6874 const nosePoints = new Array < Point > ( ) ;
6975 const mouthPoints = new Array < Point > ( ) ;
7076
@@ -74,25 +80,30 @@ export function RandomfaceSVG(sha256hash: string): RandomfaceSVGData {
7480 points . forEach ( ( point ) => {
7581 if ( pointInPolygon ( point , leftEyeArea ) ) {
7682 leftEyePoints . push ( point ) ;
77- } else if ( pointInPolygon ( point , rightEyeArea ) ) {
78- rightEyePoints . push ( point ) ;
7983 } else if ( pointInPolygon ( point , mouthArea ) ) {
8084 mouthPoints . push ( point ) ;
81- } else {
85+ } else if ( ! pointInPolygon ( point , rightEyeArea ) ) {
86+ // Only add to nose if not in right eye area (we're ignoring right eye points)
8287 nosePoints . push ( point ) ;
8388 }
8489 } ) ;
8590
86- const leftEyePath = sortPointsAndBuildPath ( leftEyePoints ) ;
87- const righEyePath = sortPointsAndBuildPath ( rightEyePoints ) ;
88- const nosePath = sortPointsAndBuildPath ( nosePoints ) ;
89- const mouthPath = sortPointsAndBuildPath ( mouthPoints ) ;
91+ // Mirror left eye points to create right eye
92+ const rightEyePoints = leftEyePoints . map ( ( point ) => ( {
93+ x : 100 - point . x ,
94+ y : point . y ,
95+ } ) ) ;
96+
97+ const leftEyePath = buildPathWithCross ( leftEyePoints , leftEyeArea ) ;
98+ const rightEyePath = buildPathWithCross ( rightEyePoints , rightEyeArea ) ;
99+ const nosePath = buildPathWithCross ( nosePoints , noseArea ) ;
100+ const mouthPath = buildPathWithCross ( mouthPoints , mouthArea ) ;
90101
91102 return {
92- svg : `<svg viewBox='0 0 100 100' fill='currentColor' stroke-linejoin='round' stroke-linecap='round' stroke-width='2' preserveAspectRatio='xMinYMin meet' fill-rule='evenodd' clip-rule='evenodd'><path d='${ leftEyePath } '></path><path d='${ righEyePath } '></path><path d='${ nosePath } '></path><path d='${ mouthPath } '></path></svg>` ,
103+ svg : `<svg viewBox='0 0 100 100' fill='currentColor' stroke-linejoin='round' stroke-linecap='round' stroke-width='2' preserveAspectRatio='xMinYMin meet' fill-rule='evenodd' clip-rule='evenodd'><path d='${ leftEyePath } '></path><path d='${ rightEyePath } '></path><path d='${ nosePath } '></path><path d='${ mouthPath } '></path></svg>` ,
93104 paths : {
94105 leftEye : leftEyePath ,
95- rightEye : righEyePath ,
106+ rightEye : rightEyePath ,
96107 nose : nosePath ,
97108 mouth : mouthPath ,
98109 } ,
@@ -107,3 +118,29 @@ function sortPointsAndBuildPath(points: Point[]) {
107118 0.2
108119 ) ;
109120}
121+
122+ function buildPathWithCross ( points : Point [ ] , area : Point [ ] ) : string {
123+ if ( points . length === 0 ) {
124+ // No points - put cross in center of area
125+ const center = polygonCenter ( area ) ;
126+ return crossPath ( center . x , center . y ) ;
127+ }
128+ if ( points . length === 1 ) {
129+ // One point - put cross at that point
130+ return crossPath ( points [ 0 ] . x , points [ 0 ] . y ) ;
131+ }
132+ return sortPointsAndBuildPath ( points ) ;
133+ }
134+
135+ function polygonCenter ( polygon : Point [ ] ) : Point {
136+ const sum = polygon . reduce (
137+ ( acc , p ) => ( { x : acc . x + p . x , y : acc . y + p . y } ) ,
138+ { x : 0 , y : 0 }
139+ ) ;
140+ return { x : sum . x / polygon . length , y : sum . y / polygon . length } ;
141+ }
142+
143+ function crossPath ( cx : number , cy : number , size = 5 ) : string {
144+ // Draw an X cross centered at (cx, cy)
145+ return `M ${ cx - size } ${ cy - size } L ${ cx + size } ${ cy + size } M ${ cx + size } ${ cy - size } L ${ cx - size } ${ cy + size } ` ;
146+ }
0 commit comments