바탕화면에 띄워서 일거수 일투족 감시하는녀석이 목표이기에 작업을 해야한다.
Electron 이라는걸 설치해서 작업해야하니깐 , 바탕화면에 위젯으로 만들기를 진행해보자.
" package.json 생성: 프로젝트의 메타데이터/스크립트/의존성 버전을 기록하는 파일."
요걸하기위해서
index.html 있는 위치에서(요게 일단 테스트용 실행파일)
npm init -y
아래와같은 Json 파일이 만들어짐.
{
"name": "virtual-assistant",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git+https://github.com/TangledUpTeam/Virtual-Assistant.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/TangledUpTeam/Virtual-Assistant/issues"
},
"homepage": "https://github.com/TangledUpTeam/Virtual-Assistant#readme"
}
--------
추후 main.js 를 만들고나서 아래와 같이 수정했다.
{
"name": "virtual-assistant",
"version": "1.0.0",
"private": true,
"description": "Desktop Live2D assistant (Electron, transparent window)",
"main": "main.js",
"scripts": {
"start": "electron .",
"start:dev": "electron .",
"postinstall": "echo Done"
},
"repository": {
"type": "git",
"url": "git+https://github.com/TangledUpTeam/Virtual-Assistant.git"
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/TangledUpTeam/Virtual-Assistant/issues"
},
"homepage": "https://github.com/TangledUpTeam/Virtual-Assistant#readme",
"devDependencies": {
"electron": "^39.1.2"
}
}
이제 아래 일렉트론을 설치하자 . -D는 개발의존성으로 설치하란뜻
npm i -D electron
그리고 main.js 파일을 추가해준다.
// main.js (프로젝트 루트)
const { app, BrowserWindow, globalShortcut, screen } = require("electron");
let win;
function createWindow() {
const { width, height } = screen.getPrimaryDisplay().workAreaSize;
win = new BrowserWindow({
width: 480,
height: 800,
x: width - 520, // 우하단 근처
y: height - 840,
frame: false, // 프레임 제거
transparent: true, // 창 배경 투명
alwaysOnTop: true, // 항상 위
resizable: true,
hasShadow: false,
skipTaskbar: true,
backgroundColor: "#00000000",
webPreferences: {
contextIsolation: true
}
});
// index.html (Live2D 띄우는 페이지)
win.loadFile("index.html");
// 클릭-스루 토글 (Alt+D): 캐릭터를 통과해서 뒤 창 클릭 가능
globalShortcut.register("Alt+D", () => {
const ignoring = win.isIgnoringMouseEvents();
win.setIgnoreMouseEvents(!ignoring, { forward: true });
});
}
app.whenReady().then(createWindow);
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
app.on("activate", () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
그리고 pakage.json 파일을 수정하고 .. (위에 수정 내용까지 참고)
마지막으로 index.html 을 수정한다.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<title>Virtual Desk Assistant - Hiyori</title>
<!-- 배경 완전 투명 + 드래그/노드래그 영역 정의 -->
<style>
html, body {
margin: 0;
height: 100%;
overflow: hidden;
/* 브라우저에서도, Electron에서도 투명 배경 유지 */
background: transparent;
}
/* 창을 끌 수 있는 핸들(투명 막대) */
.drag {
-webkit-app-region: drag; /* Electron에서 창 드래그 활성화 */
position: fixed;
top: 0; left: 0; right: 0;
height: 32px;
pointer-events: auto;
}
/* 상호작용(클릭 등)이 필요한 영역은 반드시 no-drag */
.no-drag {
-webkit-app-region: no-drag;
pointer-events: auto;
}
/* 캔버스 전체를 우하단에 두고 싶다면 아래 컨테이너를 사용 */
#app {
width: 100%;
height: 100%;
position: relative;
}
/* (선택) 우하단 고정 레이아웃 예시 */
#stage {
position: fixed;
right: 0;
bottom: 0;
left: 0;
top: 0;
}
</style>
</head>
<body>
<!-- 드래그 핸들(투명) : 일렉트론일 때 창 이동 가능 -->
<div class="drag"></div>
<!-- 캔버스 컨테이너는 no-drag로 상호작용 보장 -->
<div id="app" class="no-drag">
<div id="stage"></div>
</div>
<script>
/****************************************************************
* 순차 로더
* - 의존성 → 코어 → 플러그인 순서 보장
* - CDN 실패 시 다음 후보 자동 시도
****************************************************************/
function loadScript(url) {
return new Promise((resolve, reject) => {
const s = document.createElement('script');
s.src = url;
s.async = false; // 로드 순서 보장(중요)
s.onload = () => { console.log('✅ 로드 성공:', url); resolve(); };
s.onerror = () => { console.error('❌ 로드 실패:', url); reject(new Error(url)); };
document.head.appendChild(s);
});
}
async function init() {
try {
/******** 1) Pixi.js (v6.x) : 플러그인 0.4.x와 호환 ********/
const pixiCdn = [
'https://cdn.jsdelivr.net/npm/pixi.js@6.5.10/dist/browser/pixi.min.js',
'https://unpkg.com/pixi.js@6.5.10/dist/browser/pixi.min.js'
];
let ok = false;
for (const url of pixiCdn) {
try { await loadScript(url); ok = true; break; } catch {}
}
if (!ok) throw new Error('Pixi.js 로드 실패');
console.log('PIXI.VERSION =', window.PIXI && PIXI.VERSION);
/******** 2) Live2D Cubism Core : 플러그인이 참조하는 런타임 ********/
const coreCdn = [
// 공식 배포 경로(일시적 변경될 수 있어 백업도 둠)
'https://cubism.live2d.com/sdk-web/cubismcore/live2dcubismcore.min.js',
'https://cubism.live2d.com/sdk-web/bin/live2dcubismcore.min.js'
];
ok = false;
for (const url of coreCdn) {
try { await loadScript(url); ok = true; break; } catch {}
}
if (!ok) throw new Error('Live2D Cubism Core 로드 실패');
console.log('Live2DCubismCore =', typeof window.Live2DCubismCore); // "object" 기대
/******** 3) pixi-live2d-display (Cubism4 빌드, 0.4.x) ********/
const pluginCdn = [
'https://cdn.jsdelivr.net/npm/pixi-live2d-display@0.4.0/dist/cubism4.js',
'https://unpkg.com/pixi-live2d-display@0.4.0/dist/cubism4.js',
'https://cdn.jsdelivr.net/gh/guansss/pixi-live2d-display@v0.4.0/dist/cubism4.js'
];
ok = false;
for (const url of pluginCdn) {
try {
await loadScript(url);
if (window.PIXI?.live2d?.Live2DModel) { ok = true; break; }
} catch {}
}
if (!ok) throw new Error('pixi-live2d-display (cubism4) 로드 실패');
console.log('PIXI.live2d keys:', Object.keys(PIXI.live2d || {}));
/******** 4) Pixi 앱 & Live2D 모델 로드 ********/
// Electron/브라우저 공통: 전체 창 사이즈에 맞춤
const app = new PIXI.Application({ backgroundAlpha: 0, resizeTo: window });
document.getElementById('stage').appendChild(app.view);
// 모델 경로: 브라우저(http 서버) / Electron(file 스킴) 모두에서 동작하는 상대 경로 권장
const MODEL_URL = 'public/models/hiyori_free_ko/runtime/hiyori_free_t08.model3.json';
console.log('📦 모델 로딩:', MODEL_URL);
const model = await PIXI.live2d.Live2DModel.from(MODEL_URL);
// 배치: 화면 하단 중앙, 크기 적당히
model.anchor.set(0.5, 1);
model.scale.set(0.2); // 너비/해상도에 맞게 조절 (0.15~0.5 사이 시도)
model.position.set(window.innerWidth / 2, window.innerHeight);
app.stage.addChild(model);
// 상호작용: 탭 모션
model.interactive = true;
model.on('pointertap', () => model.motion?.('Tap')?.start?.());
// 리사이즈 대응(하단 정렬 유지)
window.addEventListener('resize', () => {
model.position.set(window.innerWidth / 2, window.innerHeight);
});
console.log('🎉 준비 완료!');
} catch (err) {
console.error('❌ 초기화 실패:', err);
document.getElementById('app').innerHTML =
`<div style="color:white;padding:20px;font-family:monospace;">
<h2>❌ 로드 실패</h2>
<p>${err.message}</p>
<p>DevTools → Network/Console 확인</p>
</div>`;
}
}
window.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>

실행해보면 뭔가 뒷배경을 날렸지만 .. 투명한 창이 있어서 ..뒤에 보이는 유투브나 넷플릭스를 실행할 수 없다..
진짜 ai 가 다 알려줘서 그렇지... 프론트엔드 공부해야겠따..

'학원 TEAM 프로젝트 > 심화과정 Team Project(최종)' 카테고리의 다른 글
| 기록 9 . 로그인기능을 구현해야한다.(네이버,구글,카카오) (0) | 2025.11.14 |
|---|---|
| 기록 8 . 캐릭터 클릭을 좀더 자연스럽게 .. (0) | 2025.11.13 |
| 기록 6 . 일단 캐릭터를 띄워보자...(가져다 쓴다) (0) | 2025.11.13 |
| 기록 5-1 . 그래서 버츄얼 비서 프로젝트..잘할수있을까? (0) | 2025.11.12 |
| 기록 5 . 프로젝트 기획 뒤짚어 엎기... (0) | 2025.11.12 |