main
reng 1 month ago
parent 32ceb9c4c6
commit 93d6ea9f6b
  1. 20
      package-lock.json
  2. 1
      package.json
  3. 158
      public/data.json
  4. 7
      src/App.jsx
  5. 1
      src/assets/lottie/Grayscale_landing.json
  6. 1
      src/assets/lottie/circle.json
  7. 1
      src/assets/lottie/egg_bg.json
  8. 1
      src/assets/lottie/hint.json
  9. 2
      src/comps/canvas.jsx
  10. 7
      src/index.css
  11. 13
      src/pages/explore.jsx
  12. 19
      src/pages/keywords.jsx

20
package-lock.json generated

@ -9,6 +9,7 @@
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"lottie-react": "^2.4.1",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"react-router-dom": "^7.13.0", "react-router-dom": "^7.13.0",
@ -2831,6 +2832,25 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/lottie-react": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/lottie-react/-/lottie-react-2.4.1.tgz",
"integrity": "sha512-LQrH7jlkigIIv++wIyrOYFLHSKQpEY4zehPicL9bQsrt1rnoKRYCYgpCUe5maqylNtacy58/sQDZTkwMcTRxZw==",
"license": "MIT",
"dependencies": {
"lottie-web": "^5.10.2"
},
"peerDependencies": {
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/lottie-web": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz",
"integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==",
"license": "MIT"
},
"node_modules/lru-cache": { "node_modules/lru-cache": {
"version": "5.1.1", "version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",

@ -11,6 +11,7 @@
}, },
"dependencies": { "dependencies": {
"@tailwindcss/vite": "^4.1.18", "@tailwindcss/vite": "^4.1.18",
"lottie-react": "^2.4.1",
"react": "^19.2.0", "react": "^19.2.0",
"react-dom": "^19.2.0", "react-dom": "^19.2.0",
"react-router-dom": "^7.13.0", "react-router-dom": "^7.13.0",

@ -50,270 +50,186 @@
"keywords": { "keywords": {
"en": [ "en": [
{ {
"id":1,
"title": "Overworked", "title": "Overworked",
"content": "How much of your schedule is actually for yourself?" "content": "How much of your schedule is actually for yourself?"
}, },
{ {
"id":2,
"title": "Internal Burnout", "title": "Internal Burnout",
"content": "Do you spend a lot of energy just managing your own emotions?" "content": "Do you spend a lot of energy just managing your own emotions?"
}, },
{ {
"id":3,
"title": "Student Loans", "title": "Student Loans",
"content": "How many years will it take to pay off that diploma?" "content": "How many years will it take to pay off that diploma?"
}, },
{ {
"id":4,
"title": "Renting", "title": "Renting",
"content": "What slice of your paycheck goes straight to the landlord?" "content": "What slice of your paycheck goes straight to the landlord?"
}, },
{ {
"title": "Debt", "id":5,
"content": "Do you feel like you owe anyone \"time\" or \"favors\"?"
},
{
"title": "Adulthood", "title": "Adulthood",
"content": "What’s the gap between your legal age and how old you actually feel?" "content": "What’s the gap between your legal age and how old you actually feel?"
}, },
{ {
"title": "Survival", "id":6,
"content": "Are you living right now, or just surviving?"
},
{
"title": "Discipline", "title": "Discipline",
"content": "Which social habits were you born with, and which did you learn to fit in?" "content": "Which social habits were you born with, and which did you learn to fit in?"
}, },
{ {
"id":7,
"title": "PUA", "title": "PUA",
"content": "Is the self-doubt coming from the task, or someone else’s judgment?" "content": "Is the self-doubt coming from the task, or someone else’s judgment?"
}, },
{ {
"title": "Consumable", "id":8,
"content": "If you took tomorrow off, would the system really stop?"
},
{
"title": "Servility",
"content": "What’s your gut reaction to an unreasonable order?"
},
{
"title": "Unwritten Rules", "title": "Unwritten Rules",
"content": "Which unspoken rules are you quietly following?" "content": "Which unspoken rules are you quietly following?"
}, },
{ {
"id":9,
"title": "Corporate Slave", "title": "Corporate Slave",
"content": "How do you tell the \"work you\" apart from the \"real you\"?" "content": "How do you tell the \"work you\" apart from the \"real you\"?"
}, },
{ {
"title": "Curfew", "id":10,
"content": "When is your most comfortable time to be home?"
},
{
"title": "Boundaries", "title": "Boundaries",
"content": "When do you say \"no\" just to protect yourself?" "content": "When do you say \"no\" just to protect yourself?"
}, },
{ {
"id":11,
"title": "Surveillance", "title": "Surveillance",
"content": "Would you act differently if you knew no one was watching?" "content": "Would you act differently if you knew no one was watching?"
}, },
{ {
"title": "Inside the Wall", "id":12,
"content": "Does your environment feel like a shield or a cage?"
},
{
"title": "Constriction",
"content": "What’s the biggest change you made just to adapt?"
},
{
"title": "Freedom", "title": "Freedom",
"content": "What does \"freedom\" actually look like to you?" "content": "What does \"freedom\" actually look like to you?"
}, },
{ {
"id":13,
"title": "Awakening", "title": "Awakening",
"content": "Do you accept your \"factory settings\"?" "content": "Do you accept your \"factory settings\"?"
}, },
{ {
"id":14,
"title": "Lying Flat", "title": "Lying Flat",
"content": "Are you resting to go further, or because the road has ended?" "content": "Are you resting to go further, or because the road has ended?"
}, },
{ {
"title": "Fighting Back", "id":15,
"content": "When was the last time you spoke up or said \"no\"?"
},
{
"title": "Subjectivity", "title": "Subjectivity",
"content": "Do you usually speak up, or just go with the flow?" "content": "Do you usually speak up, or just go with the flow?"
}, },
{ {
"title": "Undefined", "id":16,
"content": "Describe yourself in three words without using your job title."
},
{
"title": "Being Yourself", "title": "Being Yourself",
"content": "How much of your true self do you show in public?" "content": "How much of your true self do you show in public?"
}, },
{ {
"title": "Finding Gaps", "id":17,
"content": "How do you find a little breathing room in your busy life?"
},
{
"title": "Suffocating",
"content": "Which topics or places make you feel like you can't breathe?"
},
{
"title": "Who Gets It", "title": "Who Gets It",
"content": "Who in your life truly understands what you’re going through?" "content": "Who in your life truly understands what you’re going through?"
}, },
{ {
"id":18,
"title": "Anxiety", "title": "Anxiety",
"content": "Are you worried about the future, or stuck in the past?" "content": "Are you worried about the future, or stuck in the past?"
},
{
"title": "World-weary",
"content": "Is this feeling just pure fatigue from the way things are?"
},
{
"title": "Irony",
"content": "Have the rules you once hated become your survival instincts?"
},
{
"title": "Empathy",
"content": "Which words in this device said what you couldn't say out loud?"
},
{
"title": "Illusion",
"content": "Are your goals truly yours, or just what society wants for you?"
} }
], ],
"zh": [ "zh": [
{ {
"id":1,
"title": "窮忙", "title": "窮忙",
"content": "你今天的行程裡,有多少比例是為了自己?" "content": "你今天的行程裡,有多少比例是為了自己?"
}, },
{ {
"id":2,
"title": "內耗", "title": "內耗",
"content": "你會花很多力氣處理自己的情緒嗎?" "content": "你會花很多力氣處理自己的情緒嗎?"
}, },
{ {
"id":3,
"title": "學貸", "title": "學貸",
"content": "一張畢業證書要花多少年來分期付款?" "content": "一張畢業證書要花多少年來分期付款?"
}, },
{ {
"id":4,
"title": "租屋", "title": "租屋",
"content": "這個月薪水的幾分之幾交給房東了?" "content": "這個月薪水的幾分之幾交給房東了?"
}, },
{ {
"title": "負債", "id":5,
"content": "你覺得自己現在有欠下「時間」或「人情」嗎?"
},
{
"title": "成年", "title": "成年",
"content": "法律定義的成年與你心理感受的成年,中間的距離有多少?" "content": "法律定義的成年與你心理感受的成年,中間的距離有多少?"
}, },
{ {
"title": "求生存", "id":6,
"content": "你會說你現在在過生活還是求生存?"
},
{
"title": "規訓", "title": "規訓",
"content": "你所遵守的社交習慣,哪些是天生的、哪些是後來學會的?" "content": "你所遵守的社交習慣,哪些是天生的、哪些是後來學會的?"
}, },
{ {
"id":7,
"title": "PUA", "title": "PUA",
"content": "讓你自我懷疑的是事情本身,還是某人的評價?" "content": "讓你自我懷疑的是事情本身,還是某人的評價?"
}, },
{ {
"title": "耗材", "id":8,
"content": "如果你明天突然休息,系統真的會因此停擺嗎?"
},
{
"title": "奴性",
"content": "在面對不合理的指令時,你的第一反應通常是什麼?"
},
{
"title": "潛規則", "title": "潛規則",
"content": "有哪些規則是沒被寫出來,但你卻正在默默遵守的?" "content": "有哪些規則是沒被寫出來,但你卻正在默默遵守的?"
}, },
{ {
"id":9,
"title": "社畜", "title": "社畜",
"content": "你如何區分「工作時的你」與「下班後的你」?" "content": "你如何區分「工作時的你」與「下班後的你」?"
}, },
{ {
"title": "門禁", "id":10,
"content": "覺得最舒適的回家時間是什麼時候?"
},
{
"title": "邊界", "title": "邊界",
"content": "你什麼時候會說不,來保護自己?" "content": "你什麼時候會說不,來保護自己?"
}, },
{ {
"id":11,
"title": "監控", "title": "監控",
"content": "如果沒人看見,你的行為表現會和現在有很大的差異嗎?" "content": "如果沒人看見,你的行為表現會和現在有很大的差異嗎?"
}, },
{ {
"title": "牆內", "id":12,
"content": "你覺得現在的環境帶給你的是「保護感」還是「限制感」?"
},
{
"title": "限縮",
"content": "為了適應環境,你做出的最大調整是什麼?"
},
{
"title": "自由", "title": "自由",
"content": "對你來說,什麼樣的狀態才叫「自由」?" "content": "對你來說,什麼樣的狀態才叫「自由」?"
}, },
{ {
"id":13,
"title": "覺醒", "title": "覺醒",
"content": "你接受自己的出廠設定嗎?" "content": "你接受自己的出廠設定嗎?"
}, },
{ {
"id":14,
"title": "躺平", "title": "躺平",
"content": "休息是因為想走更長的路,還是因為路已經走不下去了?" "content": "休息是因為想走更長的路,還是因為路已經走不下去了?"
}, },
{ {
"title": "反擊", "id":15,
"content": "你曾為什麼事,大聲說出不滿或拒絕?" "title": "主體",
},
{
"title": "主體性",
"content": "在群體中,你通常是提出意見的人還是配合的人?" "content": "在群體中,你通常是提出意見的人還是配合的人?"
}, },
{ {
"title": "不定義", "id":16,
"content": "如果不使用職稱,你會用哪三個詞來描述自己?"
},
{
"title": "做自己", "title": "做自己",
"content": "在公共場所,你覺得自己有多少程度能呈現真實的樣貌?" "content": "在公共場所,你覺得自己有多少程度能呈現真實的樣貌?"
}, },
{ {
"title": "找縫隙", "id":17,
"content": "在繁忙的節奏中,你最常用什麼方式找回自己的空間?"
},
{
"title": "窒息",
"content": "在什麼樣的環境或話題中,你會感到最明顯的壓迫感?"
},
{
"title": "誰懂", "title": "誰懂",
"content": "你覺得目前身邊的人,誰真正理解你的處境?" "content": "你覺得目前身邊的人,誰真正理解你的處境?"
}, },
{ {
"id":18,
"title": "焦慮", "title": "焦慮",
"content": "你在擔心還沒發生的未來,還是後悔已經發生的過去?" "content": "你在擔心還沒發生的未來,還是後悔已經發生的過去?"
},
{
"title": "厭世",
"content": "厭世是對現狀的疲憊嗎?"
},
{
"title": "諷刺",
"content": "在荒謬的日常中,你如何用幽默來回應生活的無奈?"
},
{
"title": "共感",
"content": "裝置中哪些話是你說不出口,但有人替你說了?"
},
{
"title": "幻覺",
"content": "你正在追求的事,有多少是你的願望,有多少是社會的投射?"
} }
] ]
} }

@ -3,6 +3,8 @@ import './App.css'
import {Button, LangButton} from './comps/button' import {Button, LangButton} from './comps/button'
import { useText } from './utils/usetext.jsx' import { useText } from './utils/usetext.jsx'
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import Lottie from 'lottie-react';
import landing_animation from './assets/lottie/Grayscale_landing.json';
function App() { function App() {
@ -12,7 +14,10 @@ function App() {
return ( return (
<main> <main>
<LangButton lang={nextLang} onClick={toggleLang} /> <LangButton lang={nextLang} onClick={toggleLang} />
<img src="/main.png" alt="Main" className='w-full flex-1 object-contain'/> {/* <img src="/main.png" alt="Main" className='w-full flex-1 object-contain'/> */}
<div className='w-full flex-1 flex items-center justify-center'>
<Lottie animationData={landing_animation} loop={true}/>
</div>
<Button onClick={()=>{ <Button onClick={()=>{
navigate('/keywords'); navigate('/keywords');
}}>{getText('button_enter')}</Button> }}>{getText('button_enter')}</Button>

File diff suppressed because one or more lines are too long

@ -0,0 +1 @@
{"v":"5.12.1","fr":30,"ip":0,"op":61,"w":34,"h":34,"nm":"circle","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[100]},{"t":60,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17,17,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.5,"y":1},"o":{"x":0.08,"y":0},"t":0,"s":[{"i":[[-2.376,0],[0,-2.262],[2.376,0],[0,2.262]],"o":[[2.376,0],[0,2.262],[-2.376,0],[0,-2.262]],"v":[[0,-4.096],[4.303,0],[0,4.096],[-4.303,0]],"c":true}]},{"t":60,"s":[{"i":[[-6.962,0],[0,-6.627],[6.962,0],[0,6.627]],"o":[[6.962,0],[0,6.627],[-6.962,0],[0,-6.627]],"v":[[0,-12],[12.605,0],[0,12],[-12.605,0]],"c":true}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[17,17,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[31,31,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[34,34],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[1,1,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":0,"ct":1,"bm":0}],"markers":[],"props":{}}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -106,6 +106,8 @@ export default function Canvas({ lookat, ...props }) {
// draw random circles // draw random circles
const context=refContext.current; const context=refContext.current;
const canvas=refCanvas.current; const canvas=refCanvas.current;
if(!canvas || !context) return;
context.clearRect(0, 0, canvas.width, canvas.height); context.clearRect(0, 0, canvas.width, canvas.height);
// draw random circles // draw random circles

@ -3,13 +3,16 @@
body{ body{
font-family: "Space Mono", "Noto Sans TC", sans-serif; font-family: "Space Mono", "Noto Sans TC", sans-serif;
@apply bg-black text-white;
@apply flex justify-center items-center min-h-screen;
} }
.root{ #root{
@apply bg-black text-white min-h-screen flex justify-center items-center; @apply flex-1 overflow-hidden bg-black text-white flex justify-center items-center w-full max-w-[640px] ;
} }
main{ main{
@apply bg-black text-white flex justify-center items-center min-h-screen px-[1rem] py-[3.5rem] flex flex-col justify-end gap-[3rem]; @apply bg-black text-white flex justify-center items-center min-h-screen px-[1rem] py-[3.5rem] flex flex-col justify-end gap-[3rem];
@apply w-full;
} }
button{ button{

@ -4,7 +4,9 @@ import { useText } from "../utils/usetext.jsx";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import About from "./about.jsx"; import About from "./about.jsx";
import Canvas from "../comps/canvas.jsx"; import Canvas from "../comps/canvas.jsx";
import Lottie from "lottie-react";
import hint_animation from '../assets/lottie/hint.json';
import egg_bg from '../assets/lottie/egg_bg.json';
const State={ const State={
Intro: 'Intro', Intro: 'Intro',
@ -34,8 +36,9 @@ export default function Explore() {
if(state===State.Intro){ if(state===State.Intro){
return ( return (
<main className="!justify-center"> <main className="!justify-center">
<div className="text-[1.125rem]">{getText('title_explore')}</div> <div className="text-[1.125rem] text-center">{getText('title_explore')}</div>
<img src="hint.svg"/> {/* <img src="hint.svg"/> */}
<Lottie animationData={hint_animation} loop={true} className='w-full'/>
</main> </main>
); );
} }
@ -55,7 +58,9 @@ export default function Explore() {
</section> </section>
<div className="w-full relative aspect-[393/500]"> <div className="w-full relative aspect-[393/500]">
<img src="egg_bg.svg" alt="egg" className="w-full object-contain"/> {/* <img src="egg_bg.svg" alt="egg" className="w-full object-contain"/> */}
<Lottie animationData={egg_bg} loop={true} className='w-full'/>
<Canvas className="absolute inset-0 top-0 left-0 w-full h-full" <Canvas className="absolute inset-0 top-0 left-0 w-full h-full"
lookat={selectedKeyword.indexOf(lookat)}/> lookat={selectedKeyword.indexOf(lookat)}/>
</div> </div>

@ -29,23 +29,30 @@ export default function Keywords() {
return ( return (
<main className="!px-0 !justify-between"> <main className="!px-0 !justify-between">
<h1 className="text-[1.125rem] mt-[3.875rem]">{getText('title_keywords')}</h1> <h1 className="text-[1.125rem]">{getText('title_keywords')}</h1>
<section ref={refContainer} className="w-full h-[107vw] overflow-x-auto overflow-y-hidden relative"> <section className='w-full flex-1 flex items-center justify-center'>
<div ref={refContainer} className="w-full overflow-x-auto">
<div className='w-[264%] grid grid-cols-6 aspect-[1036/424] overflow-y-hidden'>
{keywords.map((keyword, index) => ( {keywords.map((keyword, index) => (
<div key={index} className="absolute w-[54vw] aspect-[212/180] bg-contain bg-no-repeat flex items-center justify-center" <div key={index} className="w-full h-full bg-no-repeat relative" >
<div className="absolute top-[-15%] w-[123%] h-[128%] bg-no-repeat bg-contain flex items-center justify-center"
style={{ style={{
top: `${Math.floor(index/colCount) * 32}vw`, left: `${15*Math.floor(index/colCount)}%`,
left: `${(index % colCount) * 40 + 5*Math.floor(index/colCount)}vw`,
backgroundImage: `url(/topic${selectedKeyword.includes(keyword) ? '_select' : ''}.svg)`, backgroundImage: `url(/topic${selectedKeyword.includes(keyword) ? '_select' : ''}.svg)`,
}} }}
onClick={()=>{ onClick={()=>{
console.log('clicked keyword', keyword.title); console.log('clicked keyword', keyword.title);
select(keyword); select(keyword);
}}> }}>
<span className="break-word max-w-[50%] text-center">{keyword.title}</span> <span className="break-word text-center w-[50%]">{keyword.title}</span>
</div>
</div> </div>
))} ))}
</div>
</div>
</section> </section>
<div className="w-full px-[1.5rem]"> <div className="w-full px-[1.5rem]">

Loading…
Cancel
Save