diff --git a/app/src/main/java/io/github/stozo04/openloop/camera/CameraManager.kt b/app/src/main/java/io/github/stozo04/openloop/camera/CameraManager.kt index fd2b63e..384d43d 100644 --- a/app/src/main/java/io/github/stozo04/openloop/camera/CameraManager.kt +++ b/app/src/main/java/io/github/stozo04/openloop/camera/CameraManager.kt @@ -159,13 +159,9 @@ class CameraManager(private val context: Context) { analysis = analysis, ) attachZoomObserver() - // The build marker suffix is the stale-APK tripwire (Lesson 012's environment - // notes): a logcat whose bind lines lack it was made by a build without the - // flick feature, whatever the checkout says. Log.i( TAG, - "Camera bound (lens=${if (lensFacing == CameraSelector.LENS_FACING_BACK) "back" else "front"}) " + - "build=hand-flick-v1" + "Camera bound (lens=${if (lensFacing == CameraSelector.LENS_FACING_BACK) "back" else "front"})" ) onCameraReady() diff --git a/app/src/main/java/io/github/stozo04/openloop/camera/lens/FaceRoster.kt b/app/src/main/java/io/github/stozo04/openloop/camera/lens/FaceRoster.kt index b5d1903..e699440 100644 --- a/app/src/main/java/io/github/stozo04/openloop/camera/lens/FaceRoster.kt +++ b/app/src/main/java/io/github/stozo04/openloop/camera/lens/FaceRoster.kt @@ -29,19 +29,10 @@ import kotlin.math.hypot * * ## ID churn * - * When ML Kit loses a face for a frame or two it often re-detects it under a **new** tracking id. - * The old id is still being held, so without care the same person would wear two lenses for up to - * [holdMs] — and, with the slots full, the new id would be locked out until the hold expired. So - * the nearest fresh face that has no slot and stands within [SAME_FACE_RADIUS_UNITS] of a - * held-but-unseen slot holder is taken to be that person. A different person cannot land on the - * exact same spot inside a third of a second, and a third person entering anywhere else during - * someone's blink still cannot steal a slot. - * - * The adopted face is **published under the original id**, not the detector's new one (Lesson - * 037). Every per-face consumer downstream — the wobble springs and eased mouth in [LensMotion], - * anything added later — keys its state on [FaceSnapshot.trackingId], so a label change that - * leaked through would reset all of it mid-blink. The new id is recorded as an alias and folded - * back onto the original on every later sighting, for as long as that person is held. + * ML Kit often re-detects a briefly lost face under a new tracking id. The roster adopts the + * nearest fresh face within [SAME_FACE_RADIUS_UNITS] of a held-but-unseen slot as the same person, + * publishing it under the original id (Lesson 037) so downstream per-face state keyed on + * [FaceSnapshot.trackingId] is not reset mid-blink. */ class FaceRoster(private val maxFaces: Int, private val holdMs: Long) { diff --git a/app/src/main/java/io/github/stozo04/openloop/camera/lens/Lens.kt b/app/src/main/java/io/github/stozo04/openloop/camera/lens/Lens.kt index 173d47f..36b5af6 100644 --- a/app/src/main/java/io/github/stozo04/openloop/camera/lens/Lens.kt +++ b/app/src/main/java/io/github/stozo04/openloop/camera/lens/Lens.kt @@ -34,27 +34,9 @@ import io.github.stozo04.openloop.R * | eye line down to the **chin** | **1.75** | * | mouth width, at rest | 0.8 | * - * These are **measured off a real tracked face**, not assumed. An earlier version reasoned them - * from published head statistics (treating one unit as the interpupillary distance) and every lens - * came out ~20% oversized — eye-to-mouth is the larger of the two spans. If a lens ever needs + * These are **measured off a real tracked face**, not assumed. If a lens ever needs * resizing, re-measure against this table rather than nudging a lens in isolation. * - * ## The chin row was wrong until 2026-08-16, and it shipped two bugs - * - * This table used to say **chin = 1.00** — which is the same number as the mouth, and that - * coincidence is the tell: the row was the *mouth* wearing the chin's label. A real jaw runs about - * another **0.75 units** below the mouth (stomion→menton ≈ 50 mm against a ≈ 67 mm pupil→stomion - * face unit), putting the chin at **-1.75**. - * - * [PizzaFace] and [Football] were both sized against the wrong number, so both stopped at roughly - * the mouth and left the subject's real chin — and the corners of their real mouth — on show below - * the art. That is what "the mouth looks duplicated" was: the character's composited mouth *and* - * the subject's own, at once. [Broccoli] was never affected because it hangs a stalk far below the - * jaw and covers to -3.88 regardless. - * - * `LensAnchorTest.characterLensesCoverTheWholeHead` now asserts crown-to-chin coverage for every - * character lens, so the class of bug cannot come back silently. - * * Because they are ratios of the face to itself, one set of numbers holds for every face at every * distance and angle — there is nothing here to re-tune per device. */ diff --git a/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensAnchor.kt b/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensAnchor.kt index a8d4788..63e3122 100644 --- a/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensAnchor.kt +++ b/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensAnchor.kt @@ -410,12 +410,8 @@ object LensAnchor { } /** - * Resolves the three features to lift onto a character: left eye, right eye, mouth. - * - * Sources follow the subject's real landmarks (so a blink, a smile and a head turn all carry - * through); destinations are fixed points in the face frame (so the character's face does not - * inherit the subject's proportions, camera perspective, or a lens-distorted nose). That split - * is the whole trick — expression from the human, geometry from the character. + * Resolves the three features to lift onto a character. Expression from the human (real + * landmarks), geometry from the character (fixed points in the face frame). */ fun features( face: FaceSnapshot, diff --git a/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensSurfaceProcessor.kt b/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensSurfaceProcessor.kt index ac63270..f3496d8 100644 --- a/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensSurfaceProcessor.kt +++ b/app/src/main/java/io/github/stozo04/openloop/camera/lens/LensSurfaceProcessor.kt @@ -783,12 +783,6 @@ class LensSurfaceProcessor(context: Context) : SurfaceProcessor { /** * Camera pass — a straight sample of the external OES texture through CameraX's transform. - * - * This used to carry up to two radial bulges (Big Mouth, Bug Eyes). Both lenses are gone, - * and with them the flip into y-down screen space they needed: the shader converted - * `vTexCoord`, warped, and converted back, which is exactly the identity when no warp - * fires. A lens that deforms pixels again wants that scaffolding back — it is in the - * history, not commented out here. */ const val CAMERA_FRAGMENT_SHADER = """ #extension GL_OES_EGL_image_external : require