{"_id":"@ai-presence/face","_rev":"7-5343743373a3309eab1ad729b28d7bd5","name":"@ai-presence/face","dist-tags":{"latest":"0.1.6"},"versions":{"0.1.0":{"name":"@ai-presence/face","version":"0.1.0","license":"MIT","_id":"@ai-presence/face@0.1.0","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"fb200fb21cce00db25652bfb3b231d3f5e3caca3","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.0.tgz","fileCount":5,"integrity":"sha512-JyYGqvvHPjvdtb+xuhA4mT3f6dNXRzs0NCffIjAR3IMSW8gNE+KoIgYBVENpL2cqFTYlvnqcFUp2bcsBB/KIww==","signatures":[{"sig":"MEUCIQDI5N3CgFUh+3IqO1VK3o1ja+qhrPzLjQPH71qmlO6HYgIgNy70sn2WEPRrhVVM8CfyUzSOz37zgN2LfEsASaAiIWo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"a9dbe4abd880634e4323fbf7bcbebd374d7f13f9","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.0"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.0_1781445990374_0.29945080477755415","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@ai-presence/face","version":"0.1.1","license":"MIT","_id":"@ai-presence/face@0.1.1","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"1a801a9f9b57927daf405cd7aec036fa35874e76","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.1.tgz","fileCount":5,"integrity":"sha512-+obw5hF9IqsJnplm+BgzPSSWDYrhksYygC99nK4VXBCwodQoEhvIdVebGur9ynykg9gddq0Nqwo1pePzKg7KdA==","signatures":[{"sig":"MEYCIQCNWx1xcQFbPFWNgwu31aD+kpmyLe3eprR+zaqqYh69DAIhAJSYN+1mUqoBVnXllySB31zH2G/LhW1J9LXc3yq5BWGU","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"f9eb05107edba0379a016ea5a4a3a00ab09010d0","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.1"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.1_1781454387747_0.8243993881067713","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@ai-presence/face","version":"0.1.2","license":"MIT","_id":"@ai-presence/face@0.1.2","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"416f7d033b4d3b23cf3b8db12716341be2eba57e","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.2.tgz","fileCount":5,"integrity":"sha512-WZrZAJrClvEv7Z07qxa3OhOswnKwztZQQHtQLY9fwdTYrcJv+hJi+vfs52OjBXruSLJqW/crC0pIAwDcGoIRMA==","signatures":[{"sig":"MEQCIB48vzgiDLtfjRABx2zavaY9I0GxKFP2bRIXEsJC07YFAiAEv561UTISbUqEqhXM/KEadku7iON48Og2tEuJ88TPSQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"efc06ceb83fb4599b7db9de849272a1b58adeb37","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.2"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.2_1781499299037_0.8765401324646949","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@ai-presence/face","version":"0.1.3","license":"MIT","_id":"@ai-presence/face@0.1.3","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"e12441dda2e01abc62db39a93cef569795bc60ae","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.3.tgz","fileCount":5,"integrity":"sha512-mVM5tJShEfcMoqt+a0y4pHmaHGYxADrZaH7YmfXztp19hkM3ztM4k/r2lmttQ+p+QbSI9HMvOAQtGTwhihr4lQ==","signatures":[{"sig":"MEYCIQDdHyxzGeSbOqvhoFdSKI8p6iV6rVs2A4vfNd2D+jc40QIhAN81mOo37ykIyxoZ/j2YokDX73LgdiLpHzeyu+rA5+Hs","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"ba4c3bffd6cbc80de77651a712744974e3bdd287","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.3"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.3_1781503727887_0.9973974162828159","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@ai-presence/face","version":"0.1.4","license":"MIT","_id":"@ai-presence/face@0.1.4","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"aaedf2e96beac15122ee0b1a84f290706cf8dbca","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.4.tgz","fileCount":5,"integrity":"sha512-DwzXOiaBaa9oiQfralJxaJ2SE1+unELLPFworoJK6uZ0B5mgiy/vO1oByM+6gItDzAGfJJIAaX72lMS6M8hILg==","signatures":[{"sig":"MEUCIAYrcldfaDAAIKS7HEz3CPhAE9FLk9tGSaW1jhij4RuuAiEAyCE+DlwE3m9+nLFY+KgOJjw4np45ixe9j2i111AwsEA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"433bd413af48a4c502ed451959425384e8b4c747","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.4"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.4_1781505769446_0.823785414593688","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@ai-presence/face","version":"0.1.5","license":"MIT","_id":"@ai-presence/face@0.1.5","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"dist":{"shasum":"78304800331b27532890c80aa791f878ef1c9de9","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.5.tgz","fileCount":5,"integrity":"sha512-8mdsoTami9tdS6r/bHaFDjlI2VNS1YDGNl2YUc3K6JuAkWqI1bdS9lDBHpl61M3/go9m4ZEHUSsIXVsO+YF1XA==","signatures":[{"sig":"MEUCIQClzCdYslmWqxq63O907yLoDWMK2eU6q1PKnojibXLSFQIgC/jpG7o6k4Tg0XwxvGjG6PlgxvC4gof5Owrf+TmI6qs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":87765},"main":"./src/presence-face.js","type":"commonjs","types":"./src/presence-face.d.ts","module":"./dist/index.mjs","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","default":"./src/presence-face.js","require":"./src/presence-face.js"}},"gitHead":"76bb308641f37aedd73be1cb63ae84b1e49d3fbc","_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"_npmVersion":"10.2.4","description":"SVG reference face renderer with parallel presence controllers.","directories":{},"sideEffects":false,"_nodeVersion":"20.11.1","dependencies":{"@ai-presence/core":"0.1.5"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/face_0.1.5_1781738734832_0.865249530977205","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@ai-presence/face","version":"0.1.6","description":"SVG reference face renderer with parallel presence controllers.","type":"commonjs","main":"./src/presence-face.js","module":"./dist/index.mjs","types":"./src/presence-face.d.ts","exports":{".":{"types":"./src/presence-face.d.ts","import":"./dist/index.mjs","require":"./src/presence-face.js","default":"./src/presence-face.js"}},"dependencies":{"@ai-presence/core":"0.1.6"},"sideEffects":false,"license":"MIT","_id":"@ai-presence/face@0.1.6","gitHead":"f116b9f6144aaeb1cb04b592f63d45445e4801e0","_nodeVersion":"20.11.1","_npmVersion":"10.2.4","dist":{"integrity":"sha512-e7Qa+LtdtiiVlAQcwWyVwJ7XpVrgBrf+VDw+tbPTTfPofqEoRti9QwaMO8O9BzeiAX8kTS3LtO8BNdc41BP+zA==","shasum":"3f41ca2898b2908977d6d90d3be12cacd7e44847","tarball":"https://registry.npmjs.org/@ai-presence/face/-/face-0.1.6.tgz","fileCount":5,"unpackedSize":87765,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQD/igio7emh1OkLbhkCkHiMZKrH/cYDqEsrnS5nGV2hbgIgC5dM3TL+PZNiIiXWDP2qsyc4LafufZtgnGkv1FJLZn0="}]},"_npmUser":{"name":"_branavan_","email":"branavan.selva@gmail.com"},"directories":{},"maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/face_0.1.6_1781741608443_0.24209574409884982"},"_hasShrinkwrap":false}},"time":{"created":"2026-06-14T14:06:30.199Z","modified":"2026-06-18T00:13:28.752Z","0.1.0":"2026-06-14T14:06:30.516Z","0.1.1":"2026-06-14T16:26:27.911Z","0.1.2":"2026-06-15T04:54:59.176Z","0.1.3":"2026-06-15T06:08:48.015Z","0.1.4":"2026-06-15T06:42:49.597Z","0.1.5":"2026-06-17T23:25:34.962Z","0.1.6":"2026-06-18T00:13:28.589Z"},"license":"MIT","description":"SVG reference face renderer with parallel presence controllers.","maintainers":[{"name":"_branavan_","email":"branavan.selva@gmail.com"}],"readme":"# @ai-presence/face\n\nReference face renderer primitives for AI Presence Kit.\n\nThis package maps canonical presence snapshots from `@ai-presence/core` to renderer-specific face controls. The expression mapper remains available, and the additive controller APIs turn the same interaction-posture snapshot into parallel micro-decisions and deterministic per-frame micro-movement for gaze, blink, brows, mouth, posture, and motion.\n\n```js\nimport { faceExpressionForPresence } from \"@ai-presence/face\";\n\nconst expression = faceExpressionForPresence(snapshot);\n```\n\n```js\nimport { faceControllerDecisionsForPresence, faceControlsForPresence } from \"@ai-presence/face\";\n\nconst controls = faceControlsForPresence(snapshot, { trace });\nconst report = faceControllerDecisionsForPresence(snapshot, { trace });\n\nrenderer.setGaze(controls.gaze);\nrenderer.setMouth(controls.mouth);\n\nconsole.log(report.decisions.gaze.controller); // \"gaze-controller\"\n```\n\n```js\nimport {\n  faceControllerCoherenceForFrame,\n  faceControllerDecisionTraceForFrame,\n  faceControllerFrameForPresence,\n} from \"@ai-presence/face\";\n\nconst frameReport = faceControllerFrameForPresence(snapshot, {\n  trace,\n  timeMs: performance.now(),\n  motionScale: matchMedia(\"(prefers-reduced-motion: reduce)\").matches ? 0 : 1,\n});\nconst decisionTrace = faceControllerDecisionTraceForFrame(frameReport);\n\nrenderer.setGaze(frameReport.frame.gaze);\nrenderer.setBlink(frameReport.frame.blink);\nrenderer.setPosture(frameReport.frame.posture);\n\nconsole.log(frameReport.coherence.rendererSafe); // true\nconsole.log(faceControllerCoherenceForFrame(frameReport).channels); // [\"gaze\", \"blink\", \"brows\", \"mouth\", \"posture\", \"motion\"]\nconsole.log(decisionTrace.decisions.gaze.control.target); // \"response-origin\"\nconsole.log(decisionTrace.transitionContext);\n// { previousState: \"ready\", transitionEvent: \"submit\", transitionAgeMs: 80 }\n```\n\n```js\nimport { renderPresenceFaceSvg } from \"@ai-presence/face\";\n\nconst result = renderPresenceFaceSvg(snapshot, {\n  trace,\n  timeMs: performance.now(),\n  motionScale: 0,\n});\n\ncontainer.innerHTML = result.svg;\nconsole.log(result.channelEvidence.mouth.frame.shape);\nconsole.log(result.attributes.motionScale); // \"0\"\nconsole.log(result.decisionTrace.decisionCount); // 6\nconsole.log(result.attributes.decisionTrace); // \"complete\"\n```\n\nThe controller does not claim hidden internal state. It stays grounded in observable states such as `reading`, `thinking`, `waiting`, `streaming`, `speaking`, `interrupted`, and `ready`, then lets each facial subsystem make a small local decision from the shared snapshot and optional trace/history.\n\n`faceControlsForPresence` remains the renderer-friendly compatibility surface. `faceControllerDecisionsForPresence` exposes the same composition as an inspection report:\n\n```js\n{\n  state: \"waiting\",\n  expression: \"listening\",\n  sharedInputs: {\n    state: \"waiting\",\n    attentionTarget: \"response\",\n    latencyPhase: \"before-output\"\n  },\n  decisions: {\n    gaze: { channel: \"gaze\", controller: \"gaze-controller\", reads: [\"state\", \"attentionTarget\", \"transitionEvent\", \"...\"], control: {} },\n    blink: { channel: \"blink\", controller: \"blink-controller\", reads: [\"state\", \"...\"], control: {} },\n    brows: { channel: \"brows\", controller: \"brows-controller\", reads: [\"state\", \"transitionEvent\", \"transitionAgeMs\", \"...\"], control: {} },\n    mouth: { channel: \"mouth\", controller: \"mouth-controller\", reads: [\"state\", \"speechActivity\", \"transitionEvent\", \"...\"], control: {} },\n    posture: { channel: \"posture\", controller: \"posture-controller\", reads: [\"state\", \"energy\", \"transitionEvent\", \"...\"], control: {} },\n    motion: { channel: \"motion\", controller: \"motion-controller\", reads: [\"state\", \"anticipation\", \"...\"], control: {} }\n  }\n}\n```\n\n`faceControllerFrameForPresence` returns the same report fields plus a frozen `frame` object and frozen `coherence` audit. The frame keeps controller decisions stable and adds bounded temporal values such as blink `phase`, mouth `beat`, posture `breath`, and motion offsets so renderers can animate interaction posture without adding their own timing policy.\n\n`faceControllerDecisionTraceForFrame(frameReport)` turns a frame report into bounded per-channel controller evidence. It keeps all six channels inspectable as local decisions before the composed frame is consumed by a renderer:\n\n```js\n{\n  channels: [\"gaze\", \"blink\", \"brows\", \"mouth\", \"posture\", \"motion\"],\n  transitionContext: {\n    previousState: \"ready\",\n    transitionEvent: \"submit\",\n    transitionAgeMs: 80\n  },\n  decisionCount: 6,\n  complete: true,\n  rendererSafe: true,\n  warningCount: 0,\n  decisions: {\n    gaze: {\n      channel: \"gaze\",\n      controller: \"gaze-controller\",\n      reads: [\"state\", \"detail.question\", \"attentionTarget\", \"transitionEvent\", \"...\"],\n      control: { target: \"response-origin\", x: -0.08, y: -0.04, focus: 0.66 },\n      frame: { target: \"response-origin\", x: -0.079, y: -0.044, focus: 0.66, driftX: 0.007, driftY: -0.032 },\n      present: true,\n      bounded: true,\n      rendererSafe: true,\n      warningCount: 0,\n      warnings: []\n    }\n  }\n}\n```\n\nUse the decision trace for debug UIs, tests, logs, and adapter smoke output that need to show which controller read which runtime fields without parsing full internal control objects or core trace history. `transitionContext` is renderer-owned evidence that a fresh `submit`, `stream-open`, `token`, or `interrupt` cue was available to micro-controllers such as gaze, blink, brows, mouth, posture, and motion. It is evidence for observable interaction posture, not a claim about hidden user or model state.\n\nThe coherence audit proves the six independently decided channels compose into one renderer-consumable frame:\n\n```js\n{\n  channels: [\"gaze\", \"blink\", \"brows\", \"mouth\", \"posture\", \"motion\"],\n  complete: true,\n  bounded: true,\n  rendererSafe: true,\n  summary: {\n    channelCount: 6,\n    presentChannelCount: 6,\n    boundedChannelCount: 6,\n    gazeTarget: \"response-origin\",\n    gazeFocus: 0.66,\n    blinkOpenness: 0.9,\n    mouthShape: \"preparing\",\n    mouthActivity: 0.16,\n    postureLean: 0.24,\n    motionEnergy: 0.46,\n    motionRecovery: 0\n  },\n  channelReports: {\n    gaze: { channel: \"gaze\", present: true, bounded: true, summary: {}, warnings: [] },\n    blink: { channel: \"blink\", present: true, bounded: true, summary: {}, warnings: [] },\n    brows: { channel: \"brows\", present: true, bounded: true, summary: {}, warnings: [] },\n    mouth: { channel: \"mouth\", present: true, bounded: true, summary: {}, warnings: [] },\n    posture: { channel: \"posture\", present: true, bounded: true, summary: {}, warnings: [] },\n    motion: { channel: \"motion\", present: true, bounded: true, summary: {}, warnings: [] }\n  },\n  warnings: []\n}\n```\n\nUse `faceControllerCoherenceForFrame(frameReport)` when auditing a saved or externally assembled report. Missing channels, mismatched controller metadata, invalid targets/shapes, and out-of-range numeric values make `rendererSafe` false and appear in `warnings`.\n\nPass `motionScale` when a downstream renderer needs reduced motion. `motionScale: 1` is the default live temporal behavior, `motionScale: 0` produces deterministic still frames across different `timeMs` values for the same snapshot/options, and values between `0` and `1` reduce temporal blink closure, drift, mouth beat, breath, anticipation/recovery kicks, motion transition offsets, and continuous motion offsets. The gaze, brows, mouth, and posture transition responses are static controller decisions from `transitionEvent` and `transitionAgeMs`; they do not read frame time, so reduced-motion frames remain deterministic while still exposing the current interaction-posture cue. The option does not remove the six controller channels or their evidence; gaze target, blink baseline, brows, mouth shape, posture, and motion decisions remain available for custom renderers.\n\n`renderPresenceFaceSvg` is the no-DOM reference SVG surface. It calls `faceControllerFrameForPresence`, derives `faceControllerDecisionTraceForFrame` from that same frame report, returns a compact SVG string, and includes state, expression, frame data, six-channel evidence, and renderer-owned decision-trace evidence so downstream AI interfaces can inspect what drove the rendered posture without copying the browser demo internals. The SVG root mirrors the compact proof as `data-face-decision-trace*` attributes, includes `data-face-latency-phase` when shared control inputs provide it, and mirrors fresh transition evidence through `data-face-previous-state`, `data-face-transition-event`, and `data-face-transition-age-ms`.\n","readmeFilename":"README.md"}