80 lines
2.6 KiB
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="rig://localhost/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', 'rig://localhost/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>
|