face: her postures reach the rig, and she stops miming on startup
`posture()` called window.live2dMotion, which does not exist — measured undefined on the device. Nine states advertised to her in the prompt and wired to nothing. The bundle exposes two levers: #live_talk, a motion slot it reads every frame, and its own head/body hit test. The nine collapse onto those rather than pretending: speaking talks, idle rests, and the rest are a look — head for attention, body for effort. #live_talk starts at "0". "1" means start a talk motion, so she came up mouthing words with no voice behind them. The gaze socket used onConnectedChanged; Quickshell's Socket emits onConnectionStateChanged, so the subscribe was never sent — a handler for a signal that does not exist.
This commit is contained in:
parent
e218601199
commit
47e8135cdc
2 changed files with 56 additions and 4 deletions
|
|
@ -41,8 +41,14 @@
|
||||||
draws nothing at all. That is exactly the "canvas is there and nothing
|
draws nothing at all. That is exactly the "canvas is there and nothing
|
||||||
draws" TASK-59 predicted would cost an afternoon, and it did (2026-08-06).
|
draws" TASK-59 predicted would cost an afternoon, and it did (2026-08-06).
|
||||||
The runtime writes to this too, so it must be a real input, not a constant.
|
The runtime writes to this too, so it must be a real input, not a constant.
|
||||||
|
|
||||||
|
Starts at "0", not the reference's "1". "1" means *start a talk motion*, so
|
||||||
|
she came up mouthing words with no voice behind them — Casey, 2026-08-07:
|
||||||
|
"she is making mouth motions like she's saying something but nothing is
|
||||||
|
saying." "0" resets to idle and the runtime writes back "3" itself. Talking
|
||||||
|
is something the shell asks for when there is something to say.
|
||||||
-->
|
-->
|
||||||
<input type="hidden" id="live_talk" value="1">
|
<input type="hidden" id="live_talk" value="0">
|
||||||
<script src="live2d/js/live2d.js"></script>
|
<script src="live2d/js/live2d.js"></script>
|
||||||
<script>
|
<script>
|
||||||
// The character layer, reduced to what the shell drives. The reference's
|
// The character layer, reduced to what the shell drives. The reference's
|
||||||
|
|
@ -103,8 +109,42 @@
|
||||||
clear: function () { bubble.classList.remove('up'); },
|
clear: function () { bubble.classList.remove('up'); },
|
||||||
// Posture from the shell. The rig's own motion groups are named by the
|
// Posture from the shell. The rig's own motion groups are named by the
|
||||||
// reference (idle, tap); anything richer waits on her own rig.
|
// reference (idle, tap); anything richer waits on her own rig.
|
||||||
|
// Posture, driven through the levers the runtime actually has.
|
||||||
|
//
|
||||||
|
// This called `window.live2dMotion`, which **does not exist** — measured
|
||||||
|
// undefined on the device. So every posture tag she emitted was a no-op:
|
||||||
|
// nine states advertised to her in the prompt and wired to nothing.
|
||||||
|
//
|
||||||
|
// What the bundle really exposes is two things. `#live_talk` is a motion
|
||||||
|
// state slot it reads every frame ("1" talk, "0" reset to idle), and its
|
||||||
|
// own touch handler hit-tests head vs body and answers with an expression
|
||||||
|
// or a tap motion. Both are reachable from here; nothing else is, without
|
||||||
|
// a rig of her own.
|
||||||
|
//
|
||||||
|
// So the nine states collapse onto what exists rather than pretending:
|
||||||
|
// speaking talks, idle rests, and the rest are a look — head for the ones
|
||||||
|
// that are about attention, body for the ones that are about effort. The
|
||||||
|
// bundle rate-limits its own hit reaction to once per ~8s, so a burst of
|
||||||
|
// tags reads as one shift rather than a twitching model.
|
||||||
posture: function (name) {
|
posture: function (name) {
|
||||||
if (typeof window.live2dMotion === 'function') window.live2dMotion(name);
|
var slot = document.getElementById('live_talk');
|
||||||
|
if (name === 'speaking' || name === 'talk') {
|
||||||
|
if (slot) slot.value = '1';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (name === 'idle' || name === 'rest') {
|
||||||
|
if (slot) slot.value = '0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var head = ['alert', 'affectionate', 'thinking', 'listening'].indexOf(name) >= 0;
|
||||||
|
var r = canvas.getBoundingClientRect();
|
||||||
|
var x = r.left + r.width / 2;
|
||||||
|
var y = r.top + r.height * (head ? 0.22 : 0.55);
|
||||||
|
['mousedown', 'mouseup', 'click'].forEach(function (t) {
|
||||||
|
try {
|
||||||
|
canvas.dispatchEvent(new MouseEvent(t, { clientX: x, clientY: y, bubbles: true }));
|
||||||
|
} catch (e) {}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
// Look at a point on the panel, in her window's own CSS pixels.
|
// Look at a point on the panel, in her window's own CSS pixels.
|
||||||
//
|
//
|
||||||
|
|
@ -121,6 +161,8 @@
|
||||||
// her first. These do not go through the compositor, so she can follow a
|
// her first. These do not go through the compositor, so she can follow a
|
||||||
// finger she is deliberately not being given.
|
// finger she is deliberately not being given.
|
||||||
lookAt: function (x, y) {
|
lookAt: function (x, y) {
|
||||||
|
if (window.__gazeSeen === undefined) window.__gazeSeen = 0;
|
||||||
|
if (window.__gazeSeen++ < 3) console.log('gaze: lookAt ' + Math.round(x) + ',' + Math.round(y));
|
||||||
try {
|
try {
|
||||||
canvas.dispatchEvent(new MouseEvent('mousemove', {
|
canvas.dispatchEvent(new MouseEvent('mousemove', {
|
||||||
clientX: x, clientY: y, bubbles: true
|
clientX: x, clientY: y, bubbles: true
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,13 @@ Singleton {
|
||||||
path: (Quickshell.env("XDG_RUNTIME_DIR") || "/run/user/1000") + "/souveraine/viewtop.sock"
|
path: (Quickshell.env("XDG_RUNTIME_DIR") || "/run/user/1000") + "/souveraine/viewtop.sock"
|
||||||
connected: root.joined
|
connected: root.joined
|
||||||
|
|
||||||
onConnectedChanged: {
|
// `onConnectionStateChanged`, not `onConnectedChanged` — Quickshell's
|
||||||
|
// Socket emits the former, so the latter is a handler for a signal
|
||||||
|
// that does not exist and never runs. The subscribe was therefore
|
||||||
|
// never sent, the compositor never pushed, and she never followed a
|
||||||
|
// finger. `ViewtopControl`'s feed had the right idiom the whole time.
|
||||||
|
onConnectionStateChanged: {
|
||||||
|
console.log("[face] gaze socket connected=" + gaze.connected);
|
||||||
if (gaze.connected)
|
if (gaze.connected)
|
||||||
gaze.write('{"op":"gaze"}\n');
|
gaze.write('{"op":"gaze"}\n');
|
||||||
}
|
}
|
||||||
|
|
@ -343,6 +349,9 @@ Singleton {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (root._gazeSeen === undefined) root._gazeSeen = 0;
|
||||||
|
if (root._gazeSeen++ < 4)
|
||||||
|
console.log("[face] gaze push: " + line);
|
||||||
if (m.ok !== undefined && m.down === undefined)
|
if (m.ok !== undefined && m.down === undefined)
|
||||||
return;
|
return;
|
||||||
if (!m.down) {
|
if (!m.down) {
|
||||||
|
|
@ -357,6 +366,7 @@ Singleton {
|
||||||
// Where her window sits on the panel. Read from the compositor's own
|
// Where her window sits on the panel. Read from the compositor's own
|
||||||
// furniture report rather than assumed, because the layout decides it and
|
// furniture report rather than assumed, because the layout decides it and
|
||||||
// it moves with the zone.
|
// it moves with the zone.
|
||||||
|
property var _gazeSeen: undefined
|
||||||
property real originX: 0
|
property real originX: 0
|
||||||
property real originY: 0
|
property real originY: 0
|
||||||
|
|
||||||
|
|
@ -364,7 +374,7 @@ Singleton {
|
||||||
id: whereAmI
|
id: whereAmI
|
||||||
path: (Quickshell.env("XDG_RUNTIME_DIR") || "/run/user/1000") + "/souveraine/viewtop.sock"
|
path: (Quickshell.env("XDG_RUNTIME_DIR") || "/run/user/1000") + "/souveraine/viewtop.sock"
|
||||||
|
|
||||||
onConnectedChanged: {
|
onConnectionStateChanged: {
|
||||||
if (whereAmI.connected)
|
if (whereAmI.connected)
|
||||||
whereAmI.write('{"op":"state"}\n');
|
whereAmI.write('{"op":"state"}\n');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue