Watch
1
0
Fork
You've already forked souveraine
0
souveraine/assets/face/index.html

80 lines
2.6 KiB
HTML

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<style>
html, body {
margin: 0; padding: 0; height: 100%; width: 100%;
background: transparent; overflow: hidden;
-webkit-user-select: none; user-select: none;
}
#live2d-widget { position: fixed; inset: 0; }
#live2d { width: 100%; height: 100%; }
#bubble {
position: fixed; left: 8px; right: 8px; top: 12px;
padding: 10px 14px; border-radius: 14px;
background: rgba(20,20,24,0.82); color: #f2f2f2;
font: 15px/1.35 system-ui, sans-serif;
opacity: 0; transition: opacity .2s ease;
}
#bubble.up { opacity: 1; }
</style>
</head>
<body>
<div id="live2d-widget"><canvas id="live2d"></canvas></div>
<div id="bubble"></div>
<script src="live2d/js/live2d.js"></script>
<script>
// The character layer, reduced to what the shell drives. The reference's
// message.js owns idle chatter, a talk box and sessionStorage position; none of
// that belongs here — the shell owns the conversation and the summoning, and
// idle chatter that is hers comes from the subconscious, not a random line
// table (TASK-59 Q2).
(function () {
var canvas = document.getElementById('live2d');
var bubble = document.getElementById('bubble');
var model = null;
function fit() {
canvas.width = window.innerWidth * window.devicePixelRatio;
canvas.height = window.innerHeight * window.devicePixelRatio;
}
window.addEventListener('resize', fit);
fit();
// loadlive2d is live2d.js's entry point: canvas id, model.json url.
try {
loadlive2d('live2d', 'live2d/model/histoire/model.json');
} catch (e) {
console.error('rig failed to load', e);
}
var hideAt = null;
window.face = {
// One line of her speech. Called repeatedly as tokens stream, so it
// replaces rather than appends — the shell holds the accumulated text.
say: function (text) {
bubble.textContent = text;
bubble.classList.add('up');
hideAt = Date.now() + 6000;
},
clear: function () { bubble.classList.remove('up'); },
// Posture from the shell. The rig's own motion groups are named by the
// reference (idle, tap); anything richer waits on her own rig.
posture: function (name) {
if (typeof window.live2dMotion === 'function') window.live2dMotion(name);
}
};
setInterval(function () {
if (hideAt && Date.now() > hideAt) { hideAt = null; window.face.clear(); }
}, 500);
canvas.addEventListener('click', function () {
if (window.souveraine) window.souveraine.tapped('body');
});
})();
</script>
</body>
</html>