묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결디자이너의 스킬업을 위한 Lottie 완벽 이해하기
저도 bodymovin 에 composition이 생성되지 않습니다.
https://www.inflearn.com/questions/840104/%EC%B5%9C%EC%8B%A0%EB%B2%84%EC%A0%84%EC%9C%BC%EB%A1%9C-%ED%95%98%EA%B3%A0-%EB%8B%A4-%ED%95%B4%EB%B4%90%EB%8F%84-bodymovin-%EC%97%90-%EC%95%84%EB%AC%B4%EA%B2%83%EB%8F%84-%EC%95%88%EB%96%A0%EC%9A%94이전에 문의글처럼 저도 동일 현상 발생합니다.브라우저, AE, bodymovin 모두 최신 버전으로 다운받아 적용해보았는데 composition을 못불러들입니다. 더 이상 진행이 안되는데 어떻게 해야할까요?
-
미해결몇 줄로 끝내는 인터랙티브 웹 개발 노하우 [초급편]
마우스 인터렉티브 변형 질문
안녕하세요. 마우스 인터렉티브를 하다가 transition: ease-in-out 궁금증이 생겼습니다!마우스의 궤적을 따라서 이미지가 잔상처럼 늘어나는 것으로 보이게 하고 싶어서 circle보다 작은 크기의 도형을 만들어 ease in out 에 초 차이를 주었는데 원하는 효과가 나타나지 않았습니다. 해당 함수를 사용하면 초에 따라서 마우스 포인터를 따라오는 속도가 달라지는 줄 알았는데 제가 잘못 이해한 걸까요?혹시 몰라 transition-duration/delay 함수도 사용해 봤는데 적용이 안 됐습니다.. 마우스를 움직일때는 잔상이 스프링처럼 길게 늘어지다가 멈추면 줄어드는 방향으로 하고 싶은데 이런 변형 관련한 질문은 어려울까요? 게이트박스와 mouseenter를 이용해서 크기가 줄어드는 걸로 활용 해보았는데 게이트 박스 외의 부분에 마찬가지로 적용하는게 어려워서 질문 드립니다..!감사합니다.
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
강의를 이제 막 수강하고 있는데요~
강의 따라해서 만든 three.js 프로젝트를 제가 가지고 있는 spirng 프로젝트의 jsp페이지에서 include?? 하는 식으로 가져와서 사용하는 것이 어렵나요?호환이나 이런부분에 대해서 해결할 줄알아야 가능한걸까요?ㅠㅠspring 프로젝트를 톰캣에서 돌리고 메뉴를 클릭하였을 때 three.js 강의로 만든 페이지가 렌더링 되서 나왔으면 좋겠거든요.가능한 걸까요? 어떤식으로 하면 될지 힌트 좀 주실 수 있을까요?
-
해결됨웹 애니메이션을 위한 GSAP 가이드 Part.02
안녕하세요 수업자료를 다운받았는데 중간중간 파일이 없어요 ㅠㅠ
영상 우측상단에 수업자료를 다운받고 열어보니 중간중간 없는 파일들이 있습니다 ㅠㅠ 저만 그런건지..
-
미해결인터랙티브 개발 실무 끝장내기 [역량 강화편]
레퍼런스 사이트
안녕하세요. 부분부분 듣다보니, 혹시 말씀하셨을 수도 있겠는데.. 질문 남깁니다. 보여주신 레퍼런스 사이트들이 취합된 곳이나 링크를 공유해주실 수 있을까요? 재밌는 강의 감사합니다.
-
미해결인터랙티브 웹 개발 제대로 시작하기
외부에서 JS파일을 불러올땐 무조건 defer를 써도 괜찮은건가요?
예외적으로 플러그인 같이 개별로 작동하는 JS파일은 async로 불러오고 일반적으로 작성한 JS들은 전부 defer로 불러온다고 했을때 발생할 수 있는 문제같은게 있을까요?
-
해결됨웹 애니메이션의 새로운 표준, Web Animations API
특정 시점에 자바스크립트 호출은 어려울까요?
우선 좋은 강의에 감사드립니다. scroll-timeline을 바탕으로 새로운 프로젝트를 작성하고 있는데요,특정 시점에 요소 opacity 조절로 노출되게끔 처리했습니다.그런데 이 노출되는 시점에서부터는 특정 스크롤까지 css keyframes로 혼자 깜빡깜빡 거리는 효과를 주고싶은데요. 자바스크립트로 class를 add / remove 해야할지 고민입니다.더 효율적이거나 좋은 방법이 있을까요?
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
이런 사이트를 올리려면 필요한 작업
안녕하세요 1분 코딩님 완강하고 저 만의 포트폴리오를 만들어보려고 노력하고 있습니다.다만 제가 이쪽 분야는 잘 몰라서 어떻게 올려야 할지 감이 안 잡힙니다. 일단 vultr 에서 서버를 구하고 가비아에서 도메인까지 1년으로 구매했는데 해도 html 하나 올려서 외부에 뿌리는 것도 어렵네요. 혹시 어떻게 해야 할지 조언을 구해도 될까요?
-
미해결웹 애니메이션의 새로운 표준, Web Animations API
section04 - 각각의 객체에 개별 애니메이션 적용하기
선생님 안녕하세요 !강의를 듣는 중 궁금한 점이 있어 질의 드립니다.section04 - 각각의 객체에 개별 애니메이션 적용하기 영상에서let bar를 for문 밖에 선언하고 for문 안에서 document.createElement를 할당한 이유가 있을까요?for문 안에 같이 선언하면서 할당하는 코드와 어떤 부분이 다른지 잘 모르겠어서 질의 드립니다. const bars = []; let bar; for(let i = 0; i < 30; i++){ bar = document.createElement('div'); bar.classList.add('bar'); barContainer.appendChild(bar); bars.push(bar); }
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
spotlght 빛 세기 이슈
이게 크롬에 따라 다른지 기기에 따라 다른지 모르겠지만 spotlight 빛이 1로 하면 거의 안 보이는 이슈가 있네요. 10000정도 해야 강의와 비슷하게 나옵니다. 코드가 잘못되었나 해서 spotlighthelper로 테스트 했습니다.
-
해결됨웹 애니메이션을 위한 GSAP 가이드 Part.02
안녕하세요 이렇게 나오는데..
오늘 강의 시작했는데 실습 예제 다운 받으려고 하니 저렇게 나오고 클릭이 안되네요 ㅜ 해결 방법 있을까요? 엣지 크롬 파이어폭스 셋다 저러네요 브라우저 보안 설정 떄문인가 해서 보안도 끄고 들어가봐도 저래요 아 그리고 실습예제 codepen 링크들어가서 보면 버튼눌러도 애니메이션이 반응이 없던데 .. 왜그런지 이유를 모르겠어요 다 그런건 아닌거같고 처음에 motionpath 예제만 그런거 같더라구요
-
미해결웹 애니메이션의 새로운 표준, Web Animations API
scroll-timeline.js 를 사용한 ScrollTimeline 실행 시, easing 효과?
안녕하세요. 강의 잘 듣고 있습니다. scroll-timeline.js 를 사용한 ScrollTimeline 실행 시, 부드러운 모션 효과를 위한 옵션이 있을까요?스크롤 한번 했을 때. 스르륵 멈출 수 있게요.
-
미해결웹 애니메이션의 새로운 표준, Web Animations API
scroll-timeline.js 파일
안녕하세요!강의 재밌게 잘 보고 있습니다 :Dscroll-timeline.js 파일은 어디서 가져오신 건가요?세팅부터 혼자서 해보려고 했는데scroll-timeline 저장소여기서 아무리 찾아봐도 안 보이네요..!Usage에 보면 import를 dist 폴더에서 scroll-timeline.js를 가져오는 것 같은데 dist 폴더도 안 보이고 src 폴더에 scroll-timeline-base.js도 아닌 것 같아서 질문 남깁니다..!또, scrollOffsets에 넣는 옵션들은 어떻게 확인하나요? README에는 new CSSUnitValue 이것밖에 안 보이는데 강의에서는 target, edge, threshold 속성들도 쓰셔서 어디서 확인하고 쓰시는지 너무 궁금합니다..!
-
미해결웹 애니메이션의 새로운 표준, Web Animations API
선생님 Section4에 제목 오타난것같습니다!
Starfiled => Starfield 인 것 같습니다!
-
미해결애플 웹사이트 인터랙션 클론!
페이지가 처음 로딩 되었을 때 애니메이션 처리가 되지 않는 느낌입니다
페이지가 맨 처음 로딩 되었을 때에는 애니메이션이 작동하지 않다가... 페이지 섹션을 일정 부분 진행하고 다시 윗방향 스크롤을 걸었을때 애니메이션이 정상작동을 합니다.그 후부터는 페이지의 시작 위치로 이동해서 시작부터 차근차근 내렸을때 정상작동을 합니다.원인이 잘 생각이 나지 않네요 Main.js(() => { let yOffset = 0; // window.pageYOffset 대신에 쓸 변수 let prevScrollHeight = 0; // 현재 스크롤 위치(yOffset) 보다 이전에 위치한 스크롤 섹션들의 스크롤 높이값의 합 let currentScene = 0; // 현재 활성화된 (눈 앞에 보고있는) 씬 (Scrollsection) let enterNewScene = false; // 새로운 Scene이 시작된 순간 true // sceneInfo는 각 scene에 대한 정보를 담고 있다. const sceneInfo = [ { // 0 type: 'sticky', heightNum: 5, // 브라우저 높이의 5배로 scrollHeight 세팅 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-0'), messageA: document.querySelector('#scroll-section-0 .main-message.a'), messageB: document.querySelector('#scroll-section-0 .main-message.b'), messageC: document.querySelector('#scroll-section-0 .main-message.c'), messageD: document.querySelector('#scroll-section-0 .main-message.d') }, values: { messageA_opacity_in: [0, 1, { start: 0.1, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.3, end: 0.4 }], messageC_opacity_in: [0, 1, { start: 0.5, end: 0.6 }], messageD_opacity_in: [0, 1, { start: 0.7, end: 0.8 }], messageA_translateY_in: [20, 0, { start: 0.1, end: 0.2 }], messageB_translateY_in: [20, 0, { start: 0.3, end: 0.4 }], messageC_translateY_in: [20, 0, { start: 0.5, end: 0.6 }], messageD_translateY_in: [20, 0, { start: 0.7, end: 0.8 }], messageA_opacity_out: [1, 0, { start: 0.25, end: 0.3 }], messageB_opacity_out: [1, 0, { start: 0.45, end: 0.5 }], messageC_opacity_out: [1, 0, { start: 0.65, end: 0.7 }], messageD_opacity_out: [1, 0, { start: 0.85, end: 0.9 }], messageA_translateY_out: [0, -20, { start: 0.25, end: 0.3 }], messageB_translateY_out: [0, -20, { start: 0.45, end: 0.5 }], messageC_translateY_out: [0, -20, { start: 0.65, end: 0.7 }], messageD_translateY_out: [0, -20, { start: 0.85, end: 0.9 }] } }, { // 1 type: 'normal', // heightNum: 5, // type normal에서는 필요 없음 scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-1'), content: document.querySelector('#scroll-section-1 .description') } }, { // 2 type: 'sticky', heightNum: 5, scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-2'), messageA: document.querySelector('#scroll-section-2 .a'), messageB: document.querySelector('#scroll-section-2 .b'), messageC: document.querySelector('#scroll-section-2 .c'), pinB: document.querySelector('#scroll-section-2 .b .pin'), pinC: document.querySelector('#scroll-section-2 .c .pin') }, values: { messageA_translateY_in: [20, 0, { start: 0.15, end: 0.2 }], messageB_translateY_in: [30, 0, { start: 0.5, end: 0.55 }], messageC_translateY_in: [30, 0, { start: 0.72, end: 0.77 }], messageA_opacity_in: [0, 1, { start: 0.15, end: 0.2 }], messageB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], messageC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], messageA_translateY_out: [0, -20, { start: 0.3, end: 0.35 }], messageB_translateY_out: [0, -20, { start: 0.58, end: 0.63 }], messageC_translateY_out: [0, -20, { start: 0.85, end: 0.9 }], messageA_opacity_out: [1, 0, { start: 0.3, end: 0.35 }], messageB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], messageC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }], pinB_scaleY: [0.5, 1, { start: 0.5, end: 0.55 }], pinC_scaleY: [0.5, 1, { start: 0.72, end: 0.77 }], pinB_opacity_in: [0, 1, { start: 0.5, end: 0.55 }], pinC_opacity_in: [0, 1, { start: 0.72, end: 0.77 }], pinB_opacity_out: [1, 0, { start: 0.58, end: 0.63 }], pinC_opacity_out: [1, 0, { start: 0.85, end: 0.9 }] } }, { // 3 type: 'sticky', heightNum: 5, scrollHeight: 0, objs: { container: document.querySelector('#scroll-section-3'), canvasCaption: document.querySelector('.canvas-caption') }, values: { } } ]; function setLayout() { // 각 스크롤 섹션의 높이 세팅 for (let i = 0; i < sceneInfo.length; i++) { if(sceneInfo[i].type === 'sticky') { sceneInfo[i].scrollHeight = sceneInfo[i].heightNum * window.innerHeight; // window.innerHeight는 브라우저 창의 높이 } else if(sceneInfo[i].type === 'normal') { sceneInfo[i].scrollHeight = sceneInfo[i].objs.container.offsetHeight } sceneInfo[i].objs.container.style.height = `${sceneInfo[i].scrollHeight}px` } yOffset = window.scrollY; let totalScrollHeight = 0; for (let i = 0; i < sceneInfo.length; i++) { totalScrollHeight += sceneInfo[i].scrollHeight; if(totalScrollHeight >= yOffset) { // 이미지로 그려보면 이해가 쉬움 currentScene = i; break; } } document.body.setAttribute('id', `show-scene=${currentScene}`) } function calcValues (values, currentYOffset) { // currentYOffset은 현재 씬에서 얼마나 스크롤 됐는지를 의미 let rv; // 현재 씬(스크롤섹션)에서 스크롤된 범위를 비율로 구하기 const scrollHeight = sceneInfo[currentScene].scrollHeight const scrollRatio = currentYOffset / sceneInfo[currentScene].scrollHeight; if (values.length === 3) { // start ~ end 사이의 애니메이션을 실행 const partScrollStart = values[2].start * scrollHeight; const partScrollEnd = values[2].end * scrollHeight; const partScrollHeight = partScrollEnd - partScrollStart if (currentYOffset >= partScrollStart && currentYOffset <= partScrollEnd) { rv = (currentYOffset - partScrollStart) / partScrollStart * (values[1] - values[0]) + values[0]; } else if (currentYOffset < partScrollStart) { rv = values[0]; } else if (currentYOffset > partScrollEnd) { rv = values[1]; } } else { rv = scrollRatio * (values[1] - values[0]) + values[0]; } return rv; } function playAnimation() { const objs = sceneInfo[currentScene].objs; const values = sceneInfo[currentScene].values; const currentYOffset = yOffset - prevScrollHeight; const scrollHeight = sceneInfo[currentScene].scrollHeight; const scrollRatio = currentYOffset / scrollHeight; switch (currentScene) { case 0: // console.log('0 play'); if (scrollRatio <= 0.22) { // in objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.42) { // in objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset); objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset); objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.62) { // in objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset); objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset); objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.82) { // in objs.messageD.style.opacity = calcValues(values.messageD_opacity_in, currentYOffset); objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageD.style.opacity = calcValues(values.messageD_opacity_out, currentYOffset); objs.messageD.style.transform = `translate3d(0, ${calcValues(values.messageD_translateY_out, currentYOffset)}%, 0)`; } break; case 2: // console.log('2 play'); if (scrollRatio <= 0.32) { // in objs.messageA.style.opacity = calcValues(values.messageA_opacity_in, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_in, currentYOffset)}%, 0)`; } else { // out objs.messageA.style.opacity = calcValues(values.messageA_opacity_out, currentYOffset); objs.messageA.style.transform = `translate3d(0, ${calcValues(values.messageA_translateY_out, currentYOffset)}%, 0)`; } if (scrollRatio <= 0.67) { // in objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_in, currentYOffset)}%, 0)`; objs.messageB.style.opacity = calcValues(values.messageB_opacity_in, currentYOffset); objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`; } else { // out objs.messageB.style.transform = `translate3d(0, ${calcValues(values.messageB_translateY_out, currentYOffset)}%, 0)`; objs.messageB.style.opacity = calcValues(values.messageB_opacity_out, currentYOffset); objs.pinB.style.transform = `scaleY(${calcValues(values.pinB_scaleY, currentYOffset)})`; } if (scrollRatio <= 0.93) { // in objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_in, currentYOffset)}%, 0)`; objs.messageC.style.opacity = calcValues(values.messageC_opacity_in, currentYOffset); objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`; } else { // out objs.messageC.style.transform = `translate3d(0, ${calcValues(values.messageC_translateY_out, currentYOffset)}%, 0)`; objs.messageC.style.opacity = calcValues(values.messageC_opacity_out, currentYOffset); objs.pinC.style.transform = `scaleY(${calcValues(values.pinC_scaleY, currentYOffset)})`; } break; case 3: // console.log('3 play'); break; } } function scrollLoop() { enterNewScene = false; prevScrollHeight = 0; // PrevScrollHeight의 초기화가 함수 내에 있어야 맥북 기준 4 scene의 총합 11540이 찍히고 다음 scrollLoop() 이 실행될 때 다시 초기화 된다. (값이 누적되지 않는다.) for (let i = 0; i < currentScene; i++) { prevScrollHeight += sceneInfo[i].scrollHeight; } if(yOffset > prevScrollHeight + sceneInfo[currentScene].scrollHeight) { enterNewScene = true; currentScene++; document.body.setAttribute('id', `show-scene-${currentScene}`); } if(yOffset < prevScrollHeight) { enterNewScene = true; if (currentScene === 0) return; // scene 0에서 바운싱 스크롤이 일어났을 때 콘솔에 -값을 찍히지 않게 방지 currentScene--; document.body.setAttribute('id', `show-scene-${currentScene}`); } if (enterNewScene) return; playAnimation(); } window.addEventListener('scroll', () => { yOffset = window.scrollY; // window.pageYOffset은 deprecated 되었다. scrollLoop() }); // window.addEventListener('DOMContentLoaded', setLayout) window.addEventListener('load', setLayout) window.addEventListener('resize', setLayout) // 화면 크기가 바뀌었을때를 기준으로 setLayout을 정의하기 })();main.css@charset "utf-8"; html { font-family: 'Noto Sans KR' , sans-serif; font-size: 14px; } body { overflow-x: hidden; color: rgb(29, 29, 31); letter-spacing: -0.05em; background: white; } p { line-height: 1.6; } a { color: rgb(29, 29, 31); text-decoration: none; } .global-nav { position: absolute; top: 0; left: 0; width: 100%; height: 44px; padding: 0 1rem; } .local-nav { position: absolute; top: 45px; left: 0; width: 100%; height: 52px; padding: 0 1rem; border-bottom: 1px solid #ddd; } .global-nav-links, .local-nav-links { display: flex; align-items: center; max-width: 1000px; height: 100%; margin: 0 auto; /* background-color: gold; */ } .global-nav-links { justify-content: space-between; } .local-nav-links .product-name { margin-right: auto; font-size: 1.4rem; font-weight: bold; } .local-nav-links a { font-size: 0.8rem; } .local-nav-links a:not(.product-name) { margin-left: 2em; } .scroll-section { border: 3px solid red; padding-top: 50vh; } #scroll-section-0 h1 { font-size: 4rem; text-align: center; } .main-message { display: flex; align-items: center; justify-content: center; top: 35vh; margin: 5px 0; height: 3em; font-size: 2.5rem; opacity: 0; } .main-message p { font-weight: bold; text-align: center; line-height: 1.2; } .main-message small { display: block; margin-bottom: 0.5em; font-size: 1.2rem; } #scroll-section-2 .main-message { font-size: 3.5rem; } .description { max-width: 1000px; margin: 0 auto; padding: 0 1rem; font-size: 1.2rem; color: #888 } .description strong { float: left; margin-right: 0.2em; /* font-size: 3rem; */ color: rgb(29, 29, 31); } .desc-message { width: 50%; font-weight: bold; } .pin { width: 1px; height: 100px; background: rgb(29,29,31); } #scroll-section-2 .b { top: 10%; left: 40%; } #scroll-section-2 .c { top: 15%; left: 45%; } .mid-message { max-width: 1000px; margin: 0 auto; padding: 0 1rem; font-size: 2rem; color: #888; } .mid-message strong { color: rgb(29,29,31); } .canvas-caption { max-width: 1000px; margin: 0 auto; padding: 0 1rem; font-size: 1.2rem; color: #888; } .footer { display: flex; align-items: center; justify-content: center; height: 7rem; color: white; background: darkorange; } .sticky-elem { display: none; position: fixed; left: 0; width: 100%; } body#show-scene-0 #scroll-section-0 .sticky-elem, body#show-scene-1 #scroll-section-1 .sticky-elem, body#show-scene-2 #scroll-section-2 .sticky-elem, body#show-scene-3 #scroll-section-3 .sticky-elem { display: block; } @media(min-width: 1024px) { #scroll-section-0 h1 { font-size: 9vw; } .main-message { font-size: 4vw; } .description { font-size: 2rem; } .description strong { font-size: 6rem; } #scroll-section-2 .main-message { font-size: 6vw; } .main-message small { font-size: 1.5vw; } .desc-message { width: 20%; } #scroll-section-2 .b { top: 20%; left: 53%; } #scroll-section-2 .c { left: 55%; } .mid-message { font-size: 4vw; } .canvas-caption { font-size: 2rem; } }blank.html<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>AirMug Pro</title> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@400;900&display=swap" rel="stylesheet"> <link rel="stylesheet" href="css/default.css"> <link rel="stylesheet" href="css/main.css"> </head> <body> <div class="container"> <nav class="global-nav"> <div class="global-nav-links"> <a href="" class="global-nav-item">Rooms</a> <a href="" class="global-nav-item">Ideas</a> <a href="" class="global-nav-item">Stores</a> <a href="" class="global-nav-item">Contact</a> </div> </nav> <nav class="local-nav"> <div class="local-nav-links"> <a href="#" class="product-name">AirMug Pro</a> <a href="#">개요</a> <a href="#">제품사양</a> <a href="#">구입하기</a> </div> </nav> <section class="scroll-section" id="scroll-section-0"> <h1>AirMug Pro</h1> <div class="sticky-elem main-message a"> <p>온전히 빠져들게 하는<br>최고급 세라믹</p> </div> <div class="sticky-elem main-message b"> <p>주변 맛을 느끼게 해주는<br>주변 맛 허용 모드</p> </div> <div class="sticky-elem main-message c"> <p>온전히 편안한<br>맞춤형 손잡이</p> </div> <div class="sticky-elem main-message d"> <p>새롭게 입가를<br>찾아온 매혹</p> </div> </section> <section class="scroll-section" id="scroll-section-1"> <p class="description"> <strong>보통 스크롤 영역</strong> Lorem, ipsum dolor sit amet consectetur adipisicing elit. Dolore explicabo commodi facere nisi expedita eaque quasi doloremque eligendi natus architecto, facilis velit nobis voluptatum suscipit autem soluta debitis neque illum quibusdam similique odio maiores. Ab optio laborum eum sit praesentium, aperiam voluptatem nihil modi tempore a magni necessitatibus hic exercitationem temporibus doloremque error omnis. Sequi, repudiandae dolor eaque non soluta praesentium doloremque, doloribus, ea consequuntur sit perferendis ex! Repellendus natus harum soluta dolorem voluptas alias qui, ipsa vero! Alias voluptate libero, facilis molestias nam aspernatur, amet accusantium consequatur a nostrum temporibus. Qui obcaecati optio quod iusto totam, aut iste dolor ea. Explicabo dolorem ducimus natus, officiis aut minima, ad sapiente voluptatem repellat aliquid suscipit at. Architecto nostrum perferendis, fugiat velit perspiciatis illum dignissimos, vitae delectus magnam blanditiis omnis ratione nihil minus deserunt repudiandae necessitatibus et, tempore cupiditate sapiente? Debitis obcaecati repellendus corrupti odit incidunt deleniti exercitationem dolorum ipsum consequatur rerum maxime, corporis placeat deserunt veniam cum qui dolorem nulla fugit eius ipsam quibusdam saepe! Aut culpa excepturi perferendis, sint animi tempora. Officia necessitatibus libero impedit alias commodi excepturi accusamus molestiae modi laudantium voluptates totam earum autem eos numquam at consequuntur ipsam repellat, perspiciatis veniam? Expedita nobis ducimus quisquam accusantium! Velit! </p> </section> <section class="scroll-section" id="scroll-section-2"> <div class="sticky-elem main-message a"> <p> <small>편안한 촉감</small> 입과 하나 되다 </p> </div> <div class="sticky-elem desc-message b"> <p> 편안한 목넘김을 완성하는 디테일한 여러 구성 요소들, 우리는 이를 하나하나 새롭게 살피고 재구성하는 과정을 거쳐 새로운 수준의 머그, AirMug Pro를 만들었습니다. 입에 뭔가 댔다는 감각은 어느새 사라지고 오롯이 당신과 음료만 남게 되죠. </p> <div class="pin"></div> </div> <div class="sticky-elem desc-message c"> <p> 디자인 앤 퀄리티 오브 스웨덴,<br>메이드 인 차이나 </p> <div class="pin"></div> </div> </section> <section class="scroll-section" id="scroll-section-3"> <p class="mid-message"> <strong>Retina 머그</strong> 아이디어를 광할하게 펼칠<br> 아름답고 부드러운 음료 공간. </p> <p class="canvas-caption"> Lorem ipsum dolor sit amet consectetur adipisicing elit. Expedita nulla nesciunt tempora asperiores culpa, illo et assumenda vel odio voluptatem? Saepe rerum qui accusamus maiores ex libero natus obcaecati accusantium aperiam eligendi ut et facere quis molestias quos repudiandae, omnis facilis deserunt cum! Expedita ipsam aliquid beatae doloremque, officia explicabo non neque reprehenderit qui quo, recusandae incidunt saepe totam! Adipisci dolorem inventore soluta. Natus pariatur sit quisquam dicta placeat! Molestias voluptas eos asperiores maxime, dolorem corporis eum quos iste dolores eveniet, cumque officiis beatae adipisci! Corporis quibusdam voluptates explicabo officiis quis cupiditate qui officia expedita. Praesentium placeat debitis recusandae ipsa similique optio accusamus, omnis vero a ducimus blanditiis fugit asperiores maiores mollitia? Pariatur exercitationem culpa, fugiat accusantium soluta incidunt beatae debitis laborum, harum neque aliquam, asperiores quod! Error numquam voluptate aut corrupti nam! Iusto illum accusamus sapiente asperiores quo eum perspiciatis aliquam blanditiis dolorem natus, modi magnam molestiae accusantium porro quisquam iure tempora laborum deserunt recusandae omnis dolore eos pariatur eveniet. Exercitationem mollitia inventore at quasi aperiam blanditiis minima accusantium, delectus, possimus quidem labore sapiente eius sint molestias doloribus est autem cupiditate iure veniam optio! Placeat dolor et, eos, saepe nemo tempore aliquid alias, facere pariatur optio sint nam ea. </p> </section> <footer class="footer"> 2023-08-01 Jun </footer> </div> <script src="js/main.js"></script> </body> </html>
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
Studiomeal 소스코드가 궁금합니다.
안녕하세요! 클론코딩형식으로 studiomeal을 구현해보고싶은데 방명록 작성이나 동영상을 띄우는 부분이 너무 궁금해서 혹시 소스가 오픈되어있는지 궁금합니다.! 추가적으로 해보려고 하는게 사용자가 사진과 제목과 내용을 작성하면 이미지, 제목, 내용이 액자처럼 되어서 마치 미술관에 전시된 그림과 제목과 내용을 확인할 수 있는 것처럼 구현해보고 싶은데 조언 부탁드립니다!
-
미해결인터랙티브 웹 개발 제대로 시작하기
질문 있습니다~
안녕하세요 선생님:-)강의 끝 부분에 특정 번호를 넣으면그 번호의 문이 열리게 activate 함수를수정해보라고 하셔서 코딩을 해봤는데이 방법처럼 해도 되는지 잘 모르겠어서요~이렇게 해도 되나요? <script> (function(){ const stageElem = document.querySelector('.stage'); let currentItem; //활성화 function activate(elem){ if(typeof(elem) == "number"){ activate(document.querySelector('.door:nth-child('+ elem +')')); return; } elem.classList.add('door-opened'); currentItem = elem; } //비활성화 function inactivate(elem){ elem.classList.remove('door-opened'); } function doorHandler(e){ const targetElem = e.target; //비활성화 if(currentItem){ inactivate(currentItem); } //활성화 if(targetElem.classList.contains('door-body')){ activate(targetElem.parentNode); } } stageElem.addEventListener('click', doorHandler); activate(3); })(); </script>
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
물리엔진 사용
현재 모듈형으로 진행해오고 있었는데cannon-es.js의 경우 npm으로만 연결이 가능한건가요..?ㅠ
-
해결됨Three.js로 시작하는 3D 인터랙티브 웹
색칠 이후에 적용이 되지않습니다...
색칠 이후에 오브젝트 모드로 진입하면 캐릭터에 적용이 되지 않습니다...
-
미해결Three.js로 시작하는 3D 인터랙티브 웹
로드 이후 gltf wireframe 속성 변경이 가능할까요?
수업 너무 재밌게 잘 들었습니다! 수업듣고 혼자 프로젝트 만들어보다 궁금증이 생겼는데요! gltf로 캐릭터 로드 후 특정 영역안에 들어갈 시 traverse를 이용해서 캐릭터 wireframe을 true로 바꾸고 싶은데요 이미 로드된 캐릭터는 wireframe을 변경할 수 없을까요..?